你知道怎么優(yōu)化阻塞了頁面渲染的 CSS嗎?
前言
默認情況下,CSS 被視為阻塞渲染的資源,這意味著瀏覽器將不會渲染任何已處理的內(nèi)容,直至 CSSOM 構(gòu)建完畢。請務(wù)必精簡您的 CSS,盡快提供它,并利用媒體類型和查詢來解除對渲染的阻塞。
背景
在渲染樹構(gòu)建中,我們看到關(guān)鍵渲染路徑要求我們同時具有 DOM 和 CSSOM 才能構(gòu)建渲染樹。這會給性能造成嚴重影響: HTML 和 CSS 都是阻塞渲染的資源。HTML 顯然是必需的,因為如果沒有 DOM,我們就沒有可渲染的內(nèi)容,但 CSS 的必要性可能就不太明顯。如果我們在 CSS 不阻塞渲染的情況下嘗試渲染一個普通網(wǎng)頁會怎樣?
TL;DR
默認情況下,CSS 被視為阻塞渲染的資源。 我們可以通過媒體類型和媒體查詢將一些 CSS 資源標記為不阻塞渲染。 瀏覽器會下載所有 CSS 資源,無論阻塞還是不阻塞。
使用 CSS 的紐約時報

不使用 CSS 的紐約時報

上例展示了紐約時報網(wǎng)站使用和不使用 CSS 的顯示效果,它證明了為何要在 CSS 準備就緒之前阻塞渲染,---沒有 CSS 的網(wǎng)頁實際上無法使用。右側(cè)的情況通常稱為“內(nèi)容樣式短暫失效”。瀏覽器將阻塞渲染,直至 DOM 和 CSSOM 全都準備就緒。
CSS 是阻塞渲染的資源。需要將它盡早、盡快地下載到客戶端,以便縮短首次渲染的時間。
不過,如果我們有一些 CSS 樣式只在特定條件下(例如顯示網(wǎng)頁或?qū)⒕W(wǎng)頁投影到大型顯示器上時)使用,又該如何?如果這些資源不阻塞渲染,該有多好。
我們可以通過 CSS“媒體類型”和“媒體查詢”來解決這類用例:
<link href="style.css" rel="stylesheet">
<link href="print.css" rel="stylesheet" media="print">
<link href="other.css" rel="stylesheet" media="(min-width: 40em)">
媒體查詢由媒體類型以及零個或多個檢查特定媒體特征狀況的表達式組成。例如,上面的第一個樣式表聲明未提供任何媒體類型或查詢,因此它適用于所有情況,也就是說,它始終會阻塞渲染。第二個樣式表則不然,它只在打印內(nèi)容時適用---或許您想重新安排布局、更改字體等等,因此在網(wǎng)頁首次加載時,該樣式表不需要阻塞渲染。
最后,最后一個樣式表聲明提供由瀏覽器執(zhí)行的“媒體查詢”: 符合條件時,瀏覽器將阻塞渲染,直至樣式表下載并處理完畢。
通過使用媒體查詢,我們可以根據(jù)特定用例(比如顯示或打?。?,也可以根據(jù)動態(tài)情況(比如屏幕方向變化、尺寸調(diào)整事件等)定制外觀。聲明您的樣式表資產(chǎn)時,請密切注意媒體類型和查詢,因為它們將嚴重影響關(guān)鍵渲染路徑的性能。
讓我們考慮下面這些實例:
<link href="style.css" rel="stylesheet">
<link href="style.css" rel="stylesheet" media="all">
<link href="portrait.css" rel="stylesheet" media="orientation:portrait">
<link href="print.css" rel="stylesheet" media="print">
第一個聲明阻塞渲染,適用于所有情況。 第二個聲明同樣阻塞渲染: “all”是默認類型,如果您不指定任何類型,則隱式設(shè)置為“all”。因此,第一個聲明和第二個聲明實際上是等效的。 第三個聲明具有動態(tài)媒體查詢,將在網(wǎng)頁加載時計算。根據(jù)網(wǎng)頁加載時設(shè)備的方向,portrait.css 可能阻塞渲染,也可能不阻塞渲染。 最后一個聲明只在打印網(wǎng)頁時應用,因此網(wǎng)頁首次在瀏覽器中加載時,它不會阻塞渲染。
建議
如果外部 CSS 資源較小,您可將它們直接插入到 HTML 文檔中,這稱為“內(nèi)嵌”。以這種方式內(nèi)嵌較小的 CSS 文件可讓瀏覽器順暢無阻地呈現(xiàn)網(wǎng)頁。如果 CSS 文件較大,您便需要確定和內(nèi)嵌用于呈現(xiàn)首屏內(nèi)容的 CSS,并暫緩加載其余樣式,直到首屏內(nèi)容顯示出來為止。如果 HTML 文檔如下所示:
<html>
<head>
<link rel="stylesheet" href="small.css">
</head>
<body>
<div class="blue">
Hello, world!
</div>
</body>
</html>
并且 small.css 資源如下所示:
.yellow {background-color: yellow;}
.blue {color: blue;}
.big { font-size: 8em; }
.bold { font-weight: bold; }
您就可以按照如下方式內(nèi)嵌關(guān)鍵的 CSS:
<html>
<head>
<style>
.blue{color:blue;}
</style>
</head>
<body>
<div class="blue">
Hello, world!
</div>
<noscript id="deferred-styles">
<link rel="stylesheet" type="text/css" href="small.css"/>
</noscript>
<script>
var loadDeferredStyles = function() {
var addStylesNode = document.getElementById("deferred-styles");
var replacement = document.createElement("div");
replacement.innerHTML = addStylesNode.textContent;
document.body.appendChild(replacement)
addStylesNode.parentElement.removeChild(addStylesNode);
};
var raf = window.requestAnimationFrame || window.mozRequestAnimationFrame ||
window.webkitRequestAnimationFrame || window.msRequestAnimationFrame;
if (raf) raf(function() { window.setTimeout(loadDeferredStyles, 0); });
else window.addEventListener('load', loadDeferredStyles);
</script>
</body>
</html>
最后
最后,請注意“阻塞渲染”僅是指瀏覽器是否需要暫停網(wǎng)頁的首次渲染,直至該資源準備就緒。
無論哪一種情況,瀏覽器仍會下載 CSS 資產(chǎn),只不過不阻塞渲染的資源優(yōu)先級較低罷了。
