Lighthouse與Google的移動端最佳實踐

任乃千發表於2019-03-03

Lighthouse是一個Google開源的自動化工具,主要用於改進網路應用(移動端)的質量。目前測試項包括頁面效能PWA可訪問性(無障礙)最佳實踐SEO。Lighthouse會對各個測試項的結果打分,並給出優化建議,這些打分標準和優化建議可以視為Google的網頁最佳實踐。

options.png

使用入門


執行Lighthouse的方式有三種:在開發者工具(Devtools)的Audits,作為Chrome擴充程式使用,或者作為命令列工具使用。Chrome開發者工具不需要額外安裝,和擴充套件程式一樣提供了一個使用者友好的介面,方便讀取報告;擴充套件程式相對於開發者工具的優勢是更及時,不用等待Chrome發版就能體驗到最新的功能;命令列工具可以將Lighthouse整合到持續整合系統。

開發者工具

僅能在Chrome60及以上使用,因為之前版本的Chrome的開發者工具的audits皮膚還不是Lighthouse。

extension.png

audits.png

通過右上角的選單或者快捷鍵(command+option+i)開啟開發者工具,然後選擇audits皮膚,點選Perform an audits會彈出一個options皮膚勾選測試項然後點選Run audits即可。

Chrome擴充程式

安裝地址(需要梯子)

extension.png
generate.png

在右上角或者選單裡點選圖中圖示,Options可以配置測試專案,點選Generate report即可測試。

命令列工具

安裝:

npm install -g lighthouse
# or use yarn:
# yarn global add lighthouse
複製程式碼

使用:

lighthouse https://example.com
複製程式碼

配置項:

$ lighthouse --help

lighthouse <url>

Logging:
  --verbose  Displays verbose logging                                                                                                      [boolean]
  --quiet    Displays no progress, debug logs or errors                                                                                    [boolean]

Configuration:
  --save-assets                  Save the trace contents & screenshots to disk                                                             [boolean]
  --list-all-audits              Prints a list of all available audits and exits                                                           [boolean]
  --list-trace-categories        Prints a list of all required trace categories and exits                                                  [boolean]
  --additional-trace-categories  Additional categories to capture with the trace (comma-delimited).
  --config-path                  The path to the config JSON.
  --chrome-flags                 Custom flags to pass to Chrome (space-delimited). For a full list of flags, see
                                 http://peter.sh/experiments/chromium-command-line-switches/.

                                 Environment variables:
                                 CHROME_PATH: Explicit path of intended Chrome binary. If set must point to an executable of a build of
                                 Chromium version 54.0 or later. By default, any detected Chrome Canary or Chrome (stable) will be launched.
                                                                                                                                       [default: ""]
  --perf                         Use a performance-test-only configuration                                                                 [boolean]
  --port                         The port to use for the debugging protocol. Use 0 for a random port                                    [default: 0]
  --hostname                     The hostname to use for the debugging protocol.                                              [default: "localhost"]
  --max-wait-for-load            The timeout (in milliseconds) to wait before the page is considered done loading and the run should continue.
                                 WARNING: Very high values can lead to large traces and instability                                 [default: 45000]
  --enable-error-reporting       Enables error reporting, overriding any saved preference. --no-enable-error-reporting will do the opposite. More:
                                 https://git.io/vFFTO
  --gather-mode, -G              Collect artifacts from a connected browser and save to disk. If audit-mode is not also enabled, the run will quit
                                 early.                                                                                                    [boolean]
  --audit-mode, -A               Process saved artifacts from disk                                                                         [boolean]

Output:
  --output       Reporter for the results, supports multiple values                        [choices: "json", "html", "domhtml"] [default: "domhtml"]
  --output-path  The file path to output the results. Use 'stdout' to write to stdout.
                 If using JSON output, default is stdout.
                 If using HTML output, default is a file in the working directory with a name based on the test URL and date.
                 If using multiple outputs, --output-path is ignored.
                 Example: --output-path=./lighthouse-results.html
  --view         Open HTML report in your browser                                                                                          [boolean]

Options:
  --help                        Show help                                                                                                  [boolean]
  --version                     Show version number                                                                                        [boolean]
  --blocked-url-patterns        Block any network requests to the specified URL patterns                                                     [array]
  --disable-storage-reset       Disable clearing the browser cache and other storage APIs before a run                                     [boolean]
  --disable-device-emulation    Disable Nexus 5X emulation                                                                                 [boolean]
  --disable-cpu-throttling      Disable CPU throttling                                                                    [boolean] [default: false]
  --disable-network-throttling  Disable network throttling                                                                                 [boolean]
  --extra-headers               Set extra HTTP Headers to pass with request                                                                 [string]

Examples:
  lighthouse <url> --view                                                   Opens the HTML report in a browser after the run completes
  lighthouse <url> --config-path=./myconfig.js                              Runs Lighthouse with your own configuration: custom audits, report
                                                                            generation, etc.
  lighthouse <url> --output=json --output-path=./report.json --save-assets  Save trace, screenshots, and named JSON report.
  lighthouse <url> --disable-device-emulation --disable-network-throttling  Disable device emulation
  lighthouse <url> --chrome-flags="--window-size=412,732"                   Launch Chrome with a specific window size
  lighthouse <url> --quiet --chrome-flags="--headless"                      Launch Headless Chrome, turn off logging
  lighthouse <url> --extra-headers "{\"Cookie\":\"monster=blue\"}"          Stringify\'d JSON HTTP Header key/value pairs to send in requests
  lighthouse <url> --extra-headers=./path/to/file.json                      Path to JSON file of HTTP Header key/value pairs to send in requests

For more information on Lighthouse, see https://developers.google.com/web/tools/lighthouse/.
複製程式碼

測試結果示例


result.png

最佳實踐


這些最佳實踐主要針對移動端或者Web應用。某些技術對瀏覽器版本要求較高,用之前最好在Can I useMDN上查一下瀏覽器支援情況

開啟外部連結使用rel="noopener"

當頁面使用 target="_blank" 跳轉至另一個頁面時,新頁面將與您的頁面在同一個程式上執行。 如果新頁面正在執行開銷極大的 JavaScript,您的頁面效能可能會受影響。最重要的是target="_blank”也是一個安全漏洞。新頁面可以通過window.opener訪問舊頁面的window物件,並且它可以使用window.opener.location=newURL將舊頁面導航至不同的網址。所以當在新視窗或標籤中開啟一個外部連結時,應該始終加上rel="noopener",例如:

<a href="https://examplepetstore.com" target="_blank" rel="noopener">...</a>
複製程式碼

位址列顏色應該和品牌顏色、網頁主題匹配

address.png

就是位址列的背景顏色應該和品牌顏色一致 通過meta標籤實現的:

<meta name="theme-color" content="#ff6633">
複製程式碼

不過僅在認可這個meta的瀏覽器上有效,比如Chrome for Android,實測pc、ios的Chrome、Safari無效。

bilibili.png

如果場景能用上還是能提高一些使用者體驗的,避免了位址列突兀。

避免使用AppCache

AppCache已被廢棄 考慮使用service worker的Cache API,另外現在ios 11.3也支援了service worker,未來一兩年應該有很大發展。

避免使用console.time()

如果使用console.time()測試頁面效能,請考慮使用User Timing API。其優勢包括:

  • 高解析度時間戳
  • 可匯出的計時資料
  • 與Chrome Devtools TImeline相整合。在 Timeline 錄製期間呼叫 User Timing 函式 performance.measure() 時,DevTools 自動將此測量結果新增到 Timeline 的結果中。 將console.time()替換為performance.mark()。如果需要測量兩個label之間經過的時間,則使用performance.measure()。User Timing API
// 獲得命名時間戳
window.performance.mark('mark_fully_loaded');
// 獲得命名時間戳之間的時間間隔或者與PerformanceTiming的時間間隔
window.performance.measure('measure_load_from_dom', 'domComplete', 'mark_fully_loaded');
複製程式碼

避免使用Date.now()

考慮改用performance.now()代替Date.now()。performance.now()可提供較高的時間戳解析度,並始終以恆定的速率增加,它不受系統時鐘(可以調整)的影響。performance.now()

// 獲取相對於navigationStart屬性中的時間戳為起點開始計時的精確到千分之一毫秒的時間戳
 window.performance.now()
複製程式碼

避免棄用的API

已棄用的API計劃從Chrome中移除,使用這些API後,被刪除後將導致網頁出錯。檢視Chrome平臺狀態

避免使用document.write()

對於網速較慢(2G、3G或較慢的WLAN)的使用者,外部指令碼通過document.write()動態注入會使頁面內容的顯示延遲數十秒。

避免巨大的網路負載

延遲請求直到需要它們 啟用文字壓縮 壓縮HTML、JS和CSS 使用Webp而不是JPEG或PNG 將JPEG影象的壓縮級別設定為85 快取請求

避免使用mutation events

以下mutation events會損害效能,在DOM事件規範中已經棄用:

  • DOMAttrModified
  • DOMAttributeNameChanged
  • DOMCharacterDataModified
  • DOMElementNameChanged
  • DOMNodeInserted
  • DOMNodeInsertedIntoDocument
  • DOMNodeRemoved
  • DOMNodeRemovedFromDocument
  • DOMSubtreeModified

建議將每個mutation events替換成MutationObserver

避免使用舊版CSS Flexbox

2009年的舊Flexbox規範已棄用,其速度比最新的規範慢2.3倍。將頁面中的display:box及以box開頭的每個屬性替換成標準的Flexbox屬性。

避免在頁面載入時自動請求地理位置

頁面在載入時自動請求使用者位置會使使用者不信任頁面或感到困惑。應將此請求與使用者的手勢進行關聯,而不是在頁面載入時自動請求使用者的位置。

避免在頁面載入時自動請求通知許可權

好的通知需要做到及時、相關且準確。如果頁面在載入時要求許可權以傳送通知,則這些通知可能與您的使用者無關或者不是他們的精準需求。為提高使用者體驗,最好是向使用者傳送特定型別的通知,並在他們選擇加入後顯示許可權請求。

避免使用Web SQL

Web SQL已棄用,建議替換為IndexedDB

背景和前景應該有足夠的對比度

低對比度文字對於許多使用者來說很難或不可能讀取 使用Chrome擴充套件程式aXe可以分析出所有的可訪問性問題

按鈕有一個可訪問的名稱

沒有名字的按鈕對依賴螢幕閱讀器的使用者不可用。當一個按鈕沒有名字時,螢幕閱讀器會宣佈“按鈕”。 對<button>元素和role="button"的元素:

  • 設定元素的內部文字
  • 設定aria-label屬性
  • 將該aria-labelledby屬性設定為螢幕閱讀器可見的文字元素。

對於<input type = "button">的元素:

  • 設定value屬性
  • 設定aria-label屬性
  • 設定aria-labelledby屬性

對於<input type="submit">和<input type="rest">:

  • 設定value屬性,或省略它。瀏覽器在value省略時賦予"submit"或"reset"的預設值
  • 設定aria-label屬性
  • 設定aria-labelledby屬性

頁面在其指令碼不可用時包含一些內容

基本內容和頁面功能不應該依賴於CSS或JS。對於必需依賴JavaScript的頁面,一種方法是使用一個元素,以提醒使用者此頁面需要JavaScript。

優化關鍵渲染路徑

將關鍵資源數降至最低:消除關鍵資源、延遲關鍵資源的下載並將它們標記為不同步等。 優化關鍵位元組數以縮短下載時間。 優化其餘關鍵資源的載入順序:儘早下載所有關鍵資源,以縮短關鍵路徑長度。

避免長寬比不正確的影象

如果渲染的影象與其原始檔中的長寬比不同,則呈現的影象可能看起來失真,產生不愉悅的使用者體驗。

  • 避免將元素的寬度或高度設定為可變大小的容器的百分比。
  • 避免設定不同於源影象尺寸的顯式寬度或高度值。
  • 考慮使用css-aspect-ratio或 Aspect Ratio Boxes來幫助保留寬高比。
  • 如果可能的話,在HTML中指定圖片的寬度和高度是一個很好的做法,這樣瀏覽器就可以為圖片分配空間,這樣可以防止頁面在載入時跳過。在HTML中而不是CSS中指定寬度和高度是更理想的,因為瀏覽器在解析CSS之前分配空間。實際上,如果您使用響應式影象,則此方法可能很困難,因為在知道視口尺寸之前無法指定寬度和高度。

啟用文字壓縮

如果瀏覽器支援,則配置伺服器以使用Brotli壓縮響應。Brotli比GZIP可以節省更多的流量。如果不支援Brotli則使用GZIP。在Chrome DevTools檢查響應是否被壓縮:

  • 開啟DevTools的Network皮膚
  • 點選指定的回覆的請求。
  • 點選Headers選項卡
  • 檢查Response Headers中content-heading欄位
    content.png

預計輸入延遲時間

輸入響應能力對使用者如何看待應用的效能起著關鍵作用。應用有100毫秒的時間響應使用者輸入。如果超過此時間,使用者就會認為應用反應遲緩。

優化程式碼在瀏覽器中的執行方式:

  1. 對於動畫效果的實現,避免使用setTimeout或setInterval,請使用requestAnimationFrame
  2. 將長時間執行的JavaScript從主執行緒移動到Web Worker
  3. 使用micro-tasks來執行對多個幀的DOM更改
  4. 使用Chrome DevTools的Timeline和Javascript分析器來評估JavaScript的影響。 降低選擇器的複雜性(例如:nth-of-type、:nth-child);使用以類為中心的方法,例如BEM,這有一篇BEM的教程
  5. 儘可能避免佈局操作,對“幾何屬性”(如寬度、高度左側或頂部)的更改都需要佈局計算。佈局幾乎總是作用到整個文件,如果有大量元素,會消耗很長時間來計算出所有元素的位置和尺寸。
  6. 避免強制同步佈局
    render.png
    首先JavaScript執行,然後計算樣式,然後佈局。但是,可以使用JavaScript強制瀏覽器提前執行佈局。這被稱為強制同步佈局。在JavaScript執行時,來自上一幀的所有舊佈局值是已知的,並且可供查詢。因此,如果在幀的開頭寫出一個元素的高度是沒有問題的,但是在查詢高度之前,已經更改其樣式,如下列程式碼。,就會強制頁面計算返回正確的高度。這是不必要的,並且開銷很大。始終應先批量讀取樣式並執行,然後執行任何寫操作。
function logBoxHeight() {

  box.classList.add('super-big');

  // Gets the height of the box in pixels
  // and logs it out.
  console.log(box.offsetHeight);
}
複製程式碼
  1. 除 transform 或 opacity 屬性之外,更改任何屬性始終都會觸發繪製。可以使用Chrome DevTools來快速確定正在繪製的區域。開啟DevTools,按下鍵盤上的 Esc 鍵。在出現的皮膚中,轉到“rendering”標籤,然後選中“Show paint rectangles”。

    rendering.png

  2. 每一個表單元素都應該有一個label label闡明瞭表單元素的用途。雖然每個元素的目的對於有視覺的使用者來說可能是顯而易見的,但對於依靠螢幕閱讀器的使用者來說並非如此。有四種方式可以實現:

  • 隱含標籤
<label>First Name <input type="text"/></label>
複製程式碼
  • 顯式標籤
<label for="first">First Name <input type="text" id="first"/></label>
複製程式碼
  • aria-label
<button class="hamburger-menu" aria-label="menu">...</button>
複製程式碼
  • aria-labelledby
<span id="foo">Select seat:</span>
<custom-dropdown aria-labelledby="foo">...</custom-dropdown>
複製程式碼
  1. 每個影象都有一個alt屬性 資訊性影象應該具有alt包含該影象內容的文字描述的屬性。螢幕閱讀器使視覺障礙的使用者能夠通過將文字內容轉換為可以使用的表格(如合成語音或盲文)來使用您的網站。螢幕閱讀器無法轉換影象。因此,如果您的圖片包含重要資訊,那麼視覺障礙使用者無法獲取該資訊。 可以在DevTools的Console選項卡中使用以下命令來查詢沒有alt屬性的圖片
$$('img:not([alt])');
複製程式碼

在Console中$$()相當於document.querySelectorAll()

  1. 配置HTML的Viewport meta標籤 如果沒有Viewport meta標籤,移動裝置將以典型的桌面裝置螢幕寬度渲染頁面,然後對頁面進行縮放以適合移動裝置螢幕。通過Viewport meta標籤可以控制寬度和縮放比例。 配置視口 設定視口 width=device-width鍵值對將視口寬度設定為裝置寬度。在訪問頁面時,initial-scale=1鍵值對設定初始縮放級別。
<head>
  ...
  <meta name="viewport" content="width=device-width, initial-scale=1">
  ...
</head>
複製程式碼
  1. 壓縮圖片(僅針對JPEG) 將每個影象的壓縮級別設定為85或更低,像TinyJPG這樣的Web服務可以幫助自動化影象優化的過程

避免頁面存在不成功的HTTP狀態碼

搜尋引擎可能無法正確索引返回不成功的HTTP狀態碼的頁面。

允許使用者貼上到密碼欄位中

密碼貼上提高了安全性,因為它使使用者能夠使用密碼管理器。密碼管理員通常為使用者生成強密碼,安全地儲存密碼,然後在使用者需要登入時自動將其貼上到密碼欄位中。 刪除阻止使用者貼上到密碼欄位的程式碼。使用事件斷點中的Clipboard paste來打斷點,可以快速找到阻止貼上密碼的程式碼。比如下列這種阻止貼上密碼的程式碼:

let input = document.querySelector('input');
input.addEventListener('paste', (e) => {
  e.preventDefault(); // This is what prevents pasting.
});
複製程式碼

dom-breakpoint.png

避免DOM過大

大型的DOM樹會以多種方式降低頁面效能:

  • 網路效率和負載效能,如果你的伺服器傳送一個大的DOM樹,你可能會運送大量不必要的位元組。這也可能會減慢頁面載入時間,因為瀏覽器可能會解析許多沒有顯示在螢幕上的節點。
  • 執行時效能。當使用者和指令碼與頁面互動時,瀏覽器必須不斷重新計算節點的位置和樣式。一個大的DOM樹與複雜的樣式規則相結合可能會嚴重減慢渲染速度。 記憶體效能。如果使用通用查詢選擇器(例如,document.querySelectorAll('li') 您可能會無意中將引用儲存到大量的節點),這可能會壓倒使用者裝置的記憶體功能。

一個最佳的DOM樹:

  • 總共少於1500個節點。
  • 最大深度為32個節點。
  • 沒有超過60個子節點的父節點。
  • 一般來說,只需要在需要時尋找建立DOM節點的方法,並在不再需要時將其銷燬。

如果你不能避免一個大型的DOM樹,改善渲染效能的另一種方法是簡化你的CSS選擇器。請參閱減少風格計算的範圍和複雜性

使用被動事件監聽器以提升滾動效能

被動事件是新興的Web標準,可以顯著提高滾動效能,尤其在移動裝置上。當使用touch事件監聽器(scroll事件不存在這個問題)進行滾動時,因為瀏覽器不知道你是否會取消滾動,它們總是等待監聽器執行完畢後才開始滾動,這樣就造成了明顯的延遲。事件監聽器options中使用passive:true表明監聽器永遠不會取消滾動,這樣瀏覽器就可以立即滾動。 在支援被動事件偵聽器的瀏覽器中,將偵聽器標記為passive即可:

document.addEventListener('touchstart', onTouchStart, {passive: true});
複製程式碼

參考資料

  • https://developers.google.com/web/tools/lighthouse/
  • https://developers.google.com/web/fundamentals/performance/rail
  • https://developers.google.com/web/fundamentals/performance/rendering/
  • https://developers.google.com/web/fundamentals/performance/user-centric-performance-metrics

歡迎訪問我的部落格

相關文章