CSS 非同步載入技術 不影響頁面渲染

edithfang發表於2015-04-12
警告! 我發這篇帖子全是好意,但是它並不負責讓讀它的人意識到下面將會遇到的問題. 社群很快地給了我許多的反饋 (有些反饋我很感激) ,而越來越明顯的是這項技術並不如我所希望的那樣穩定. 不像我那樣的成功地對它進行了測試和利用,許多開發者在 IE 和 Firefox 中都遇到了問題( F F測試版中直接崩潰) 而其他人則報告在 Chrome 和 Safari 中是成功的。我現在的建議是: 不要將其用於產品。我計劃處理好這些反饋,並結合任何有關的資訊對本文進行更新。

這些技術背後的原理不是新的。例如燈絲(Filament)技術組已經發布了大量有關 載入CSS 和字型的內容. 我寫就本文以記錄我對載入非阻塞資源的想法和觀點。

觸發非同步樣式下載的訣竅是使用一個 <link> 元素,並 為media 屬性設定一個不可用的值 (我用的是 media=”none”, 不過其它的任何值也是可以的)。當一個媒體查詢的結果值計算出來是 false 的時候,瀏覽器仍然會下載樣式表,但是不會在渲染頁面之前等待樣式表的資源可用。

<link rel="stylesheet" href="css.css" media="none">


樣式表一下載好,media 屬性就必須被設定一個可用的值,以便樣式規則能被應用到 html 文件中onload 事件就可以用來將 media 屬性切換到all:

<link rel="stylesheet" href="css.css" media="none" onload="if(media!='all')media='all'">


這種載入 CSS 的方法將比標準的方法在向訪問者傳送有用資訊的速度上快很多。至關重要的 CSS 載入時仍然可以用一般的阻塞方式處理 (或者你也可以為了最終的效能對它進行內聯處理) ,而不重要的樣式則可以慢慢下載,並在解析/渲染過程的後面一點的階段進行應用.

這一技術使用了 JavaScript,但是你也可以在一個<noscript>元素中封裝一個等價的阻塞方式的 <link> 元素來處理不能執行 JavaScript 的瀏覽器:

<link rel="stylesheet" href="css.css" media="none" onload="if(media!='all')media='all'">
<noscript><link rel="stylesheet" href="css.css"></noscript>


這項技術有一個副作用。當一個非阻塞的樣式表完成載入,文件就將進行重繪,以反映它定義的任何新的樣式規則。而注入新的樣式到頁面中會觸發內容迴流, 但這也只是在這對第一次沒有歷史快取的頁面載入過程中會是一個問題。由於任何跟效能有關的東西,你都將要在需要控制一次迴流耗費超過潛在的速度優勢時,進行必要的調整。

使用非阻塞 CSS 載入字型

字型第一次繪製的效能是一個問題,它們是阻塞式的資源,也會讓應用它們的文字在該字型下載時不可見 。使用上述示例中的非阻塞連結,就可能在幕後下載包含字型資料的樣式表,不阻塞壓面的渲染:

<link rel="stylesheet" href="main.css">
<link rel="stylesheet" href="font.css" media="none" onload="if(media!='all')media='all'">


font.css 包含一個 base64 編碼的 WOFF 版本的 Merriweather 字型。

@font-face {
  font-family: Merriweather;
  font-style: normal;
  font-weight: 400;
  src: local('Merriweather'), url('data:application/x-font-woff;charset=utf-8;base64,...')
}


main.css 包含了需要應用到站點的所有樣式規則。下面是字型的宣告:

body {
  font-family: Merriweather, "Lucida Grande", ...;
}


當字型正在下載時,第一個匹配到的備用回退字型 (這裡就是 Lucida Grande) 被用來渲染頁面的內容。 一旦字型樣式表被應用了,Merriweather 就會被使用. 我嘗試去確保回退的字型將相似的佈局特徵共享給優先選擇的字型,那樣不可避免的迴流就儘可能微妙了。

我在基於一個模擬的 3G 網路連線的 Chrome 中,使用我的 Google Analytics Debugger 站點 拿阻塞和非阻塞方式進行了對比測試。本地的測試產生了如下所示的網路圖;注意 DOMContentLoaded 在更早的 450ms 觸發了,而資源在運用了非阻塞技術後下載起來更快了:

載入 CSS 時不影響頁面渲染



模擬 3G 網路的圖形。頂部顯示了阻塞式的字型。底部顯示了非阻塞式的字型。

將其部署到一個測試伺服器並在 3G 連線環境下執行 webpagetest 構造產生了如下時間線 :

載入 CSS 時不影響頁面渲染



3G 時間線。頂部顯示阻塞式的字型,底部展示非阻塞式的字型。

兩種方法都花了2.8秒鐘來完整的渲染頁面,但是非阻塞方法比一般的阻塞方法使得繪製早了1秒鐘。在在主樣式表進行了內聯的情況下執行相同的測試,顯示了在將非阻塞 CSS 被應用於處理字型時有0.7秒的時間優勢:

載入 CSS 時不影響頁面渲染



主 CSS 內容的 3G 時間線。頂部顯示阻塞式字型,底部顯示非阻塞式字型。

這一技術對於字型的效果確實很好,但是我也建議對新的 CSS 字型載入模組保持密切關注,它會給與我們超過字型載入的更多的控制能力。

總結

載入字型是應用非阻塞技術的一個例子,而他也可以被用於其它的目的,比如從核心的 CSS 處分離出 JavaScript 增強的樣式。

我已經開始去嘗試將樣式分成框架(核心佈局) 和展現 (其它所有的東西)這種想法,它可以讓重要的頁面佈局阻塞頁面渲染,而可見的樣式資料延遲一會。
相關閱讀
評論(1)

相關文章