Day04 X Core Web Vital & RAIL Model

在昨天介绍网页检测工具时,我们看到它提供了一些看起来十分专业的 Metrics,不过光看文字还真的猜不出它们代表的是什麽意思 ?

今天第一个段落会介绍三个评估使用者体验的指标:LCP、FID、CLS,它们也被称作 Core Web Vitals。

第二个段落则会介绍由 Google 提出且是「以使用者为中心」的用效能衡量指标 - RAIL Model。

Core Web Vitals

Google 根据长期以来大量的使用者体验制定出了网站使用体验的核心指标( Core Web Vital) ,Google 更指出若 75% 以上的使用者在网站中的浏览体验都能够通过以上 3 种指标,就能够大幅的提升使用者的搜寻体验,甚至能够让原本因等待而离开的使用者减少 24%!

虽然说这个指标是专门拿来评定使用者体验的,不过经过前面几天的介绍,大家应该早就了解前端应用的效能之於使用者体验大概就像汽车的引擎之於整台车了,没有马力强大的引擎在背後运转,设备再高级的进口车也终究只是单纯拿来欣赏的摆饰。效能一塌糊涂的网站就算做的再漂亮再炫,使用者终究会因为没有良好的体验而选择离开。

虽说网站效能只是 Core Web Vitals 列入的其中一个考量,然而藉由提升网站效能,我们可以提升 Core Web Vitals 的指标分数,进而改善使用者体验,因此我认为 Core Web Vitals 是在做前端效能优化时不可或缺的参考指标。今天就来好好认识它们,并了解提升各个指标的方法吧!

LCP (Largest Contentful Paint ) — 显示最大内容元素所需时间 [速度指标]

LCP 是计算网页可视区 (viewport) 中最大元件的载入时间,也就是页面的主要内容被使用者看到的时间,是速度的指标。

不过可视区内最大的元素并不是固定不变的

上图的页面在载入时一开始可视区的最大元素是左上角的文字,接下来随着页面载入变成了标题,最後变成了图片,因为图片是可视区最大的元素了,因此 LCP 就会以该图片所需要载入的时间做计算。

目前会被 LCP API 考虑的 DOM 元件有:

  • <img> elements
  • 包在 <svg> element 里面的 <image> elements
  • <video> elements
  • 透过 CSS url() 函式载入 background-image 的 element
  • 包含 text node 或是 inline-level text elements children 的 block-level element

如何优化 LCP

优化 LCP 的方法蛮直觉的,就是尽可能加快最大化元素 candidates 的载入速度,因此方法非常多元

减少服务器回应时间

  • 针对主机效能优化
  • 使用地理位置较近的 CDN cache 静态资源
  • 善用 Browser Cache
  • 提早载入第三方资源

尽量避免 Blocking Time

  • 降低 JavaScript blocking time
  • 降低 CSS blocking time

加快资源载入的时间

  • 图片大小优化
  • 预先载入重要资源
  • 将文字档案进行压缩
  • 根据使用者的网路状态提供不同的内容
  • 使用 service worker

避免使用客户端渲染(CSR)

  • 若必须使用 CSR ,建议优化 JavaScript ,避免渲染时使用太多资源
  • 尽量在服务器端完成页面渲染,让用户端取得已渲染好的内容

想更了解 LCP 的眉眉角角的读者可以参考LCP 官方文件

FID — First Input Delay 首次输入延迟/封锁时间总计 [互动性指标]

FID 用於测量使用者第一次对网站进行互动的时间,不过 FID 仅将单次互动例如滑鼠点击,而不将画面缩放,滑鼠滚动等连续性操作考虑进去。输入延迟 (Input Delay) 通常发生於浏览器的主执行序(Main Thread)过度繁忙,而导致页面内容无法正确地与使用者进行互动。举例来说,可能浏览器正在载入一支相当肥大的 JavaScript 档案,导致其他元素不能被载入而延迟可互动的时间。

例如,当你今天进入一个网页时,发现网页中有一个表单,你点击输入匡想要输入文字,却发现网站还没完全载入完,网页没办法马上回应你的行为,点击输入匡却完全没有任何如 input focus 的反馈,也没办法输入文字,这大大影响了使用者体验,这就是 FID 所在意的针对互动性的时间衡量。

如何优化 FID

  • 减少 JavaScript 运作的时间
  • 降低网站的 request 数并降低档案大小
  • 减少主执行序的工作
  • 降低第三方程序码的影响

想更了解 FID 的眉眉角角的读者可以参考FID 官方文件

CLS — Cumulative Layout Shift 累计版面配置转移 [稳定性指标]

有没有遇过一种情况是当你在网页中准备点击一个按钮或连结的瞬间,突然间一个广告插入或是跳出来,让你不小心点开别的网站,恨的牙痒痒的呢?这就是 CLS 这个指标想要避免的不良体验。

什麽情形会造成 CLS 分数不佳

Google 的官方文件指出几点可能会造成 CLS 指数不佳的原因:

  • 图片缺少初始尺寸,所以等载入後宽高才会长出来
  • 缺少尺寸的广告、内嵌(embed)以及 iframe
  • 动态置入内容
  • 下载网站字体有机会造成页面闪烁
  • 更新 DOM 前等待网路回应的动作

如何避免 CLS

CLS 这个指数本身就跟效能比较没有关系了,他的解决方式也很直觉,例如给予会比较慢载入的元素一个预设的宽度与高度,就可以避免页面 Layout 随着资源载入跟着跳动。至於下载字体问题最简单的解法是透过 preload 的 resource hint,这也会在未来的篇章介绍到。

CLS 的计算方式

LCP 跟 FID 都是用反应时间来当作指标,唯独 CLS 是一个介於 0-1 之间的指标分数,那究竟这个分数是怎麽计算出来的呢?

元件移位分数(layout shift score) = 影响范围(impact fraction) * 移动距离(distance fraction)

以上面这张图为例子,这个元素偏移的影响范围为整个萤幕长度的 75%,元件的移动距离为萤幕长度的 25%,因此此元素的 CLS 分数为 0.75*0.25 = 0.1875。(不过要精确一点的话还有一些要素要加进计算当中,但我们可以先忽略它)

然而这只是其中一个元素的分数,网站的 CLS 分数则是将所有发生位移的元件依上述公式算出来的值进行加总,一个稳定性良好的网站必须把加总的值控制在 0.1 以内才算合格。

我喜欢绚丽的动画,会不会让网站 CLS 变很高啊?

网页的动画常常使用到让页面元素移动的技巧,例如点选 Menu 展开更多选项的清单,那这样会不会影响 CLS 分数啊?CLS 所在意的是「非预期的转移」,所以如果页面上的转移动画很明显跟使用者互动有关,就不会被算进 CLS 里喔!

想更了解 CLS 的眉眉角角的读者可以参考CLS 官方文件


除了透过 Lighthouse 等网页监测工具,还有没有其他方式可以算出网站的 Core Web Vitals ?

当然有的,如果想知道还有什麽方式可以得出 Core Web Vitals 可以参考这里

不过我认为一个蛮酷的方式是 Core Web Vitals 也推出 NPM Module 让开发者可以透过程序得到这些指标啦!

import {getCLS, getFID, getLCP} from 'web-vitals';

function sendToAnalytics(metric) {
  const body = JSON.stringify(metric);
  // Use `navigator.sendBeacon()` if available, falling back to `fetch()`.
  (navigator.sendBeacon && navigator.sendBeacon('/analytics', body)) ||
      fetch('/analytics', {body, method: 'POST', keepalive: true});
}

getCLS(sendToAnalytics);
getFID(sendToAnalytics);
getLCP(sendToAnalytics);

RAIL Model

RAIL Model 是由 Google 所提出的一个效能指标,是一个「以使用者为中心」的模式,这个模型将使用者体验细分成一些 key actions,例如 tap, scroll, load,并且协助我们更容易定义它们的效能指标,目标是让使用者体验可以更好。

RAIL 代表的是 Web App Life Cycle 里的四个指标:

  • R : Response
  • A : Animation
  • I : Idle
  • L : Load

使用者对它们分别会有不同的期待与标准,来判断一个网站的效能好不好。

Response : process events in under 50ms

根据一些可靠的研究所得出的结论,人类从操作行为到感知反应有 100 毫秒的间隔,也就是说使用者注意到延迟之前,我们有 100 毫秒的时间去回应使用者的行为。

咦?那为什麽上面写 under 50ms ?

我们的目标是在 100ms 以内回应使用者的行为没错,那到底为什麽上面又写 50ms 呢?原因在於通常除了处理使用者的 input 事件,浏览器还有其他的工作要做,而这些工作占用了可接受输入响应的部分可用时间。

考虑到这一点,可以安全地假设只有剩余的 50 毫秒可用於实际处理使用者的 input 事件。下图显示了在 idle task 间收到的输入如何排队,从而减少了可用的处理时间

至於什麽是 idle task,为什麽是 idle task 是 50ms,等等会说明。

Animation: produce a frame in 10ms

目前大多数的装置会以「每秒 60 次」的频率重新整理萤幕,也就是每秒 60 帧(常常听到别人说 frame rate 其实就是在指这个,常看到的 60 fps 代表的是 60 frames per second),才能让使用者看到平顺的动画。这也就代表每一帧的时间只能花 16ms 左右 (一秒 1000ms / 60 = 16.66)。

咦?怎麽又来了,上面写 10ms 耶!原因是因为浏览器大概需要 6ms 来渲染每一帧,所以才会说希望工作尽量在 10ms 内完成。如果超出这个标准太多或是帧率不稳定,浮动性很高,画面便会开始出现抖动、卡顿,严重影响使用者体验。

至於提升 frame rate 的方式,後面的篇章都会陆续提到,今天先有这个概念就够了。

Idle: maximize idle time

目标是最大化的利用 idle time 以提升使用者的 input event 在 50ms 以内获得回应的机会。

  • 我们可以利用 idle time 来做一些延迟的工作,像是为了加快页面首次载入(Page Initial Load)的速度,可以尽可能在一开始载入少量但必要的资料,剩余的资料可以利用 idle time 来载入。
  • 在 50ms 或更短的 idle time 内执行工作。如果超过 50ms,就有可能干扰网页在 50ms 内响应使用者 input 的能力。
  • 如果使用者在 idle time 的工作期间与页面交互,则使用者交互应始终具有最高的 priority 并中断 idle time 的工作。

Load: deliver content and become interactive in under 5 seconds

经过 Day02 後我们知道页面载入速度会大大影响使用者跳出率甚至影响企业的营收,所以能够尽快载入页面且让使用者可以开始与之互动是很重要的目标。不过页面载入速度其实也跟装置的硬体资源与网路环境有关,所以 RAIL 根据使用者体验的研究後订出了一个目标:使用者在使用中低规格的 mobile device 且搭配缓慢的 3G 网路环境情况下,网站能够在 5 秒内载入完毕且让使用者可以开始与之互动,是一个效能好的网站需要达到的最低指标。

至於如何提升载入速度,也是未来篇章会慢慢介绍的。

RAIL Model 的介绍就到这边,可能有读者会疑问为什麽会出现一些奇怪的数字指标,像是 idle time 要在 50ms 内做完、页面要在 5 秒内载入等等,还记得吗?RAIL Model 是一个以「使用者为中心」的效能指标,这些数据指标都是大量的使用者经验与数据经过整理与分析後得出的,个人觉得参考性蛮高的喔!
(使用者体验真的又是一个非常博大精深的领域了)

本日小结

首先真的要感谢读者看到今天还没有左转离开,因为目前为止都还没有真的开始介绍效能优化的方法,而是在介绍效能优化的目的与参考指标,虽然些许乏味,不过我想读者们一定明白这些观念是非常重要的!相信读者现在一定很清楚我们未来要进行的优化它们的目的到底是什麽了。

好消息!明天终於要正式进入介绍效能优化的各个技巧的章节了,不过别担心,会先从最简单的方式开始介绍,再慢慢深入到较需要花心思理解的技术,大家明天见!

References & 图片来源

https://web.dev/vitals/
https://web.dev/vitals-tools/
https://web.dev/lcp/
https://web.dev/fid/
https://web.dev/cls/
https://www.youtube.com/watch?v=wO9GGY17NXY
https://ithelp.ithome.com.tw/articles/10187164
https://web.dev/rail/


<<:  从零开始的8-bit迷宫探险【Level 11】在 iPhone 里盖座迷宫,就。很。墙

>>:  day5 network simulator GNS3 (雷)没硬体怎麽玩?

[Day1] 资讯安全是什麽?

第一天,想笔记下我对资讯安全的理解。 资讯安全怎麽来的? 我印象里的历史战争剧中,国家或两个阵营打仗...

JS 06 - 建构函式

大家好! 今天开始就要学习函式库的基础了。 我们进入今天的主题吧! 物件模板 我们先来看下方的资料:...

Day 29 Chatbot integration- 多功能 chatbot 就此诞生!

Chatbot integration- 多功能 chatbot 就此诞生! 终於到了这一步,要把所...

[Day 30] LeetCode - 125 Valid Palindrome

本篇同步发布於Blog:[解题] LeetCode - 125 Valid Palindrome 平...

Day22-不能说的秘密(四)

前言 前几天谈了那麽多种储存密码的方式之後,大家应该都累了,所以今天来谈一个比较轻松的实际案例 如果...