Front-End Performance Checklist 2021[1]
https://www.smashingmagazine....css前端性能优化(一):准备工做[2]html
Google在2015年推出了Brotli,这是一种全新的开源无损数据格式,并被全部现代浏览器支持。Brotli有11个预设的编码质量级别,更高的质量级别要求更多的CPU以换取更好的压缩比。较慢的压缩速度最终会致使更高的压缩率,但Brotli解压速度仍然很快。4级压缩的Brotli比Gzip更小,压缩速度也更快。浏览器只有在用户经过HTTPS访问网站时才会接受Brotli。它被普遍支持,许多cdn也支持它。你甚至能够在尚不支持BCD的CDN上启用Brotli(与Service Worker一块儿使用)。前端
问题在于,因为以高压缩级别使用Brotli压缩全部资产的成本很高,所以许多托管服务提供商不能仅仅由于其产生的巨额成本开销而在短期内使用它。实际上,在最高压缩级别下,Brotli是如此之慢,以致于服务器等待动态压缩资产时,服务器开始发送响应所花费的时间会抵消文件大小中的任何潜在收益。(可是,若是在构建期间有时间进行静态压缩,则最好使用更高的压缩设置。)git
Brotli文件格式包括一个内置的静态字典,除了包含多种语言的各类字符串外,它还支持对这些单词进行多种转换的选项,从而增长了其多功能性。在Felix Hanau研究中,他发现了一种方法可提升5-9级的压缩[3]---使用“比默认值更专业的字典子集”,加上Content-Type头告诉压缩器它是否应该对HTML、JavaScript或CSS使用子集。结果是“当使用有限的字典使用方法在高压缩级别压缩web内容时,对性能的影响能够忽略不计(与一般的增长12%相比,CPU只增长了1%到3%)。”github
经过Elena Kirilenko的研究[4],咱们可使用之前的压缩产物来实现快速高效的Brotli再压缩。根据Elena的说法,“一旦咱们拥有经过Brotli压缩的资产,而且咱们尝试动态压缩动态内容(其中的内容相似于咱们能够提早使用的内容),咱们就能够大大缩短压缩时间”。例如,提供JavaScript包子集(如部分代码已在客户端上缓存或经过WebBundles提供动态包)或者使用基于事前已知模板的动态HTML或动态子集的WOFF2字体。根据Elena的说法,删除10%的内容时,压缩率提升了5.3%,压缩速度提升了39%;删除50%的内容时,压缩率提升了3.2%,压缩率提升了26%。web
策略:使用最高压缩比配置的Brotli+Gzip 预压缩静态资源,并使用 Brotli 配置 4~6 级压缩比来快速压缩(动态)HTML。确保服务器正确处理 Brotli 或 gzip 的内容协商头。算法
设备像素越多,屏幕上显示内容的细节就越细。api
高分辨率屏幕:图像资产须要更多的细节。对于位图来讲,它的图像编码数据是基于每个像素的,所以,图像像素越多,文件越大。当咱们将物理屏幕的分辨率增长一倍时,像素的总数增长了四倍:水平像素的两倍,垂直像素的两倍。一个“2倍”的屏幕不只仅是双倍,而是四倍所需的像素数!promise
所以,尽量选择矢量图像,由于它们与分辨率无关,老是提供清晰的结果。若是须要位图,提供响应图像。浏览器
针对图片的无损压缩,从高到低:JPEG XL > AVIF >> WebP > JPEG
另外一种由谷歌和Cloudinary开发的自由开放格式。目前未标准化,暂没有浏览器支持。
二、AVIF
一种开放的,免版权法的格式,支持有损和无损压缩,动画,有损alpha通道,能够处理尖锐的线条和纯色(这是JPEG的一个问题),同时提供更好的结果。在相同的DSSIM(使用近似人类视觉的算法在两个或多个图像之间的类似性(差别))下,能够节省高达50%的文件大小。与WebP不一样,AVIF在很大程度上一直优于JPEG。
AVIF甚至比大型svg表现得更好,尽管它固然不该该被视为svg的替代品。它也是第一个支持HDR颜色支持的图像格式之一;提供更高的亮度,色位深度和色域。惟一的缺点是,目前AVIF不支持渐进图像解码,相似于Brotli,高压缩率编码目前至关慢,尽管解码是快速的。
苹果公司在Safari 14中添加了对WebP的支持,到今天为止,全部现代浏览器都支持WebP。WebP也不是没有缺点的,它不支持像JPEG那样的渐进式渲染,这就是为何用户使用好的 JPEG 可能会更快地看到实际图像,尽管 WebP 图像的网络加载速度可能会更快。使用 JPEG,咱们能够用一半甚至四分之一的时间就提供给“像样的”用户体验,并在稍后加载其他的数据,而不是像 WebP 那样只有半空的图像。是否使用WebP取决于你想要的是什么:使用 WebP,你将减小图像大小,而使用 JPEG,你将提升图像的可感知性。另外,WebP并不老是生成比JPEG更小的图像。
如何选择?咱们可使用渐进式加强的方式:
固然,若是是背景图片,咱们可使用image-set作相同的处理
除了图片格式的问题,针对不一样的网络状况,咱们也应该作相应的优化:为慢速网络和低内存设备提供轻体验,为快速网络和高内存设备提供全体验。
为此,咱们可使用Client Hints与服务器协商选择适当的资源填充在页面上。Client Hints是HTTP请求头字段,例如DPR, Viewport-Width, Width, Save-Data, Accept(指定图像格式首选项)等。
咱们还能够将其与Service Worker结合,Service Worker能够在请求中添加新的Client Hints Hearders values,重写URL并将图像请求指向CDN,根据连通性和用户偏好调整响应,等等。它不只适用于图像资产,并且适用于几乎全部其余请求。
● 针对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]
最可靠的方法是混合惰性加载,使用Native Lazy-loading和支持懒加载第三方库(检测任何经过用户交互触发的可见性变化(使用IntersectionObserver))
● 图像优化指南[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未出来以前,大多数浏览器都实现了一个超时时间,若是字体下载太慢,超过这段时间后将使用备用字体。这是一种有用的技术,但不幸的是,浏览器的实际实现是不一样的。
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选项可让浏览器自由决定是否使用自定义字体,而这个决定很大程度上取决于浏览器的链接速度。若是速度很慢,那你的自定义字体可能就不会被使用)。
在加载web字体时,浏览器默认渲染文字不可见,在现代浏览器中,FOIT最多持续3s,当人们说web字体阻塞了资源时,他们极可能是指FOIT。
在加载web字体后,默认使用系统字体做为渲染文字的备用方案,一般在FOIT超时(3s)后使用。IE与Edge浏览器并不会等待,会直接使用备用方案渲染文字。FOUT 比 FOIT更可取,但需注意尽可能减小其回流影响。
它是一种字体加载策略,首先渲染常规 web字体,当粗体与斜体正在加载时,使用字体合成来渲染粗体与斜体变体。
尤为是对于中文来讲,一个完整的中文字体包至少几M,但咱们的项目仅使用了其中一部分而已,不必全加载。咱们能够用字体代工厂将 Web 字体转换成较小的子集,或者若是您使用的是开源字体,则可使用Glyphhanger或Fontsquirrel对它们进行子集化。您甚至可使用 PeterMüller 的subfont来自动完成整个字体子集化的工做流程,subfont 是一个命令行工具,能够静态分析您的页面以生成最佳的 Web 字体子集,而后将其注入到您的页面中。
目前可使用的更好的选择是:预加载关键 FOFT[11]and “compromise”技术[12]。他们两个都分两阶段渲染来逐步交付 Web 字体-首先须要一个小的超级子集,以便使用 Web 字体快速准确地渲染页面,而后加载异步家族的其他部分。所不一样的是,只有在不支持字体加载事件的场景中,“compromise”技术才会异步加载 polyfill,所以默认状况下您无需加载 polyfill。
除了这两种方式,还有其余的,咱们统一对比一下:
使用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请求中生成这些。
结论:单凭这一点是不够的。
虽然这不是web字体加载策略,但不得不说它比错误的使用web字体好。
优势:
● 不肯定是否能够更简单:只使用font-family没有@font-face。 ● 接近即时渲染性能:不担忧FOUT或FOIT。
缺点:
● 可用性有限。不多有系统字体能够跨平台使用。检查fontfamily.io查看系统字体是否为你的需求提供了可接受的浏览器支持。
结论:好,可是也没什么值得兴奋的。
有2种典型的方式:内联进<link rel="stylesheet">中或放进<style>中。
优势:
● 看起来很好的渲染性能:没有FOUT或FOIT。这是一个很是好的点。 ● 灵活性:没有FOUT或FOIT,就不须要担忧重绘/回流。 ● 健壮性:内联将全部鸡蛋放入初始服务器请求篮子中。
缺点:
● 渲染性能问题:虽然它没有FOUT,但它显然延迟了初始渲染时间。另外,单一的一个WOFF2文件可能只有10-15KB左右,内联它可能会让你超过HTTP/1的建议14KB或更少。 ● 浏览器支持:不利用@font-face块中逗号分隔的格式列表,这种方法只嵌入了一种格式类型。一般状况下,这意味着WOFF,所以使用这种方法迫使您在广泛性(WOFF)和更窄的用户代理支持、更小的文件大小(WOFF2)之间进行选择。 ● 糟糕的可伸缩性:请求不会并行发生,连续加载。 ● 自托管:固然是必需的。
结论:只有当你真的不喜欢FOUT时才使用这种方法——不推荐。
使用像loadCSS的工具将全部的字体转化为Data URI。
优势:
● 渲染性能:基本消除了FOIT。 ● 灵活性:易于将请求分组到单个重绘(将多个Data uri放在一个样式表中)。 ● 轻松:不须要任何额外的CSS更改使用。这是一个很大的好处,但不是万能的。 ● 健壮:若是异步请求失败,将继续显示回退文本。
缺点:
● 渲染性能:在解析样式表和Data uri时,具备很是明显但很短的FOIT。 ● 灵活性和可伸缩性:分组请求和重绘是耦合在一块儿的。若是将多个Data uri组合在一块儿(这将致使串行加载而不是并行加载),它们将一块儿从新绘制。使用此方法,不能并行加载并重绘。 ● 维护不友好:要求你有本身的方法来肯定字体格式支持,在获取Data URI样式表以前,你的JavaScript加载器须要肯定支持哪一种字体格式(WOFF2或WOFF)。这意味着若是出现了一种新的字体格式,你须要为它开发一个功能测试。 ● 浏览器支持:你能够绕过对加载器步骤的维护和对WOFF2或WOFF的硬代码,但这将致使没必要要的请求或潜在的丢弃请求(这与咱们讨论内联数据uri的缺点相同)。 ● 自我托管:必需的。
结论:还好,但咱们能够作得更好。
使用带有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字体阻塞——浏览器只下载其中的一小部分。使用这种方法,您必须告诉浏览器下载哪些字体,而不依赖于使用。
结论:这是基线标准。适用于大多数用例。
该方法是基于上一种方法作了些许改变,当你加载同一个字体的多维度或多样式的时候这很是有用,好比:常规、加粗、倾斜、加粗+倾斜等等。该方法主要是将这些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相比。
这与标准的FOFT的区别就是它不像标准FOFT那样在第一阶段加载所有的常规字体,它仅加载其子集(一般只包含A-Z和可选的0-9和/或标点)。完整的常规web字体会在第二阶段与其余权重和样式一块儿加载。
// demo: https://www.zachleat.com/web-fonts/demos/critical-foft-polyfill.html
优势:
● 有FOFT的全部优势。 ● 渲染性能:第一阶段的加载速度更快(在较慢的链接上更明显),进一步减小了第一阶段网页字体重绘的时间,使你最经常使用的网页字体回流发生得更快而不是更晚。
缺点:
● 有FOFT的全部缺点。 ● 第一阶段加载的常规字体子集与第二阶段加载整个常规字体重复加载了,引入了少许的开销,这是咱们为减小回流而付出的代价。 ● 许可限制:须要子集。
结论:使用下面的一个改进的关键FOFT变体。
第一阶段加载子集的方式改成转成data url 的形式进行加载。虽然这会阻塞初始渲染时间,可是咱们仅植入了很小的子集,与消除了大部分的FOUT相比这个代价很小。
// demo:https://www.zachleat.com/web-fonts/demos/critical-foft-preload-polyfill.html
优势:
● 有关键FOFT的全部优势。 ● 为常规字体消除FOIT和大大减小FOUT。当加载其余权重和样式时,第二阶段加载的其余字符会出现一个小回流,但影响要小得多。
缺点:
● 有关键FOFT的全部缺点。 ● 小的内联Data URI将略微阻塞初始渲染时间,咱们用这个来换取高度减小的FOUT。 ● 自我托管:必需的。
结论:在浏览器还不彻底支持preload时,这是黄金标准。
第一阶段的常规字体子集使用Preload的方式进行加载。
优势:
● 有关键FOFT的全部优势。 ● 渲染性能:与以前的方式相比下载的优先级更高,它比上一种方式以Data URI的方式内嵌更好,由于它能够利用请求缓存,而不是每次请求都要去获取相同的web字体数据。
缺点:
● 有关键FOFT的全部缺点。 ● 只使用单一的web字体格式。 ● preload会略微延迟初始渲染时间。 ● 自托管:可能须要。
结论:目前的黄金标准。
@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()。
自从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/...