關(guān)鍵CSS和Webpack: 減少阻塞渲染的CSS的自動化解決方案

原文地址: Critical CSS and Webpack: Automatically Minimize Render-Blocking CSS

原文作者: Anthony Gore

譯者: 蝸牛(GivenCui)

校對者: veizz

"消除阻塞渲染的CSS和JavaScript"。 這一條Google Page Speed Insights的建議總讓我困惑。

當(dāng)一個網(wǎng)頁被訪問時,Google希望它僅加載對初始視圖有用的內(nèi)容,并使用空閑時間來加載其他內(nèi)容。這種方式可以使用戶盡可能早地看到頁面。

我們可以做很多事情來減少阻塞渲染的JavaScript,例如code splitting、tree shaking,緩存等。

但是如何減少阻塞渲染的CSS?為此,可以拆分并優(yōu)先加載首次渲染所需要的CSS(關(guān)鍵CSS),然后再加載其它CSS。

可以通過編程的方式篩選出關(guān)鍵CSS,在本文中,我將向你展示如何通過Webpack的自動化流程來實現(xiàn)該方案。

什么是阻塞渲染

如果資源是“阻塞渲染”的,則表示瀏覽器在資源下載或處理完成之前不會顯示該頁面。

通常,我們在 html 的 head 標簽中添加 CSS 樣式表,這種方式會阻塞渲染,如下所示:

當(dāng)這個 html 頁面被網(wǎng)絡(luò)瀏覽器加載時,它將從上到下被逐行解析。當(dāng)瀏覽器解析到 link 標簽時,它將立即開始下載 CSS 樣式表,在完成之前不會渲染頁面。

對于一個大型網(wǎng)站,尤其是像使用了 Bootstrap 這種龐大框架的網(wǎng)站,樣式表有幾百 KB,用戶必須耐心等待其完全下載完才能看到頁面。

那么,我們是否應(yīng)該把link標簽放到 body 中,以防止阻塞渲染?你可以這么做,但是阻塞渲染也不是全無優(yōu)點,我們實際上可以利用它。如果頁面渲染時沒有加載任何 CSS,我們會遇到丑陋的"內(nèi)容閃現(xiàn)"。

我們想要的完美解決方案就應(yīng)該是:首屏相關(guān)的關(guān)鍵 CSS 使用阻塞渲染的方式加載,所有的非關(guān)鍵 CSS 在首屏渲染完成后加載。

關(guān)鍵CSS

這里是我用 Webpack 和 Bootstrap 編寫的一個簡單的網(wǎng)頁, 下面的截圖是首次渲染后的樣式。

點擊 Sign Up today 按鈕會彈出一個模態(tài)框, 模態(tài)框彈出時的樣式如下:

首次渲染需要的樣式包括導(dǎo)航條的樣式、超大屏幕樣式、按鈕樣式、其它布局和字體的公用樣式。但是我們并不需要模態(tài)框的樣式,因為它不會立即在頁面中顯示??紤]到這些,下面是我們拆分關(guān)鍵 CSS 和非關(guān)鍵 CSS 的可能的方式:

critical.css

non_critical.css

如果你已經(jīng)有這個概念,那么你可能會提出兩個疑問:

我們?nèi)绾斡贸绦騾^(qū)分關(guān)鍵CSS和非關(guān)鍵CSS?

如何讓頁面在首次渲染之前加載關(guān)鍵CSS,之后加載非關(guān)鍵CSS?

示例項目

我將簡要介紹一下這個項目的基本配置,這樣我們在遇到解決方案時,方便快速消化。

首先, 在入口文件中引入Bootsrap SASS。

main.js

我使用 sass-loader 來處理 sass,與 Extract Text Plugin 一起使用,將編譯出來的 css 放到單獨的文件中。

使用 HTML Webpack Plugin 來創(chuàng)建一個 HTML 文件,它引入編譯后的 CSS。這在我們的解決方案中是必需的,你馬上就會看到。

webpack.config.js

運行構(gòu)建之后,這里是HTML文件的樣子。請注意,CSS文件在head標簽里引入,因此將會阻塞渲染。

index.html

編程識別關(guān)鍵 CSS

手動區(qū)分關(guān)鍵 CSS 維護起來會非常痛苦。以編程方式來實現(xiàn)的話,我們可以使用 Addy Osmani 的 Critical。這是一個 Node.js 模塊,它將讀入 HTML 文檔,并識別關(guān)鍵 CSS。Critical 能做的還不止這些,你很快就能體會到。

Critical 識別關(guān)鍵 CSS 的方式如下:指定屏幕尺寸并使用 PhantomJS 加載頁面,提取在渲染頁面中用到的所有 CSS 規(guī)則。

以下為對項目的設(shè)置:

執(zhí)行時,會將Webpack打包輸出文件中HTML更新為:

它還將輸出一個新的 CSS 文件,例如 style.96106fab.css (文件自動 Hash 命名)。這個 CSS 文件與原始樣式表相同,只是不包含關(guān)鍵 CSS。

內(nèi)聯(lián)嵌入關(guān)鍵CSS樣式

你會注意到,關(guān)鍵CSS已經(jīng)嵌入到文檔的頭部。這是最佳的,因為頁面不必從服務(wù)器加載它。

預(yù)加載非關(guān)鍵CSS

你還會注意到,非關(guān)鍵 CSS 使用了一個看起來更復(fù)雜的 link 標簽來加載。rel="preload" 通知瀏覽器開始獲取非關(guān)鍵 CSS 以供之后用。其關(guān)鍵在于,preload 不阻塞渲染,無論資源是否加載完成,瀏覽器都會接著繪制頁面。

link 標簽中的 onload 屬性允許我們在非關(guān)鍵 CSS 加載完成時運行腳本。Critical 模塊可以自動將此腳本嵌入到文檔中,這種方式提供了將非關(guān)鍵 CSS 加載到頁面中的跨瀏覽器兼容方法。

把 Critical 組件添加到 webpack 打包流程中

我創(chuàng)建了一個名為 HTML Critical Webpack Plugin 的插件,該插件僅僅是 Critical 模塊的封裝。它將在 HTML Webpack Plugin 輸出文件后運行。

你可以在 Webpack 的項目中這樣引入:

注意:你應(yīng)該只在生產(chǎn)版本中使用,因為它將使你的開發(fā)環(huán)境的構(gòu)建很慢

表現(xiàn)結(jié)果

現(xiàn)在已經(jīng)抽離了關(guān)鍵 CSS,并且把非關(guān)鍵 CSS 的加載放到空閑時間,這在性能方面會有怎樣的提升呢?

我使用 Chrome 的 Lighthouse 擴展插件進行測試。請記住,我們嘗試優(yōu)化的指標是“首次有效繪制”,也就是用戶需要多久才能看到真正可瀏覽的頁面。

不使用區(qū)分關(guān)鍵CSS技術(shù)的表現(xiàn)

使用區(qū)分關(guān)鍵CSS技術(shù)的表現(xiàn)

正如你所看到的,我的應(yīng)用程序 First Meaningful paint 時間縮短了將近 1 秒,到達可交互狀態(tài)的時間節(jié)省了 0.5 秒。實際中,你的應(yīng)用程序可能無法獲得如此驚人的改善,因為我的 CSS 很笨重(我包含了整個 Bootstrap 庫),而且在這樣一個簡單的應(yīng)用程序中,我沒有很多關(guān)鍵CSS規(guī)則。

文章轉(zhuǎn)自:Github

文章地址:翻譯 | 關(guān)鍵CSS和Webpack: 減少阻塞渲染的CSS的自動化解決方案

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容