CSS 加載新方式

Chrome 瀏覽器有意改變<link rel="stylesheet">的加載方式,當(dāng)其出現(xiàn)在<body>中時(shí),這一變化將更加明顯。筆者決定在本文中進(jìn)行詳細(xì)說明這種改變可能帶來影響與好處梆掸。

一.目前CSS文件的加載方式
<head>
  <link rel="stylesheet" href="/all-of-my-styles.css">
</head>
<body>
  …content…
</body>

CSS 會(huì)阻礙渲染,因此在all-of-my-styles.css全部加載完之前酿愧,用戶就只能面對一片空白的屏幕沥潭。

通常,我們將某個(gè)站點(diǎn)的所有 CSS 樣式合并為一到兩個(gè)資源嬉挡,這意味著用戶會(huì)下載一堆當(dāng)前頁面根本就用不上的規(guī)則钝鸽。這是因?yàn)榫W(wǎng)站可能包含許多不同類型的頁面,每個(gè)頁面都有自己的「組件」庞钢;而在組件級別傳遞 CSS 的話拔恰,會(huì)降低 HTTP/1 的性能。

然而基括,對 SPDY 和 HTTP/2 來說颜懊,事實(shí)卻并非如此。在這些協(xié)議中,許多小資源只需要很小的代價(jià)就能完成遞送河爹,并且被獨(dú)立緩存匠璧。

<head>
  <link rel="stylesheet" href="/site-header.css">
  <link rel="stylesheet" href="/article.css">
  <link rel="stylesheet" href="/comment.css">
  <link rel="stylesheet" href="/about-me.css">
  <link rel="stylesheet" href="/site-footer.css">
</head>
<body>
  …content…
</body>

這樣一來就解決了冗余問題,但也意味著你需要知道輸出<head>時(shí)頁面將包含的內(nèi)容咸这,從而防止 streaming夷恍。與此同時(shí),瀏覽器還是只能等待所有 CSS 樣式加載完畢媳维,才能開始渲染酿雪。如果加載 /site-footer.css的速度不夠快,就會(huì)耽誤所有頁面的渲染侄刽。

二.目前最先進(jìn)的 CSS 加載方法
<head>
  <script>
    // https://github.com/filamentgroup/loadCSS
    !function(e){"use strict"
    var n=function(n,t,o){function i(e){return f.body?e():void setTimeout(function(){i(e)})}var d,r,a,l,f=e.document,s=f.createElement("link"),u=o||"all"
    return t?d=t:(r=(f.body||f.getElementsByTagName("head")[0]).childNodes,d=r[r.length-1]),a=f.styleSheets,s.rel="stylesheet",s.href=n,s.media="only x",i(function(){d.parentNode.insertBefore(s,t?d:d.nextSibling)}),l=function(e){for(var n=s.href,t=a.length;t--;)if(a[t].href===n)return e()
    setTimeout(function(){l(e)})},s.addEventListener&&s.addEventListener("load",function(){this.media=u}),s.onloadcssdefined=l,l(function(){s.media!==u&&(s.media=u)}),s}
    "undefined"!=typeof exports?exports.loadCSS=n:e.loadCSS=n}("undefined"!=typeof global?global:this)
  </script>
  <style>
    /* The styles for the site header, plus: */
    .main-article,
    .comments,
    .about-me,
    footer {
      display: none;
    }
  </style>
  <script>
    loadCSS("/the-rest-of-the-styles.css");
  </script>
</head>
<body>
</body>

在上面的代碼中指黎,通過一些內(nèi)聯(lián)樣式我們可以加速初始渲染,同時(shí)隱藏起還沒有加載完樣式的組件州丹,并通過 JavaScript 異步地完成加載醋安。剩余的 CSS 加載完后會(huì)重寫.main-article中的display:none

這個(gè)方法受到性能專家的推崇,他們認(rèn)為這是快速完成初始渲染的好方法墓毒,并且經(jīng)過實(shí)地測量確實(shí)在加載的時(shí)候快了不少茬故。

但也存在一些不足之處。蚁鳖。。赁炎。醉箕。。

「1.它需要一個(gè)(小的)JavaScript 庫」

這是由 WebKit 的實(shí)現(xiàn)方式造成的徙垫。一旦頁面中添加了<link rel="stylesheet">讥裤,即使樣式表是由 JavaScript 加載的,WebKit 還是會(huì)在加載完成之前阻礙渲染姻报。

在 Firefox 和 IE/Edge 瀏覽器中己英,通過 JS 加載樣式表是完全異步進(jìn)行的。穩(wěn)定版本的 Chrome 瀏覽器是通過 WebKit 的方式加載的吴旋,但在 Canary 版本中损肛,仍然是使用 Firefox/Edge 加載方式。

「2.必須經(jīng)歷兩個(gè)加載階段」

在上述模式中荣瑟,內(nèi)聯(lián)的 CSS 通過display:none隱藏了沒有加載完樣式的內(nèi)容治拿,直到異步加載完剩余的 CSS 樣式。如果你將這些樣式分派到兩個(gè)或多個(gè) CSS 文件中笆焰,這些文件有可能不按照順序加載劫谅,導(dǎo)致加載過程中出現(xiàn)內(nèi)容錯(cuò)亂:

內(nèi)容錯(cuò)亂,就好比彈出廣告一樣,會(huì)導(dǎo)致用戶體驗(yàn)挫敗捏检,必須全力消滅荞驴。

既然有兩個(gè)加載階段,你就必須決定渲染的先后順序贯城。你當(dāng)然會(huì)想首先渲染「位置顯要」的內(nèi)容熊楼。但是,所謂的「位置」是根據(jù)窗口大小來決定的冤狡。因此孙蒙,問題來了,你得找出一把「萬能」鑰匙悲雳。

三.一個(gè)更簡單挎峦、更好的方法
<head>
</head>
<body>
  <!-- HTTP/2 push this resource, or inline it, whichever's faster -->
  <link rel="stylesheet" href="/site-header.css">
  <header>…</header>

  <link rel="stylesheet" href="/article.css">
  <main>…</main>

  <link rel="stylesheet" href="/comment.css">
  <section class="comments">…</section>

  <link rel="stylesheet" href="/about-me.css">
  <section class="about-me">…</section>

  <link rel="stylesheet" href="/site-footer.css">
  <footer>…</footer>
</body>

計(jì)劃是這樣的:針對每個(gè)<link rel="stylesheet">,加載樣式表時(shí)我們阻止渲染它的后續(xù)內(nèi)容合瓢,但是允許渲染它之前的內(nèi)容坦胶。樣式表是并行加載的,但是按照一定的順序顯示晴楔。這使得<link rel="stylesheet">的效用與<script src="…"></script>相近顿苇。

假設(shè)網(wǎng)站 header、正文和 footer 的 CSS 已經(jīng)加載完畢税弃,但其余內(nèi)容仍在等待纪岁,那么頁面會(huì)是這樣的:

  • Header:已渲染
  • 正文:已渲染
  • 評論部分:未渲染,它前面的 CSS 還未被加載(/comment.css)则果。
  • 關(guān)于本站:未渲染幔翰。它前面的 CSS 還未被加載(/comment.css)。
  • Footer:未渲染西壮。盡管它本身的 CSS 已加載完成遗增,但它前面的 CSS 還未被加載(/comment.css)。

這是一個(gè)按順序渲染的頁面款青。你不需要決定哪部分內(nèi)容在「顯要位置」做修,只要在頁面組件第一次實(shí)例化之前引入該組件的 CSS 即可。它完全兼容 Streaming抡草,因?yàn)槌悄阈枰渭埃駝t不必要輸出<link>

當(dāng)使用內(nèi)容決定布局的布局系統(tǒng)時(shí)(例如表格和 flexbox)康震,要注意避免加載時(shí)出現(xiàn)內(nèi)容錯(cuò)位旋炒。這不是什么新問題了,但是分步渲染會(huì)使得它出現(xiàn)得更為頻繁签杈。你可以通過 hack flexbox 來解決瘫镇,但對整體頁面布局來說鼎兽,使用 CSS grid 工具效果更佳(不過對小一些的組件來說,flexbox 還是很棒的)铣除。

四.Chrome瀏覽器的改變

HTML 規(guī)范并沒有規(guī)定 CSS 應(yīng)當(dāng)怎樣阻止頁面渲染谚咬,它不鼓勵(lì)在 body 中使用<link rel="stylesheet">,但是所有的瀏覽器都允許使用尚粘。當(dāng)然了择卦,瀏覽器們在處理 body 中的 link 時(shí)都有自己的方法:

  • Chrome和Safari:一旦發(fā)現(xiàn) <link rel="stylesheet"> 就停止渲染,并且在已發(fā)現(xiàn)的樣式表全部完成加載之前不會(huì)開始渲染郎嫁。這會(huì)導(dǎo)致<link> 前未被渲染的內(nèi)容也被阻塞秉继。

  • Firefox: head中的<link rel="stylesheet">會(huì)阻塞渲染,直至所有已發(fā)現(xiàn)的樣式表加載完畢泽铛,body中的<link rel="stylesheet">并不阻塞任何渲染尚辑,除非某個(gè) head 中的樣式表已經(jīng)阻塞了渲染,這會(huì)導(dǎo)致無樣式的內(nèi)容出現(xiàn)閃爍(FOUC)盔腔。

  • IE/Edge: 阻塞解析器直到樣式表加載完畢杠茬,但是允許渲染<link>之前的內(nèi)容。

在 Chrome 團(tuán)隊(duì)弛随,我們喜歡 IE/Edge 的方式瓢喉,所以打算跟它看齊。這就允許上文描述的漸進(jìn)式 CSS 渲染方式舀透。我們正在努力把它變成標(biāo)準(zhǔn)栓票,從允許<body>中的<link>開始。

目前 Chrome/Safari 采用的方式是向下兼容的愕够,帶來的問題是阻塞渲染的時(shí)間比實(shí)際需要的長逗载。Firefox 的方式稍微復(fù)雜一些某弦,但有個(gè)解決的方法:

「Firefixing!」

因?yàn)?Firefox 并不總是為了<body>中的<link>阻塞渲染努隙,我們得為這個(gè)多花點(diǎn)功夫來避免 FOUC蠢笋。謝天謝地這很容易,因?yàn)?code><script>會(huì)阻塞解析端盆,同時(shí)也會(huì)等掛起的樣式表完成加載:

<link rel="stylesheet" href="/article.css"><script> </script>
<main>…</main>

此處的<script>元素必須是非空的,但加個(gè)空格足矣。

Firefox 和 Edge/IE 可以實(shí)現(xiàn)很美好的漸進(jìn)式渲染漩勤,而 Chrome 和 Safari 在所有 CSS 加載完畢之前只能給你看一張白屏。目前 Chrome/Safari 采用的方式怎么都比將所有的樣式表都放<head>里要強(qiáng)缩搅,所以你現(xiàn)在就可以開始采用這個(gè)方法了越败。后面幾個(gè)月,Chrome 會(huì)遷移到 Edge 的模式硼瓣,這樣用戶就能體驗(yàn)更快的渲染速度了究飞。

就是這樣置谦!通過更簡單的方法加載你需要的 CSS,強(qiáng)力提升渲染速度亿傅。

五.快速定位 CSS 加載問題

那么問題來了媒峡,怎么樣才能知道是不是 css 加載影響了頁面的性能呢?只有定位到問題確實(shí)是 css 葵擎,老板才會(huì)給你時(shí)間和人力來優(yōu)化這方面的問題對不對谅阿?

網(wǎng)站性能優(yōu)化— WebP 全方位介紹

筆者之前做過前端優(yōu)化的工作,國內(nèi)外的前端性能優(yōu)化工具也使用了不少酬滤,現(xiàn)階段可以較好實(shí)現(xiàn)這個(gè)定位頁面慢加載因素的工具有:
OneAPM Browser Insight签餐、AppDynamicsRuxit盯串,大家有興趣的話可以去嘗試下氯檐。

注:本文原文作者為 Jake Archibald,由 OneAPM 運(yùn)營人員翻譯整理

原文地址:https://jakearchibald.com/2016/link-in-body/

Browser Insight 是一個(gè)基于真實(shí)用戶的 Web 前端性能監(jiān)控平臺(tái)嘴脾,能夠幫大家定位網(wǎng)站性能瓶頸男摧,網(wǎng)站加速效果可視化;支持瀏覽器译打、微信耗拓、App 瀏覽 HTML 和 HTML5 頁面。想閱讀更多技術(shù)文章奏司,請?jiān)L問 OneAPM 官方技術(shù)博客乔询。
本文轉(zhuǎn)自 OneAPM 官方博客

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市韵洋,隨后出現(xiàn)的幾起案子竿刁,更是在濱河造成了極大的恐慌,老刑警劉巖搪缨,帶你破解...
    沈念sama閱讀 222,252評論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件食拜,死亡現(xiàn)場離奇詭異,居然都是意外死亡副编,警方通過查閱死者的電腦和手機(jī)负甸,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,886評論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來痹届,“玉大人呻待,你說我怎么就攤上這事《痈” “怎么了蚕捉?”我有些...
    開封第一講書人閱讀 168,814評論 0 361
  • 文/不壞的土叔 我叫張陵,是天一觀的道長柴淘。 經(jīng)常有香客問我迫淹,道長秘通,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,869評論 1 299
  • 正文 為了忘掉前任千绪,我火速辦了婚禮充易,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘荸型。我一直安慰自己盹靴,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,888評論 6 398
  • 文/花漫 我一把揭開白布瑞妇。 她就那樣靜靜地躺著稿静,像睡著了一般。 火紅的嫁衣襯著肌膚如雪辕狰。 梳的紋絲不亂的頭發(fā)上改备,一...
    開封第一講書人閱讀 52,475評論 1 312
  • 那天,我揣著相機(jī)與錄音蔓倍,去河邊找鬼悬钳。 笑死,一個(gè)胖子當(dāng)著我的面吹牛偶翅,可吹牛的內(nèi)容都是我干的默勾。 我是一名探鬼主播,決...
    沈念sama閱讀 41,010評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼聚谁,長吁一口氣:“原來是場噩夢啊……” “哼母剥!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起形导,我...
    開封第一講書人閱讀 39,924評論 0 277
  • 序言:老撾萬榮一對情侶失蹤环疼,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后朵耕,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體炫隶,經(jīng)...
    沈念sama閱讀 46,469評論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,552評論 3 342
  • 正文 我和宋清朗相戀三年阎曹,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了伪阶。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,680評論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡芬膝,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出形娇,到底是詐尸還是另有隱情锰霜,我是刑警寧澤,帶...
    沈念sama閱讀 36,362評論 5 351
  • 正文 年R本政府宣布桐早,位于F島的核電站癣缅,受9級特大地震影響厨剪,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜友存,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,037評論 3 335
  • 文/蒙蒙 一祷膳、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧屡立,春花似錦直晨、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,519評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至焚刺,卻和暖如春敛摘,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背乳愉。 一陣腳步聲響...
    開封第一講書人閱讀 33,621評論 1 274
  • 我被黑心中介騙來泰國打工兄淫, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人蔓姚。 一個(gè)月前我還...
    沈念sama閱讀 49,099評論 3 378
  • 正文 我出身青樓捕虽,卻偏偏與公主長得像,于是被迫代替她去往敵國和親赂乐。 傳聞我的和親對象是個(gè)殘疾皇子薯鳍,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,691評論 2 361

推薦閱讀更多精彩內(nèi)容

  • 問答題47 /72 常見瀏覽器兼容性問題與解決方案? 參考答案 (1)瀏覽器兼容問題一:不同瀏覽器的標(biāo)簽?zāi)J(rèn)的外補(bǔ)...
    _Yfling閱讀 13,760評論 1 92
  • 轉(zhuǎn)載說明 一挨措、介紹 瀏覽器可以被認(rèn)為是使用最廣泛的軟件挖滤,本文將介紹瀏覽器的工作原理,我們將看到浅役,從你在地址欄輸入g...
    17碎那年閱讀 2,457評論 0 22
  • 1. 介紹 瀏覽器可能是最廣泛使用的軟件斩松。本書將介紹瀏覽器的工作原理。我們將看到觉既,當(dāng)你在地址欄中輸入google....
    康斌閱讀 2,023評論 7 18
  • 簡介瀏覽器可以被認(rèn)為是使用最廣泛的軟件瞪讼,本文將介紹瀏覽器的工 作原理钧椰,我們將看到,從你在地址欄輸入google.c...
    聽風(fēng)閣閱讀 3,293評論 0 7
  • 管理層面——分配機(jī)制 股權(quán)激勵(lì)的本質(zhì)是激勵(lì)符欠,激勵(lì)的標(biāo)的是股權(quán)嫡霞,是一種相對長期價(jià)值的分配行為。既然是分配希柿,首要考慮的...
    tsglxy閱讀 186評論 0 0