关于前端:前端性能优化二资源优化

1次阅读

共计 15548 个字符,预计需要花费 39 分钟才能阅读完成。

​Front-End Performance Checklist 2021[1]
https://www.smashingmagazine….

前端性能优化(一):筹备工作[2]

一、传输优化

Google 在 2015 年推出了 Brotli,这是一种全新的开源无损数据格式,并被所有古代浏览器反对。Brotli 有 11 个预设的编码品质级别,更高的品质级别要求更多的 CPU 以换取更好的压缩比。较慢的压缩速度最终会导致更高的压缩率,但 Brotli 解压速度依然很快。4 级压缩的 Brotli 比 Gzip 更小,压缩速度也更快。浏览器只有在用户通过 HTTPS 拜访网站时才会承受 Brotli。它被广泛支持,许多 cdn 也反对它。你甚至能够在尚不反对 BCD 的 CDN 上启用 Brotli(与 Service Worker 一起应用)。

问题在于,因为以高压缩级别应用 Brotli 压缩所有资产的老本很高,因而许多托管服务提供商不能仅仅因为其产生的巨额老本开销而在短时间内应用它。实际上,在最高压缩级别下,Brotli 是如此之慢,以至于服务器期待动静压缩资产时,服务器开始发送响应所破费的工夫会对消文件大小中的任何潜在收益。(然而,如果在构建期间有工夫进行动态压缩,则最好应用更高的压缩设置。)

Brotli 文件格式包含一个内置的动态字典,除了蕴含多种语言的各种字符串外,它还反对对这些单词进行多种转换的选项,从而减少了其多功能性。在 Felix Hanau 钻研中,他发现了一种办法可 进步 5 - 9 级的压缩[3]— 应用“比默认值更业余的字典子集”,加上 Content-Type 头通知压缩器它是否应该对 HTML、JavaScript 或 CSS 应用子集。后果是“当应用无限的字典应用办法在高压缩级别压缩 web 内容时,对性能的影响能够忽略不计(与通常的减少 12% 相比,CPU 只减少了 1% 到 3%)。”

通过Elena Kirilenko 的钻研[4],咱们能够应用以前的压缩产物来实现疾速高效的 Brotli 再压缩。依据 Elena 的说法,“一旦咱们领有通过 Brotli 压缩的资产,并且咱们尝试动静压缩动静内容(其中的内容相似于咱们能够提前应用的内容),咱们就能够大大缩短压缩工夫”。例如,提供 JavaScript 包子集(如局部代码已在客户端上缓存或通过 WebBundles 提供动静包)或者应用基于事先已知模板的动静 HTML 或动静子集的 WOFF2 字体。依据 Elena 的说法,删除 10%的内容时,压缩率进步了 5.3%,压缩速度进步了 39%;删除 50%的内容时,压缩率进步了 3.2%,压缩率进步了 26%。

策略:应用最高压缩比配置的 Brotli+Gzip 预压缩动态资源,并应用 Brotli 配置 4~6 级压缩比来疾速压缩(动静)HTML。确保服务器正确处理 Brotli 或 gzip 的内容协商头。

二、图片优化

(一)CSS 像素与物理像素

设施像素越多,屏幕上显示内容的细节就越细。

高分辨率屏幕:图像资产须要更多的细节。对于位图来说,它的图像编码数据是基于每一个像素的,因而,图像像素越多,文件越大。当咱们将物理屏幕的分辨率增加一倍时,像素的总数减少了四倍: 程度像素的两倍,垂直像素的两倍。一个“2 倍”的屏幕不仅仅是双倍,而是四倍所需的像素数!

因而,尽可能抉择矢量图像,因为它们与分辨率无关,总是提供清晰的后果。如果须要位图,提供响应图像。

(二)图片格式

针对图片的无损压缩,从高到低:JPEG XL > AVIF >> WebP > JPEG

1、JPEG XL

另一种由谷歌和 Cloudinary 开发的自在凋谢格局。目前未标准化,暂没有浏览器反对。

2、AVIF

一种凋谢的,免版权法的格局,反对有损和无损压缩,动画,有损 alpha 通道,能够解决尖利的线条和纯色 (这是 JPEG 的一个问题),同时提供更好的后果。在雷同的 DSSIM(应用近似人类视觉的算法在两个或多个图像之间的相似性(差别)) 下,能够节俭高达 50% 的文件大小。与 WebP 不同,AVIF 在很大水平上始终优于 JPEG。

AVIF 甚至比大型 svg 体现得更好,只管它当然不应该被视为 svg 的替代品。它也是第一个反对 HDR 色彩反对的图像格式之一;提供更高的亮度,色位深度和色域。惟一的毛病是,目前 AVIF 不反对渐进图像解码,相似于 Brotli,高压缩率编码目前相当慢,只管解码是疾速的。

3、WebP

苹果公司在 Safari 14 中增加了对 WebP 的反对,到明天为止,所有古代浏览器都反对 WebP。WebP 也不是没有毛病的,它不反对像 JPEG 那样的渐进式渲染,这就是为什么用户应用好的 JPEG 可能会更快地看到理论图像,只管 WebP 图像的网络加载速度可能会更快。应用 JPEG,咱们能够用一半甚至四分之一的工夫就提供给“像样的”用户体验,并在稍后加载其余的数据,而不是像 WebP 那样只有半空的图像。是否应用 WebP 取决于你想要的是什么:应用 WebP,你将缩小图像大小,而应用 JPEG,你将进步图像的可感知性。另外,WebP 并不总是生成比 JPEG 更小的图像。

如何抉择?咱们能够应用渐进式加强的形式:

当然,如果是背景图片,咱们能够应用 image-set 做雷同的解决

(三)自适应媒体加载与 Client Hints

除了图片格式的问题,针对不同的网络状况,咱们也应该做相应的优化:为慢速网络和低内存设施提供轻体验,为疾速网络和高内存设施提供全体验。

为此,咱们能够应用 Client Hints 与服务器协商抉择适当的资源填充在页面上。Client Hints 是 HTTP 申请头字段,例如 DPR, Viewport-Width, Width, Save-Data, Accept(指定图像格式首选项)等。

咱们还能够将其与 Service Worker 联合,Service Worker 能够在申请中增加新的 Client Hints Hearders values,重写 URL 并将图像申请指向 CDN,依据连通性和用户偏好调整响应,等等。它不仅实用于图像资产,而且实用于简直所有其余申请。

(四)其余优化

1、应用压缩工具适当压缩图片

● 针对 JPEG

mozJPEG:可通过管制扫描级别来缩短开始渲染工夫
Guetzli:谷歌的开源编码器,专一于感知性能,并利用 Zopfli 和 WebP 的学习成绩,惟一的毛病是:解决工夫慢(每百万像素一分钟的 CPU)

● 针对 PNG

能够应用 Pingo

● 针对 SVG

能够应用 SVGO、SVGOMG,如果你须要从网站疾速预览和复制或下载所有 SVG 资产,能够应用 svg-grabber

始终值得一提的是放弃矢量资产整洁。确保清理未应用的资产,删除不必要的元数据,并缩小图稿中门路点的数量(从而缩小 SVG 代码)。

● 其余工具

Squoosh:以最佳压缩级别(有损或无损)压缩,调整大小和解决图像

应用响应式图像断点生成器或 Cloudinary 或 Imgix 等服务来主动执行图像优化。同样,在许多状况下,仅应用 srcset 和 size 将会取得显着的益处。

要查看响应式标记的效率,能够应用 Imaging-heap,这是一种命令行工具,能够测量视口大小和设施像素比率之间的效率。

能够将主动图像压缩增加到你的 GitHub 工作流程中,因而任何图像都不会影响未压缩的生产。可对 PNG 和 JPG 一起应用 mozjpeg 和 libvips。

Lepton 是一种工具和文件格式,可均匀无损压缩 JPEG 22%。

如果你想尽早显示占位符图像,可应用 BlurHash。BlurHash 将图像转换代表该图像占位符的短字符串(仅 20-30 个字符!)。该字符串足够短,能够轻松地将其增加为 JSON 对象中的字段。当然,简略点,你也能够应用纯色、渐变色或小图;如果想要占位图更靠近于原图,除了 BlurHash,你也能够应用 SVG。前面咱们会介绍,想先理解的能够看一下:

LQIP(Low Quality Image Placeholders)[7]
SQIP(a pluggable image converter with vector support)[8]
svg-placeholders[9]
Gradient Image Placeholders[10]

2、懒加载非关键图片,并在要害图像渲染实现后再加载任何异步脚本

最牢靠的办法是混合惰性加载,应用 Native Lazy-loading 和反对懒加载第三方库(检测任何通过用户交互触发的可见性变动(应用 IntersectionObserver))

3、思考 preload 要害图片

4、思考依据媒体查问加载不同大小的图片

5、确保图片总是设置 width 与 height 或在 css 中设置 aspect-ratio 属性,防止页面加载期间产生布局跳跃

6、应用 CDN,通过网络更快地发送图像

更多更具体的图像优化指南,可参考:

● 图像优化指南[5]

● Maximally optimizing image loading for the web in 2021[6]

三、视频优化

是时候该摈弃 GIF 了,具备低廉动画成果的 GIF 加载会影响渲染性能和带宽,不如改用动画 WebP(将 GIF 用作兜底),或将其全副替换为循环的 HTML5 视频;与图像不同,浏览器不会预加载 <video> 内容,但 HTML5 视频往往比 GIF 更轻,更小。

如果没有抉择的状况下,也能够应用有损 GIF,gifsicle 或 giflossy 对 gif 进行有损压缩以减小图像大小。

Colin Bendell 的测试显示,在 Safari 技术预览中,img 标签内的内联视频比 GIF 标签至多快 20 倍,解码速度快 7 倍,而且文件大小也只有一小部分。然而,其余浏览器不反对它。

有很多形式能够将 GIF 转化为 MP4,比方:应用FFmpeg[11],你能够在管制执行上面命令即可:

ffmpeg -i my-animation.gif -b:v 0 -crf 25 -f mp4 -vcodec libx264 -pix_fmt yuv420p my-animation.mp4

WebM 是一种绝对较新的文件格式,最后公布于 2010 年。它比 MP4 格局的视频要小很多,然而浏览器反对不是很好,并不是所有的浏览器都反对。咱们也能够应用 FFmpeg 将 GIF 转为 WebM 格局:

ffmpeg -i my-animation.gif -c vp9 -b:v 0 -crf 41 my-animation.webm

咱们在应用过程中,能够同时提供 WebM 和 MP4,这样如果浏览器不反对 WebM,它能够退回到 MP4。

<!-- By Houssein Djirdeh. https://web.dev/replace-gifs-with-videos/ -->
<!-- A common scenartio: MP4 with a WEBM fallback. -->
<video autoplay loop muted playsinline>
  <source src="my-animation.webm" type="video/webm">
  <source src="my-animation.mp4" type="video/mp4">
</video>

2018 年,开源媒体联盟公布了一种新的有前途的视频格式,称为 AV1。AV1 的压缩与 H.265 编解码器(H.264 的演进)类似,但与后者不同,AV1 是收费的。H.265 许可证的价格迫使浏览器供应商改为使用性能雷同的 AV1:(就像 H.265 一样)AV1 压缩的成果是 WebM 的两倍。

事实上,苹果目前应用 HEIF 格局和 HEVC (H.265),最新 iOS 上的所有照片和视频都以这些格局保留,而不是 JPEG 格局。尽管 HEIF 和 HEVC (H.265)还没有适当地裸露在 web,AV1 是 - 它正在取得浏览器反对。因而,能够在 <video> 的 source 中增加 AV1 格局的视频。

如果视频文件太大,但又想要疾速渲染图片,比方在你的启动页面又一个比拟大的背景视频,一种罕用的技术是首先以静止图像的模式显示第一帧,或者显示一个通过大量优化的、能够被解释为视频一部分的短循环片段,而后,当视频缓冲足够时,就开始播放理论的视频。

如果你想提供响应式的海报图片,你也能够借助第三方库 responsive-video-poster 去实现它。

钻研表明视频流的品质会影响观看者的行为。事实上,如果启动提早超过 2 秒,观众就会开始放弃视频。超过这一点,1 秒的提早将导致约 5.8% 的放弃率减少。

通常小屏幕设施无奈解决咱们提供的在电脑上播放的 720p 和 1080p。依据 Doug Sillars 的说法,咱们能够创立更小的视频版本,并应用 Javascript 为更小的屏幕检测源代码,以确保在这些设施上疾速流畅地播放。或者,咱们能够应用流媒体视频。HLS 视频流将向设施发送适当大小的视频 - 形象出为不同屏幕创立不同视频的需要。它还将协商网络速度,并适应视频比特率的速度,您正在应用的网络。

为了防止带宽上的节约,咱们只能为真正可能播放视频的设施增加视频源。或者,咱们能够从视频标签中删除 autoplay 属性,并应用 JavaScript 为更大的屏幕插入自动播放。此外,咱们须要在视频中增加 preload=”none” 来通知浏览器不要下载任何视频文件,直到它真正须要该文件:

<!-- Based on Doug Sillars's post. https://dougsillars.com/2020/01/06/hiding-videos-on-the-mbile-web/ -->
<video id="hero-video"
          preload="none"
          playsinline
          muted
          loop
          width="1920"
          height="1080"
          poster="poster.jpg">
<source src="video.webm" type="video/webm">
<source src="video.mp4" type="video/mp4">
</video>

而后咱们能够针对实际反对 AV1 的浏览器:

<source src="video.av1.mp4" type="video/mp4; codecs=av01.0.05M.08">
<source src="video.hevc.mp4" type="video/mp4; codecs=hevc">
<source src="video.webm" type="video/webm">
<source src="video.mp4" type="video/mp4">

而后咱们能够在特定的阈值 (例如 1000px) 上从新增加自动播放:

/* By Doug Sillars. https://dougsillars.com/2020/01/06/hiding-videos-on-the-mbile-web/ */
<script>
    window.onload = addAutoplay();
    var videoLocation  = document.getElementById("hero-video");
    function addAutoplay() {if(window.innerWidth > 1000){videoLocation.setAttribute("autoplay","");
      };
    }
</script>

四、字体优化

(一)字体格局

WOFF2 的浏览器反对十分好,能够将 WOFF 作为不反对 WOFF2 的浏览器的兜底字体 – 也能够用零碎字体兜底。

(二)基本概念

在理解如果优化字体之前,有几个根本的概念你须要把握:

【font-display】

在 font-display 未进去之前,大多数浏览器都实现了一个超时工夫,如果字体下载太慢,超过这段时间后将应用备用字体。这是一种有用的技术,但可怜的是,浏览器的理论实现是不同的。

Browser Timeout Fallback Swap
Chrome 35+ 3 seconds Yes Yes
Opera 3 seconds Yes Yes
Firefox 3 seconds Yes Yes
Internet Explorer 0 seconds Yes Yes
Safari No timeout N/A N/A

font-display,它是一个 css 属性,它决定了一个 @font-face 在不同的下载工夫和可用工夫下是如何展现的。

字体显示时间轴:字体显示工夫线基于一个计时器,该计时器在用户代理尝试应用给定下载字体的那一刻开始。工夫线分为三个时间段,在这三个时间段中指定应用字体的元素的渲染行为。

● 字体阻塞周期:如果未加载字体,任何试图应用它的元素都必须渲染不可见的后备字体。如果在此期间字体已胜利加载,则失常应用它。● 字体替换周期:在阻塞周期后立刻产生,如果未加载字体,任何尝试应用它的元素都必须渲染后备字体。如果在此期间字体已胜利加载,则失常应用它。● 字体失败周期:在替换周期后立刻产生,如果在此周期开始时字体还未加载,则标记为加载失败,应用失常的后备字体。否则,字体就会失常应用。

font-display 有几个取值:

● auto:默认,字体显示策略由用户代理定义(绝大多数浏览器默认应用相似 block 的形式)● block:为字体提供一个短暂的阻塞周期(绝大多少状况举荐为 3s)和有限的替换周期。换句话说就是,如果字体没有加载,浏览器首先会绘制“不可见”的文本,但一旦加载,就会替换字体面。● swap:为字体提供一个十分小的阻塞周期(通常为 0s)和有限的替换周期。(后备文本立刻显示直到自定义字体加载实现后再应用自定义字体渲染文本)。通常用于比拟重要的文案,比方 Logo 文案。● fallback:为字体提供一个十分小的阻塞周期和短暂的替换周期(这个能够说是 auto 和 swap 的一种折中形式。须要应用自定义字体渲染的文本会在较短的工夫(100ms 或更少 according to Google)不可见,如果自定义字体还没有加载完结,那么就先加载无款式的文本。一旦自定义字体加载完结,那么文本就会被正确赋予款式)。通常用于注释。● optional:为字体提供一个十分小的阻塞周期(通常 100ms 或更少),并且没有替换周期(成果和 fallback 简直一样,都是先在极短的工夫内文本不可见,而后再加载无款式的文本。不过 optional 选项能够让浏览器自在决定是否应用自定义字体,而这个决定很大水平上取决于浏览器的连贯速度。如果速度很慢,那你的自定义字体可能就不会被应用)。

【Flash of Invisible Text(FOIT)】

在加载 web 字体时,浏览器默认渲染文字不可见,在古代浏览器中,FOIT 最多继续 3s,当人们说 web 字体阻塞了资源时,他们很可能是指 FOIT。

【Flash of Unstyled Text(FOUT)】

在加载 web 字体后,默认应用零碎字体作为渲染文字的备用计划,通常在 FOIT 超时 (3s) 后应用。IE 与 Edge 浏览器并不会期待,会间接应用备用计划渲染文字。FOUT 比 FOIT 更可取,但需注意尽量减少其回流影响。

【Flash of Faux Text(FOFT)】

它是一种字体加载策略,首先渲染惯例 web 字体,当粗体与斜体正在加载时,应用字体合成来渲染粗体与斜体变体。

(三)字体子集化

尤其是对于中文来说,一个残缺的中文字体包至多几 M,但咱们的我的项目仅应用了其中一部分而已,没必要全加载。咱们能够用字体代工厂将 Web 字体转换成较小的子集,或者如果您应用的是开源字体,则能够应用 Glyphhanger 或 Fontsquirrel 对它们进行子集化。您甚至能够应用 PeterMüller 的 subfont 来主动实现整个字体子集化的工作流程,subfont 是一个命令行工具,能够动态剖析您的页面以生成最佳的 Web 字体子集,而后将其注入到您的页面中。

(四)字体加载计划

目前能够应用的更好的抉择是:预加载要害 FOFT[11]and “compromise”技术[12]。他们两个都分两阶段渲染来逐渐交付 Web 字体 - 首先须要一个小的超级子集,以便应用 Web 字体疾速精确地渲染页面,而后加载异步家族的其余部分。所不同的是,只有在不反对字体加载事件的场景中,“compromise”技术才会异步加载 polyfill,因而默认状况下您无需加载 polyfill。

除了这两种形式,还有其余的,咱们对立比照一下:

1、preload

应用 preload 尽可能早的获取字体资源,但 predload 字体须要放在要害 CSS 和 JavaScript 的链接之后。

<link rel="preload" href="font.woff2" as="font" type="font/woff2" crossorigin>

留神:它的优缺点很大程序上取决与你如何联合 @font-face 和 font-display 应用。

长处:

● 非常容易实现,一个 <link> 就能够了。● 比 @font-face 块有更好的渲染性能。在加载流中,Web 字体被要求更高的优先级。● 应用 type 属性指定字体格局,对将来敌对。在这一点上,依然有可能(尽管看起来不太可能)web 浏览器将在 WOFF2 之前实现预加载,如果没有这个属性,您可能会看到一个节约的申请。所以,确保蕴含 type。● 不要蕴含批改过的字体(应用子集或其余形式)。

毛病:

● 可伸缩性:预加载的越多,就越阻塞初始渲染。尽量只应用最重要的一到两种字体。● 灵活性:没有方法分组重绘 / 回流。● 在第三方服务器上可能没法应用。在你申请 web 字体之前就须要晓得标记渲染的 URL。例如,Google Fonts,在你向他们的 CDN 收回的 CSS 申请中生成这些。

论断:单凭这一点是不够的。

2、不应用 web 字体

尽管这不是 web 字体加载策略,但不得不说它比谬误的应用 web 字体好。

长处:

● 不确定是否能够更简略:只应用 font-family 没有 @font-face。● 靠近即时渲染性能:不放心 FOUT 或 FOIT。

毛病:

● 可用性无限。很少有零碎字体能够跨平台应用。查看 fontfamily.io 查看零碎字体是否为你的需要提供了可承受的浏览器反对。

论断:好,然而也没什么值得兴奋的。

3、内联 Data URI

有 2 种典型的形式:内联进 <link rel=”stylesheet”> 中或放进 <style> 中。

长处:

● 看起来很好的渲染性能:没有 FOUT 或 FOIT。这是一个十分好的点。● 灵活性:没有 FOUT 或 FOIT,就不须要放心重绘 / 回流。● 健壮性:内联将所有鸡蛋放入初始服务器申请篮子中。

毛病:

● 渲染性能问题:尽管它没有 FOUT,但它显然提早了初始渲染工夫。另外,繁多的一个 WOFF2 文件可能只有 10-15KB 左右,内联它可能会让你超过 HTTP/ 1 的倡议 14KB 或更少。● 浏览器反对:不利用 @font-face 块中逗号分隔的格局列表,这种办法只嵌入了一种格局类型。通常状况下,这意味着 WOFF,因而应用这种办法迫使您在普遍性 (WOFF) 和更窄的用户代理反对、更小的文件大小 (WOFF2) 之间进行抉择。● 蹩脚的可伸缩性:申请不会并行产生,间断加载。● 自托管:当然是必须的。

论断:只有当你真的不喜爱 FOUT 时才应用这种办法——不举荐。

4、异步 DATA URI 款式

应用像 loadCSS 的工具将所有的字体转化为 Data URI。

长处:

● 渲染性能:根本打消了 FOIT。● 灵活性:易于将申请分组到单个重绘(将多个 Data uri 放在一个样式表中)。● 轻松:不须要任何额定的 CSS 更改应用。这是一个很大的益处,但不是万能的。● 强壮:如果异步申请失败,将持续显示回退文本。

毛病:

● 渲染性能:在解析样式表和 Data uri 时,具备非常明显但很短的 FOIT。● 灵活性和可伸缩性:分组申请和重绘是耦合在一起的。如果将多个 Data uri 组合在一起(这将导致串行加载而不是并行加载),它们将一起从新绘制。应用此办法,不能并行加载并重绘。● 保护不敌对:要求你有本人的办法来确定字体格局反对,在获取 Data URI 样式表之前,你的 JavaScript 加载器须要确定反对哪种字体格局(WOFF2 或 WOFF)。这意味着如果呈现了一种新的字体格局,你须要为它开发一个功能测试。● 浏览器反对:你能够绕过对加载器步骤的保护和对 WOFF2 或 WOFF 的硬代码,但这将导致不必要的申请或潜在的抛弃申请(这与咱们探讨内联数据 uri 的毛病雷同)。● 自我托管:必须的。

论断:还好,但咱们能够做得更好。

5、FOUT+ 一个类名

应用带有 polyfill 的 css 字体加载 API 来检测特定的字体何时曾经加载,并且只有在它胜利加载后才利用该 web 字体在你的 CSS 中。通常这意味着在元素上切换一个类。应用 SASS 或 LESS mixins 更容易保护。

// demo:https://www.zachleat.com/web-fonts/demos/fout-with-class-polyfill.html
<style>
  @font-face {
    font-family: Lato;
    src: url('font-lato/lato-regular-webfont.woff2') format('woff2'),
         url('font-lato/lato-regular-webfont.woff') format('woff');
  }
  @font-face {
    font-family: LatoBold;
    src: url('font-lato/lato-bold-webfont.woff2') format('woff2'),
         url('font-lato/lato-bold-webfont.woff') format('woff');
    font-weight: 700;
  }
  body {font-family: sans-serif;}
  .fonts-loaded body {font-family: Lato, sans-serif;}
  .fonts-loaded h1,
  .fonts-loaded strong {
    font-family: LatoBold, sans-serif;
    font-weight: 700;
  }
</style>
<script>
  (function() {
    // Optimization for Repeat Views
    if(sessionStorage.fontsLoadedFoutWithClassPolyfill) {
      document.documentElement.className += "fonts-loaded";
      return;
    }
    /* Font Face Observer v2.0.13 - © Bram Stein. License: BSD-3-Clause */
    // 此处省略
    var fontA = new FontFaceObserver('Lato');
    var fontB = new FontFaceObserver('LatoBold', {weight: 700});
    Promise.all([fontA.load(null, 10000),
      fontB.load(null, 10000),
    ]).then(function () {
      document.documentElement.className += "fonts-loaded";
      // Optimization for Repeat Views
      sessionStorage.fontsLoadedFoutWithClassPolyfill = true;
    });
  })();
</script>

长处:

● 渲染性能:打消了 FOIT。这种办法通过了试验和测试,是 TypeKit 举荐的办法之一。● 灵活性:很容易将申请分组到一个从新绘制(应用一个类用于多个 web 字体加载)。● 可伸缩性:申请是并行产生的。● 强壮:如果申请失败,回退文本依然显示。● 托管:独立于字体加载器的工作(很容易通过第三方主机或现有的 @font-face 块实现)。● 弱小的浏览器反对,polyfill 通常能够在任何反对 web 字体的中央工作。● 将来敌对:polyfill 不耦合到字体格局,应该与现有的 @font-face 块工作。这意味着当新格局呈现时,你能够像平时一样扭转你的 @font-face。● 不须要批改字体(通过子设置或其余形式)。

毛病:

● 须要严格保护 / 管制 CSS。在 CSS 中繁多应用 web 字体 font-family 而不应用 Loaded 类可能会触发 FOIT。● 通常须要你硬编码哪些 web 字体你想在页面上加载。这可能意味着你最终会加载比页面须要的更多的 web 字体内容。记住,如果应用 @font-face,更新的浏览器只下载在你的页面上理论应用的 web 字体。这是收费给你的。这就是为什么《纽约时报》能够在其主页上避开 100 种不同的 @font-face 字体阻塞——浏览器只下载其中的一小部分。应用这种办法,您必须通知浏览器下载哪些字体,而不依赖于应用。

论断:这是基线规范。实用于大多数用例。

6、FOFT 或 FOUT+ 两段渲染

该办法是基于上一种办法做了些许扭转,当你加载同一个字体的多维度或多样式的时候这十分有用,比方:惯例、加粗、歪斜、加粗 + 歪斜等等。该办法次要是将这些 web 字体分为两个阶段加载,先加载惯例体,而后渲染假粗体和假斜体内容(应用字体合成),而真正的 web 字体的权重和代替款式正在加载。

// demo: https://www.zachleat.com/web-fonts/demos/foft.html
// 基于上一个形式,批改了局部内容,上面仅批改的局部
<style>
  body {font-family: sans-serif;}
  .fonts-loaded-1 body {font-family: LatoInitial;}
  .fonts-loaded-2 body {font-family: Lato;}
</style>
<script>
  (function() {if( "fonts" in document) {
      // Optimization for Repeat Views
      if(sessionStorage.fontsLoadedFoft) {
        document.documentElement.className += "fonts-loaded-2";
        return;
      }
​
      document.fonts.load("1em LatoInitial").then(function () {
        document.documentElement.className += "fonts-loaded-1";
​
        Promise.all([document.fonts.load("400 1em Lato"),
          document.fonts.load("700 1em Lato"),
          document.fonts.load("italic 1em Lato"),
          document.fonts.load("italic 700 1em Lato")
        ]).then(function () {
          document.documentElement.className += "fonts-loaded-2";
​
          // Optimization for Repeat Views
          sessionStorage.fontsLoadedFoft = true;
        });
      });
    }
  })();
  </script>

长处:

● 领有上一种形式的所有长处。● 渲染性能:极大地缩小了网页字体加载时产生的内容跳跃量。思考到咱们将网页字体加载分为两个阶段,这使得第一个阶段(惯例字体,这将导致最多的回流)比咱们将所有字体组合在一起进行一次重绘要快得多。

毛病:

● 领有上一种形式的所有毛病。● 有些设计师对字体合成十分敏感。主观地说,合成的变体不如真正的变体有用,但这不是一个偏心的比拟。请记住,合成版本只是一个长期占位符,咱们须要问的问题是: 它们比后退字体更有用还是更没用?更有用。

论断:适宜那些对额定性能感兴趣的,但不能与要害 FOFT 相比。

7、要害 FOFT

这与规范的 FOFT 的区别就是它不像规范 FOFT 那样在第一阶段加载全副的惯例字体,它仅加载其子集(通常只蕴含 A - Z 和可选的 0 - 9 和 / 或标点)。残缺的惯例 web 字体会在第二阶段与其余权重和款式一起加载。

// demo: https://www.zachleat.com/web-fonts/demos/critical-foft-polyfill.html

长处:

● 有 FOFT 的所有长处。● 渲染性能:第一阶段的加载速度更快(在较慢的连贯上更显著),进一步缩小了第一阶段网页字体重绘的工夫,使你最罕用的网页字体回流产生得更快而不是更晚。

毛病:

● 有 FOFT 的所有毛病。● 第一阶段加载的惯例字体子集与第二阶段加载整个惯例字体反复加载了,引入了大量的开销,这是咱们为缩小回流而付出的代价。● 许可限度:须要子集。

论断:应用上面的一个改良的要害 FOFT 变体。

8、要害 FOFT+DATA URI

第一阶段加载子集的形式改为转成 data url 的模式进行加载。尽管这会阻塞初始渲染工夫,然而咱们仅植入了很小的子集,与打消了大部分的 FOUT 相比这个代价很小。

// demo:https://www.zachleat.com/web-fonts/demos/critical-foft-preload-polyfill.html

长处:

● 有要害 FOFT 的所有长处。● 为惯例字体打消 FOIT 和大大减少 FOUT。当加载其余权重和款式时,第二阶段加载的其余字符会呈现一个小回流,但影响要小得多。

毛病:

● 有要害 FOFT 的所有毛病。● 小的内联 Data URI 将稍微阻塞初始渲染工夫,咱们用这个来换取高度缩小的 FOUT。● 自我托管:必须的。

论断:在浏览器还不齐全反对 preload 时,这是黄金规范。

9、要害 FOFT+Preload

第一阶段的惯例字体子集应用 Preload 的形式进行加载。

长处:

● 有要害 FOFT 的所有长处。● 渲染性能:与之前的形式相比下载的优先级更高,它比上一种形式以 Data URI 的形式内嵌更好,因为它能够利用申请缓存,而不是每次申请都要去获取雷同的 web 字体数据。

毛病:

● 有要害 FOFT 的所有毛病。● 只应用繁多的 web 字体格局。● preload 会稍微提早初始渲染工夫。● 自托管:可能须要。

论断:目前的黄金规范。

(五)其余优化

1、不要将 local 与 web 字体混合应用,如下:

@font-face {
  font-family: Open Sans;
  src: local('Open Sans Regular'),
       local('OpenSans-Regular'),
       url('opensans.woff2') format ('woff2'),
       url('opensans.woff') format('woff');
}

就算本地字体名称能够匹配 web 字体名字,但不能保障它两是同一个字体,事实上,大多数状况不是。因为手机上的字体可能只是字体的一个子集,用户能够批改字体如 line-height 等,体现会有所不同,有些字体可能还是以其余字体代替,还有可能字体因为版本的问题而不同,所以不举荐应用 local 字体。除了 Android 申请 Roboto,Google 字体对所有用户禁止应用 local()。

2、尽可能的自托管你的动态资源

自从 Chrome v86(公布于 2020 年 10 月),跨站点的资源,如字体不能共享在同一个 CDN - 因为分区浏览器缓存,这是 Safari 多年来的默认行为。没有了跨站点资源共享缓存的劣势。

当所有的申请都来自同一个域,并且连贯在同一个 HTTP/ 2 上时,它们能够互相调度。要害资源 (如 CSS 和字体) 能够在队列中向前推,并在低优先级资源 (如图像) 之前交付。

因为谷歌字体 (以及大多数第三方资源) 是从与主页资源不同的畛域提供的,因而不能对它们进行优先排序,并最终相互竞争下载带宽。这可能导致理论获取工夫比最佳状况下的 8 次往返要长得多。

如果做不到自托管,也能够应用代理的形式将其代理到你的域名下:将字体申请 url 的域名改为 html 的域名,利用 Service worker 拦挡,申请真正的链接。

(六)指标

要测量 Web 字体加载性能,请思考所有文本可见工夫(所有字体均已加载且所有内容均以 Web 字体显示的时刻)、变为 实在斜体的工夫 以及首次渲染后的Web 字体回流数

总的来说,(平安)的网络字体加载策略就是:将字体子集化并在第二阶段渲染做好筹备,应用 font-display 描述符申明它们,应用字体加载 API 对重绘进行分组,并将字体存储在长久的 service worker 缓存中。第一次拜访时,在阻塞的内部脚本之前插入脚本预加载字体。

欢送关注我的集体公众号:

参考资料

Front-End Performance Checklist 2021[1]:https://www.smashingmagazine….
前端性能优化(一):筹备工作 [2]:https://mp.weixin.qq.com/s/QD…
Brotli compression using a reduced dictionary[3]:https://blog.cloudflare.com/b…
Fast and efficient recompression using previous compression artifacts[4]:https://dev.to/riknelix/fast-…
图像优化指南[5]:https://images.guide/
Maximally optimizing image loading for the web in 2021[6]:https://www.industrialempathy…
LQIP(Low Quality Image Placeholders)[7]:https://www.guypo.com/introdu…
SQIP(a pluggable image converter with vector support)[8]:https://github.com/axe312ger/…
svg-placeholders[9]:https://jmperezperez.com/svg-…
Gradient Image Placeholders[10]:https://calendar.perfplanet.c…
exact instructions for FFmpeg[11]:https://medium.com/@borisscha…
Critical FOFT with preload[12]:https://www.zachleat.com/web/…
“The Compromise” method:https://www.zachleat.com/web/…

正文完
 0