(給前端食堂加星標,吃好每一頓飯)前端
衡量一個 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源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。