解讀新一代 Web 效能體驗和質量指標

ConardLi發表於2020-05-26

衡量一個 Web 頁面的體驗和質量一直有非常多的工具和指標 ... 每次我們去關注這些指標的時候都會非常痛苦,因為這些指標真的是又多又難理解,測量這些指標的工具也非常多。

當看到最近釋出的 Chrome 83 中又增加了幾個效能指標的時候我頭都大了...

然而不要著急,這些指標就是為了聚焦關注度和降低理解成本的,下面我們就來具體看一下,新增加的 Core Web Vitals 到底是什麼東西?

如何衡量使用者體驗質量?

優化使用者體驗的質量一直都是是每個 Web 站點長期成功的關鍵,衡量使用者體驗的質量有很多方面。雖然使用者體驗的某些方面是需要基於特定於站點和上下文的,但是所有站點仍然有一組共同的指標——Core Web Vitals,這些指標包括載入體驗、互動性和頁面內容的視覺穩定性,他們構成了 2020 年核心 Web 健康指標的基礎。

多年來,Google 提供了很多工具:(Lighthouse, Chrome DevTools, PageSpeed Insights, Search Console's Speed Report) 來衡量和報告效能。一些開發人員是使用這些工具的專家,而大部分其他人則發現大量的工具和衡量標準都很難學習和使用。

網站開發者不應該為了理解他們交付給使用者的體驗的質量指標而成為效能專家。Web Vitals 計劃的目的就是簡化場景,降低學習成本,並幫助站點關注最重要的指標,即 Core Web Vitals

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 頁主要內容的載入速度是眾多開發者一直在關注的一個點,而且可衡量的指標非常多。

比如最早的 loadDOMContentLoaded 事件,用這兩個事件來衡量頁面載入速度是非常糟糕的,因為它們不一定與使用者在螢幕上看到的內容相對應。

以使用者為中心的更新效能指標(例如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較差的最常見原因是:

  • 伺服器響應時間慢
  • 阻斷渲染的 JavascriptCSS
  • 資源載入時間慢
  • 客戶端渲染

所以我們從上面的角度去考慮改善 LCP

優化伺服器

這個很好理解,瀏覽器從伺服器接收內容所需的時間越長,則在螢幕上呈現任何內容所花費的時間就越長。更快的伺服器響應時間可以直接改善包括 LCP 在內的所有頁面載入指標。

衡量伺服器相應時間有一個專門的指標:首位元組相應時間(TTFB)是最初的網路請求被髮起到從伺服器接收到第一個位元組這段時間,它包含了 TCP 連線時間,傳送 HTTP 請求時間和獲得響應訊息第一個位元組的時間。你可以嘗試在下面幾個方便優化 TTFB

  • 快取 HTML 離線頁面,快取頁面資源,減少瀏覽器對資源的請求。
  • 儘量減小資源阻斷渲染:CSSJavaScript 壓縮、合併、級聯、內聯等等
  • 對圖片進行優化。轉化圖片的格式為 JPG 或者 WEBP 等等的格式,降低圖片的大小,以加快請求的速度。
  • HTML 重寫、壓縮空格、去除註釋等。減少 HTML 大小,加快速度。
  • 使用 preconnect 儘快與伺服器建立連結、使用 dns-prefetch 儘快進行 DNS 查詢。
  • 使用 CDN 加快請求速度

優化阻斷渲染的資源

JavaScriptCSS 都是會阻斷頁面渲染的資源,需要儘可能的對 CSSJavaScript 檔案進行壓縮、延遲載入首屏無需使用的 JavaScript、內聯關鍵的 CSS 等來減小阻斷時間。

優化資源載入時間

剛才我們上面提到的這些資源,如果在首屏進行渲染,則載入這些元素所花費的時間將直接影響 LCP

  • <img> 元素
  • <image>元素內的<svg>元素
  • <video> 元素
  • 通過 url() 函式載入背景圖片的元素
  • 包含文字節點或其他內聯文字元素子級的塊級元素。

你可以使用下面的手段進行優化:

  • 對圖片進行優化。轉化圖片的格式為 JPG 或者 WEBP 等等的格式,降低圖片的大小。
  • 對重要的資源進行預載入,比如為 style 標籤新增 rel="preload" 屬性
  • 使用 GzipBrotli 壓縮頁面資源,降低傳輸時間
  • 使用 service worker 快取資源

服務端渲染

使用服務端渲染可以確保首先在伺服器上呈現頁面內容,可以有效改善 LCP,但是相比客戶端渲染的缺點是會加大頁面從而影響 TTFB、服務端渲染需要等待所有 js 執行完畢後才能相應使用者輸入,這會使互動體驗變差。

FID

第一印象

我們都知道留下一個好的第一印象是多麼重要。在網路上,一個好的第一印象可以決定一個人是不是可以成為一個網站的忠實的使用者,或者是離開以後再也不會回來。問題是,什麼能給人留下好印象,你如何衡量你可能給使用者留下什麼樣的印象?

在網路上,第一印象可以有很多種不同的形式——我們對網站的設計和視覺吸引力有第一印象,對其速度和響應能力也有第一印象。

開發者們使用 First Contentful Paint(FCP) 可以衡量對網站載入速度對第一印象 。但是,網站可以在螢幕上繪製畫素的速度只是一部分,同樣重要的是使用者嘗試與這些畫素進行互動時你的網站的響應速度!

什麼是 FID

FID( First Input Delay) 即記錄使用者和頁面進行首次互動操作所花費的時間 。FID 指標影響使用者對頁面互動性和響應性的第一印象。 為了提供良好的使用者體驗,站點應努力使首次輸入延遲小於 100 毫秒。

FID 發生在 FCPTTI 之間,因為這個階段雖然頁面已經顯示出部分內容,但尚不具備完全的可互動性。這個階段使用者和頁面互動,往往會有較大延遲。

如上圖所示,瀏覽器接收到使用者輸入操作時,主執行緒正在忙於執行一個耗時比較長的任務,只有當這個任務執行完成後,瀏覽器才能響應使用者的輸入操作。它必須等待的時間就此頁面上該使用者的 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?

不要使用無尺寸元素

影像和視訊等元素上始終需要包括 widthheight 尺寸屬性,現代瀏覽器會根據影像的 widthheight 屬性設定影像的預設長寬比,知道縱橫比後,瀏覽器就可以為元素計算和保留足夠的空間。

或者,使用 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 APIJavaScript 中測量每個指標。 Google 提供了一個 npm 包:web-vitals,這個庫提供了非常簡單的 API,測量每個指標就像呼叫一個普通函式一樣簡單:

npm install web-vitals

每個測量函式都接收一個 report 回撥函式作為引數,回撥函式將在測量完成後觸發,另外,對於像 LCPCLS 這樣的指標是不斷變化的,所以它們的回撥函式可能會多次觸發,如果你想獲取在這期間獲取每次變化的數值,你可以指定第二個引數 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 這三個核心指標,這樣可以大大聚焦我們的關注度,降低理解成本。

徽章的顏色可以告訴你頁面有沒有通過預設設定的閾值:

  • 灰色:外掛不支援或者被禁用
  • 綠色:通過所有指標
  • 紅色:一個或多個指標不達標

參考

小結

最後,想在瀏覽器中使用上面的工具和指標?快升級一下 Chrome 83 版本吧~,更多 Chrome 83 的更新可以點選 Chrome 83 釋出,支援直接讀寫本地檔案!新的跨域策略! 檢視。

文中如有錯誤,歡迎在評論區指正,如果這篇文章幫助到了你,歡迎點贊和關注。

想閱讀更多優質文章、可關注我的github部落格,你的star✨、點贊和關注是我持續創作的動力!

推薦關注我的微信公眾號【code祕密花園】,每天推送高質量文章,我們一起交流成長。

相關文章