我来填坑了,CSS 篇终于写出来了,如果你没看过前面的 JS 篇,可以 在这里观看 。
众所周知,CSS 的加载会阻塞浏览器渲染或是引起浏览器重绘,目前业界普遍推荐把 CSS 放到 <head> 中,防止在 CSS 还没加载完,DOM 就已经绘制出来了,造成 CSS 加载完成后的重绘。那在现代浏览器中我们有没有办法提高首屏渲染速度那?
你是不是经常在第一次打开某个网站的时候看到这种情况,本来的页面是这样的
实际上刚加载出来的是这样的
字体文件没加载出来,或者加载的太慢了
以下面这段 html 为例,解释一遍 CSS 加载解析的过程。
- <html>
- <head>
- <!-- headStyle.css中存在字体文件webfont.woff2 -->
- <link rel="stylesheet" type="text/css" href="/headStyle.css">
- </head>
- <body>
- <p>Text</p>
- <link rel="stylesheet" type="text/css" href="/bodyEndStyle.css">
- </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。
因为 CSS 已经在 head 中,我们不需要为 css 加 preload 属性了,但是 css 中用到的字体文件,一定要在所有 css 之前 proload 上。
- <link rel="preload" href="/webfont.woff2" as="font">
首页用到的 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/">
- <link rel="preload" href="//cdn.cn/webfont.woff2" as="font">
- <link rel="preload" href="//cdn.cn/Page1-A.js" as="script">
- <link rel="preload" href="//cdn.cn/Page1-B.js" as="script">
- <link rel="prefetch" href="//cdn.cn/Page2.js">
- <link rel="prefetch" href="//cdn.cn/Page3.js">
- <link rel="prefetch" href="//cdn.cn/Page4.js">
- <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 的方案感兴趣,欢迎留言与我讨论!
来源: https://segmentfault.com/a/1190000012643583