(给前端食堂加星标,吃好每一顿饭)前端
衡量一个 Web
页面的体验和质量一直有很是多的工具和指标 ... 每次咱们去关注这些指标的时候都会很是痛苦,由于这些指标真的是又多又难理解,测量这些指标的工具也很是多。
git

当看到最近发布的 Chrome 83
中又增长了几个性能指标的时候我头都大了...github
然而不要着急,这些指标就是为了聚焦关注度和下降理解成本的,下面咱们就来具体看一下,新增长的 Core Web Vitals
究竟是什么东西?web
如何衡量用户体验质量?

优化用户体验的质量一直都是是每一个 Web
站点长期成功的关键,衡量用户体验的质量有不少方面。虽然用户体验的某些方面是须要基于特定于站点和上下文的,可是全部站点仍然有一组共同的指标——Core Web Vitals
,这些指标包括加载体验、交互性和页面内容的视觉稳定性,他们构成了 2020
年核心 Web
健康指标的基础。算法
多年来,Google 提供了不少工具:(Lighthouse, Chrome DevTools, PageSpeed Insights, Search Console's Speed Report
) 来衡量和报告性能。一些开发人员是使用这些工具的专家,而大部分其余人则发现大量的工具和衡量标准都很难学习和使用。npm
网站开发者不该该为了理解他们交付给用户的体验的质量指标而成为性能专家。Web Vitals
计划的目的就是简化场景,下降学习成本,并帮助站点关注最重要的指标,即 Core Web Vitals
。api
Core Web Vitals
Core Web Vitals
是应用于全部 Web
页面的 Web Vitals
的子集,全部的站点开发者都应该关注一下,他们将在全部谷歌提供的性能测试工具中进行显示。每一个 Core Web Vitals
表明用户体验的一个不一样方面,在该领域是可衡量的,并反映了以用户为中心的关键结果的真实体验。浏览器
网页核心的性能指标应该是随着时间的推移而不断演变的。当前 2020
年主要关注用户体验的三个方面——加载、交互性和视觉稳定性:缓存

-
Largest Contentful Paint (LCP)
: 衡量加载体验:为了提供良好的用户体验,LCP
应该在页面首次开始加载后的2.5
秒内发生。 -
First Input Delay (FID)
: 衡量可交互性,为了提供良好的用户体验,页面的FID
应当小于 100毫秒。 -
Cumulative Layout Shift (CLS)
:衡量视觉稳定性,为了提供良好的用户体验,页面的CLS应保持小于 0.1。
下面咱们来详细介绍这三种性能指标:服务器
LCP
加载体验的衡量
衡量 Web
页主要内容的加载速度是众多开发者一直在关注的一个点,并且可衡量的指标很是多。
好比最先的 load
、DOMContentLoaded
事件,用这两个事件来衡量页面加载速度是很是糟糕的,由于它们不必定与用户在屏幕上看到的内容相对应。
以用户为中心的更新性能指标(例如First Contentful Paint(FCP)
)它只能捕捉加载体验的最开始。若是页面最开始显示的是一个 loading
动画,那这个指标就很难关注了。
后来,业界开始建议使用好比 First Meaningful Paint (FMP)
和 Speed Index (SI)
(均可以在 Lighthouse
中获取)等性能指标来帮助捕获初次渲染后的更多加载体验,可是这些指标很是复杂,难以解释,并且误报率也比较高。
什么是 LCP

Largest Contentful Paint (LCP)
用于衡量标准报告视口内可见的最大内容元素的渲染时间。为了提供良好的用户体验,网站应努力在开始加载页面的前 2.5
秒内进行 最大内容渲染
。
相比 FCP
,这个指标就很是有价值了,由于这个值是根据页面加载渲染不断变化的,若是页面有一个 lodaing
动画,而后才渲染出具体内容,那么这个指标计算出来的就是具体内容的加载速度,而非 lodaing
动画的加载速度。
LCP 考虑哪些元素
LCP
目前并不会计算全部元素,由于这样会使这个指标变得很是复杂,它如今只关注下面的元素:
-
<img>
元素 -
<image>
元素内的<svg>
元素 -
<video>
元素 -
经过 url()
函数加载背景图片的元素 -
包含文本节点或其余内联文本元素子级的块级元素。
为了在开始时保持简单,将元素限制到这个有限的集合是有意的。随着研究的深刻,未来可能会添加更多的元素。
如何计算 LCP ?
页面上最大的元素即绘制面积最大的元素,所谓绘制面积能够理解为每一个元素在屏幕上的 “占地面积”,若是元素延伸到屏幕外,或者元素被裁切了一部分,被裁切的部分不算入在内,只有真正显示在屏幕里的才算数。
图片元素的面积计算方式稍微有点不一样,由于能够经过 CSS
将图片扩大或缩小显示,也就是说,图片有两个面积:“渲染面积”与“真实面积”。在 LCP
的计算中,图片的绘制面积将获取较小的数值。例如:当“渲染面积”小于“真实面积”时,“绘制面积”为“渲染面积”,反之亦然。
页面在加载过程当中,是线性的,元素是一个一个渲染到屏幕上的,而不是一瞬间全渲染到屏幕上,因此“渲染面积”最大的元素随时在发生变化。
若是元素被删除,LCP算法将再也不考虑该元素,若是被删除的元素恰好是 “绘制面积” 最大的元素,则使用新的 “绘制面积” 最大的元素建立一个新的性能条目。
该过程将持续到用户第一次滚动页面或第一次用户输入(鼠标点击,键盘按键等),也就是说,一旦用户与页面开始产生交互,则中止报告新的性能指标。

在以上两个时间轴中,最大的元素随内容加载而变化。在第一个示例中,新内容被添加到 DOM
中,而且更改了最大的元素。在第二个示例中,布局发生更改,之前最大的内容从视口中删除。一般状况下,延迟加载的内容要大于页面上已存在的内容。
改善 LCP
LCP较差的最多见缘由是:
-
服务器响应时间慢 -
阻断渲染的 Javascript
和CSS
-
资源加载时间慢 -
客户端渲染
因此咱们从上面的角度去考虑改善 LCP
:
优化服务器
这个很好理解,浏览器从服务器接收内容所需的时间越长,则在屏幕上呈现任何内容所花费的时间就越长。更快的服务器响应时间能够直接改善包括 LCP
在内的全部页面加载指标。

衡量服务器相应时间有一个专门的指标:首字节相应时间(TTFB
)是最初的网络请求被发起到从服务器接收到第一个字节这段时间,它包含了 TCP
链接时间,发送 HTTP
请求时间和得到响应消息第一个字节的时间。你能够尝试在下面几个方便优化 TTFB
:
-
缓存 HTML
离线页面,缓存页面资源,减小浏览器对资源的请求。 -
尽可能减少资源阻断渲染: CSS
和JavaScript
压缩、合并、级联、内联等等 -
对图片进行优化。转化图片的格式为 JPG
或者WEBP
等等的格式,下降图片的大小,以加快请求的速度。 -
对 HTML
重写、压缩空格、去除注释等。减小HTML
大小,加快速度。 -
使用 preconnect
尽快与服务器创建连接、使用dns-prefetch
尽快进行DNS
查找。 -
使用 CDN
加快请求速度
优化阻断渲染的资源
JavaScript
和 CSS
都是会阻断页面渲染的资源,须要尽量的对 CSS
和 JavaScript
文件进行压缩、延迟加载首屏无需使用的 JavaScript
、内联关键的 CSS
等来减少阻断时间。
优化资源加载时间
刚才咱们上面提到的这些资源,若是在首屏进行渲染,则加载这些元素所花费的时间将直接影响 LCP
。
-
<img>
元素 -
<image>
元素内的<svg>
元素 -
<video>
元素 -
经过 url()
函数加载背景图片的元素 -
包含文本节点或其余内联文本元素子级的块级元素。
你可使用下面的手段进行优化:
-
对图片进行优化。转化图片的格式为 JPG
或者WEBP
等等的格式,下降图片的大小。 -
对重要的资源进行预加载,好比为 style
标签添加rel="preload"
属性 -
使用 Gzip
和Brotli
压缩页面资源,下降传输时间 -
使用 service worker
缓存资源
服务端渲染
使用服务端渲染能够确保首先在服务器上呈现页面内容,能够有效改善 LCP
,可是相比客户端渲染的缺点是会加大页面从而影响 TTFB
、服务端渲染须要等待全部 js 执行完毕后才能相应用户输入,这会使交互体验变差。
FID
第一印象
咱们都知道留下一个好的第一印象是多么重要。在网络上,一个好的第一印象能够决定一我的是否是能够成为一个网站的忠实的用户,或者是离开之后不再会回来。问题是,什么能给人留下好印象,你如何衡量你可能给用户留下什么样的印象?
在网络上,第一印象能够有不少种不一样的形式——咱们对网站的设计和视觉吸引力有第一印象,对其速度和响应能力也有第一印象。
开发者们使用 First Contentful Paint(FCP)
能够衡量对网站加载速度对第一印象 。可是,网站能够在屏幕上绘制像素的速度只是一部分,一样重要的是用户尝试与这些像素进行交互时你的网站的响应速度!
什么是 FID

FID( First Input Delay)
即记录用户和页面进行首次交互操做所花费的时间 。FID
指标影响用户对页面交互性和响应性的第一印象。为了提供良好的用户体验,站点应努力使首次输入延迟小于 100
毫秒。
FID
发生在 FCP
和 TTI
之间,由于这个阶段虽然页面已经显示出部份内容,但尚不具有彻底的可交互性。这个阶段用户和页面交互,每每会有较大延迟。

如上图所示,浏览器接收到用户输入操做时,主线程正在忙于执行一个耗时比较长的任务,只有当这个任务执行完成后,浏览器才能响应用户的输入操做。它必须等待的时间就此页面上该用户的 FID
值。
例如,如下全部 HTML
元素都须要在响应用户交互以前等待主线程上正在进行的任务完成:
-
文本输入框,复选框和单选按钮( <input>,<textarea>
) -
选择下拉菜单( <select>
) -
连接( <a>
)
如何提升 FID
如下几个方面是提升 FID
的重要指标:
减小 JavaScript
执行时间
同上面改善 LCP
的方法:
-
缩小并压缩 JavaScript
文件 -
延迟加载首屏不须要的 JavaScript
-
尽可能减小未使用的 polyfill
分解耗时任务

上面提到一个较长的耗时任务是影响 FID
的重要指标,任何阻塞主线程 50
毫秒或更长时间的代码段均可以称为“长任务”,咱们能够将长的耗时任务拆分为较小的异步任务。
使用 Web Worker

主线程阻塞是输入延迟的主要缘由之一。Web Workers
可让你在与主执行线程分离的后台线程上运行 JavaScript
,这样作的好处是能够在一个单独的线程中执行费时的处理任务,从而容许主(一般是UI)线程运行而不被阻塞。将非 UI
操做移至单独的工做线程能够减小主线程的阻塞时间,从而改善 FID
。
CLS
视觉稳定性

您是否曾经在访问一个 Web
页面时发生下面的状况?在阅读文章的同时文字忽然移动了、你忽然找不到你阅读的位置了、点按钮的时候按钮被移动到了其余地方,致使你点了其余东西?
页面内容的意外移动一般是因为异步加载资源或将 DOM
元素动态添加到现有内容上方的页面而发生的。罪魁祸首多是尺寸未知的图像或视频,渲染后比其后备更大或更小的字体,或者是动态调整自身大小的第三方广告或小部件。
Cumulative Layout Shift (CLS)
可经过测量实际用户发生的频率来帮助您解决此问题。
什么是 CLS?

CLS
会测量在页面的整个生命周期中发生的每一个意外的样式移动的全部单独布局更改得分的总和。布局的移动可能发生在可见元素从一帧到下一帧改变位置的任什么时候候。为了提供良好的用户体验,网站应努力使 CLS
分数小于 0.1
。
如何计算 CLS?
布局偏移分值
为了计算布局的偏移值,浏览器会查看两个渲染帧之间的视口大小和视口中不稳定元素的移动。布局偏移分是该移动的两个指标的乘积:影响分数和距离分数。
layout shift score = impact fraction * distance fraction
影响分数
前一帧和当前帧的全部不稳定元素的可见区域的并集(占视口总面积的一部分)是当前帧的影响分数。

在上图中,有一个元素在一帧中占据了视口的一半。而后,在下一帧中,元素下移视口高度的25%
。红色的虚线矩形表示两个帧中元素的可见区域的并集,在这种状况下,其为总视口的75%
,所以其影响分数为 0.75
。
距离分数
布局偏移值方程的另外一部分测量不稳定元素相对于视口移动的距离。距离分数是任何不稳定元素在框架中移动的最大距离(水平或垂直)除以视口的最大尺寸(宽度或高度,以较大的为准)。

在上面的例子中,最大的视口尺寸是高度,而且不稳定元素移动了视口高度的25%
,这使得距离分数为0.25
。
所以,在此示例中,影响分数为0.75
,距离分数为0.25
,所以版式位移分数为0.75 * 0.25 = 0.1875
。
如何改善 CLS?
不要使用无尺寸元素
图像和视频等元素上始终须要包括 width
和 height
尺寸属性,现代浏览器会根据图像的 width
和 height
属性设置图像的默认长宽比,知道纵横比后,浏览器就能够为元素计算和保留足够的空间。
或者,使用 aspect-ratio
也能够提早指定宽高比:
img {
aspect-ratio: attr(width) / attr(height);
}
那响应式的图片呢?可使用 srcset
定义图像,使浏览器能够在图像之间进行选择,以及每一个图像的大小。
<img
width="1000"
height="1000"
src="puppy-1000.jpg"
srcset="puppy-1000.jpg 1000w,
puppy-2000.jpg 2000w,
puppy-3000.jpg 3000w"
alt="ConardLi"
/>
-
永远不要在现有内容之上插入内容,除非是响应用户交互。这确保了预期的布局变化。 -
宁肯转换动画,也不要转换触发布局变化的属性的动画。以一种提供从一个状态到另外一个状态的上下文和连续性的方式动画转换。
提早给广告位预留空间
不少页面广告都是动态插入的,因此必定要提早为广告位预留必定空间。
警戒字体变化
字体一般是大文件,须要一段时间才能加载,一些浏览器直到下载完字体后才呈现文本
font-display: swap
告诉浏览器默认使用系统字体进行渲染,当自定义字体下载完成以后再进行替换。
@font-face {
font-family: 'Pacifico';
font-style: normal;
font-weight: 400;
src: local('Pacifico Regular'), local('Pacifico-Regular'), url(https://fonts.gstatic.com/xxx.woff2) format('woff2');
font-display: swap;
}
另外,你可使用 <link rel="preload">
更早的加载字体文件。
获取 Core Web Vitals
Google 认为,Core Web Vitals
对于全部网络体验都相当重要。所以,它致力于在其工具中显示这些指标,下面是现有工具中指标的支持状况:

还没有支持这些指标的工具都将在最近获得支持。
web-vitals

如今你可使用标准的 Web API
在 JavaScript
中测量每一个指标。Google
提供了一个 npm
包:web-vitals
,这个库提供了很是简单的 API
,测量每一个指标就像调用一个普通函数同样简单:
npm install web-vitals
每一个测量函数都接收一个 report
回调函数做为参数,回调函数将在测量完成后触发,另外,对于像 LCP
和 CLS
这样的指标是不断变化的,因此它们的回调函数可能会屡次触发,若是你想获取在这期间获取每次变化的数值,你能够指定第二个参数 reportAllChanges
,不然回调函数只有在最终测量完成后触发一次。
import {getCLS, getFID, getLCP} from 'web-vitals';
getCLS(console.log, true);
getFID(console.log); // Does not take a `reportAllChanges` param.
getLCP(console.log, true);
这些变化的指标若是触发屡次的话可能会屡次发送到你的服务器,因此回调函数中提供了下面三个参数:
-
name
:指标名称 -
id
:本地分析的id -
delta
:当前值和上次获取值的差值
所以你只须要每次上报 delta
(当前值和上次获取值的差值),而不须要报告新值。而后在服务器能够经过计算全部id对应值的和来获取最终结果。

import {getCLS, getFID, getLCP} from 'web-vitals';
function logDelta({name, id, delta}) {
console.log(`${name} matching ID ${id} changed by ${delta}`);
}
getCLS(logDelta, true);
getFID(logDelta);
getLCP(logDelta, true);
你能够很好的结合 Google Analytics
来记录你的上报指标:
import {getCLS, getFID, getLCP} from 'web-vitals';
function sendToGoogleAnalytics({name, delta, id}) {
ga('send', 'event', {
eventCategory: 'Web Vitals',
eventAction: name,
eventValue: Math.round(name === 'CLS' ? delta * 1000 : delta),
eventLabel: id,
nonInteraction: true,
});
}
getCLS(sendToGoogleAnalytics);
getFID(sendToGoogleAnalytics);
getLCP(sendToGoogleAnalytics);
使用 Chrome 插件
若是你不想在程序中计算,还可使用 Chrome
插件这样更方便的方式,Google
也提供了一个新的插件 web-vitals-extension
来帮助咱们获取这些指标:

这个插件很是简洁,只有 CLS、FID、LCP
这三个核心指标,这样能够大大聚焦咱们的关注度,下降理解成本。

徽章的颜色能够告诉你页面有没有经过默认设定的阈值:
-
灰色:插件不支持或者被禁用 -
绿色:经过全部指标 -
红色:一个或多个指标不达标
参考
-
https://web.dev/vitals/ -
https://web.dev/lcp/ -
https://web.dev/fid/ -
https://web.dev/cls/ -
https://github.com/GoogleChrome/web-vitals#api -
https://github.com/GoogleChrome/web-vitals-extension -
https://developers.google.com/web/updates/2020/05/nic83#coop
公众号:前端食堂
掘金:童欧巴
知乎:童欧巴
这是一个终身学习的男人,他在坚持本身热爱的事情,欢迎加入前端食堂,和这个男人一块儿开心的变胖~
推荐阅读:
在看和转发是莫大鼓励❤️
本文分享自微信公众号 - 前端食堂(webcanteen)。
若有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一块儿分享。