天天看點

現代浏覽器性能優化-CSS篇

我來填坑了,CSS篇終于寫出來了,如果你沒看過前面的JS篇,可以在這裡觀看。

衆所周知,CSS的加載會阻塞浏覽器渲染或是引起浏覽器重繪,目前業界普遍推薦把CSS放到

<head>

中,防止在CSS還沒加載完,DOM就已經繪制出來了,造成CSS加載完成後的重繪。那在現代浏覽器中我們有沒有辦法提高首屏渲染速度那?

你是不是經常在第一次打開某個網站的時候看到這種情況,本來的頁面是這樣的

現代浏覽器性能優化-CSS篇

實際上剛加載出來的是這樣的

現代浏覽器性能優化-CSS篇

字型檔案沒加載出來,或者加載的太慢了

了解CSS解析過程

以下面這段HTML為例,解釋一遍CSS加載解析的過程。

<html>
<head>
  <!-- headStyle.css中存在字型檔案webfont.woff2 -->
  <link rel="stylesheet" type="text/css" href="/headStyle.css" target="_blank" rel="external nofollow" >
</head>
<body>
  <p>Text</p>
  <link rel="stylesheet" type="text/css" href="/bodyEndStyle.css" target="_blank" rel="external nofollow" >
</body>
</html>
           

浏覽器自上而下讀取HTML文檔,當發現headStyle.css的時候,停止Parser HTML,開始下載下傳headStyle.css,解析headStyle.css的過程中發現字型檔案webfont.woff2,開始下載下傳webfont.woff2,并繼續解析css生成CSSStyleSheet。解析完畢後,繼續Parser HTML,當發現p标簽時,會将p标簽結合目前的CSSStyleSheet展示出來,此時使用者螢幕中已經有p标簽的内容了。當浏覽器發現bodyEndStyle.css時,就會下載下傳headStyle.css,解析CSS,然後更新CSSStyleSheet,這時會引起一次重繪。當字型下載下傳完畢的時候也會引起一次重繪。

這個過程中,有兩個非常嚴重的問題。一、如果headStyle.css檔案很大,浏覽器需要解析很多行CSS後才能還有個字型檔案需要下載下傳,其實此時已經很晚了,字型下載下傳時間稍長一點,就會出現我前面截圖提到的問題。二、bodyEndStyle.css中如果存在p标簽對應的樣式,那p标簽的樣式會在bodyEndStyle.css解析完成後,改變一次樣式,很影響體驗。

如何解決這些問題那?其中也會用到一些JS篇中提到的點,如果沒看過,建議先看看。

優化核心依舊是減少下載下傳時間

JS篇中的預先解析DNS(dns-prefetch)依舊适用,提前解析CSS檔案所在域名的DNS。

Preload

因為CSS已經在head中,我們不需要為css加preload屬性了,但是css中用到的字型檔案,一定要在所有css之前proload上。

<link rel="preload" href="/webfont.woff2" target="_blank" rel="external nofollow"  as="font">
           

首頁CSS内聯,非必要CSS異步加載

首頁用到的CSS内聯寫在

<head>

中,其餘CSS均采用異步加載,可以采用這種自己實作的加載CSS的方法,在合适的需要時加載需要的css

function LoadStyle(url) {
  try {
    document.createStyleSheet(url)
  } catch(e) {
    var cssLink = document.createElement('link');
    cssLink.rel = 'stylesheet';
    cssLink.type = 'text/css';
    cssLink.href = url;
    var head = document.getElementsByTagName('head')[0];
    head.appendChild(cssLink)
  }
}
           

如果你使用webpack,那就更輕松了,使用import函數,大緻如下

// 在a.js子產品中直接引入css
import 'style.css'
           
// 在需要a.js子產品的地方
improt('path-of-a.js').then(module => {})
           

webpack打包後,其實是把style.css打包進了a.js,在異步加載a.js的時候,會将style.css中的代碼插入

haed

标簽中。

終極完美結構

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>Faster</title>
  <link rel="dns-prefetch" href="//cdn.cn/" target="_blank" rel="external nofollow" >

  <link rel="preload" href="//cdn.cn/webfont.woff2" target="_blank" rel="external nofollow"  as="font">
  <link rel="preload" href="//cdn.cn/Page1-A.js" target="_blank" rel="external nofollow"  as="script">
  <link rel="preload" href="//cdn.cn/Page1-B.js" target="_blank" rel="external nofollow"  as="script">
  
  <link rel="prefetch" href="//cdn.cn/Page2.js" target="_blank" rel="external nofollow" >
  <link rel="prefetch" href="//cdn.cn/Page3.js" target="_blank" rel="external nofollow" >
  <link rel="prefetch" href="//cdn.cn/Page4.js" target="_blank" rel="external nofollow" >

  <style type="text/css">
    /* 首頁用到的CSS内聯 */
  </style>
</head>
<body>

<script type="text/javascript" src="//cdn.cn/Page1-A.js" defer></script>
<script type="text/javascript" src="//cdn.cn/Page1-B.js" defer></script>
</body>
</html>
           

在JS篇)中,我已經解釋過這套結構中JS的執行順序了,本篇隻是加入了CSS和字型。至此,我心中終極完美的頁面HTML結構就是這樣了。

如果你對異步加載CSS的方案感興趣,歡迎留言與我讨論!

擴充閱讀

  • 浏覽器的工作原理
  • 關于Preload, 你應該知道些什麼?
  • Preload,Prefetch 和它們在 Chrome 之中的優先級

繼續閱讀