Kan-Ru Chen's Weblog

Simpler way to load CSS asynchronously

Smashing Newsletter 看到的,只要 <link> 標籤就可以簡單把 CSS 變成非同步讀取:

<link rel="stylesheet" href="/path/to/my.css"
      media="print" onload="this.media='all'">

有用過 Google PageSpeed Insight 分析網站的,應該都有看過如下的結果:

PageSpeed screenshot

原因是因為瀏覽器在處理 CSS 與 JavaScript 檔案的時候會阻擋其他資源的載入。解決的 方法裡,JavaScript 類型的資源可以標示 defer 或是 async 屬性讓瀏覽器知道我們 希望可以非同步的載入執行此 JavaScript 檔案,可惜 CSS 並沒有類似的屬性可以使用。

一般處理 CSS 的載入有兩個策略:

  1. 盡量把最重要的樣式內嵌(inline)在 HTML 內,
  2. 用 JavaScript 動態的插入 <link> 標籤。

策略 1. 應該不難理解,因為都已經要下載 HTML 了,不如把少部份最重要的樣式直接也寫 在裡面,可以省下一次網路請求。策略 2. 則是把其他剩餘的樣式集中在一起,用 JavaScript 在網頁讀取完畢後再動態的插入 <link> 標籤讓瀏覽器套用。LoadCSS 似乎是個常用的 library 但是我沒有用過,因為我不喜歡這種需要很多 JavaScript 的解 法。

這次看到的這個方法非常簡單,原本的 CSS 標籤如下:

<link rel="stylesheet" href="/path/to/my.css">

只要再加上 media="print" 以及 onload="this.media='all'" 就可以讓瀏覽器非同步載入 CSS 了!

原理是,瀏覽器在遇到非使用中的 media 時,只會下載但是不會套用樣式,所以設定 mediaprint 可以避免套用 CSS 的時候延遲其他的資源的載入,而 onload 的部 份則是在等到其他資源都載入完畢後,才把 media 切回 all 或是 screen 讓瀏覽器 套用樣式。雖然還是需要一點點 CSS,整體看起來清爽許多,也不需要額外的 library!

如果需要支援沒有開啟 JavaScript 的瀏覽器,記得加上 fallback:

<noscript><link rel="stylesheet" href="/path/to/my.css"></noscript>

完整的範例如下:

<link rel="stylesheet" href="/path/to/my.css"
      media="print" onload="this.media='all'">
<noscript><link rel="stylesheet" href="/path/to/my.css"></noscript>

我迫不及待的立刻試用了😊 ∎