异步加载CSS
说到加载 CSS 这种事儿不是很简单吗?像这样咯:
<link rel="stylesheet" href="cssfile.css">
这不就完事儿了嘛!
这样是没错!但是这样有问题啊——会阻塞渲染!浏览器看到这个标签就会停下手里的活儿,去加载 CSS 并解析了。
当然了,如果这个 CSS 文件是接下来要渲染的内容所需的,那无可厚非,必须先要有了这个 CSS 才能接着渲染,阻塞也是情理之中。
但实际的情况却是,我们很多 CSS 内容其实在首屏的时候是不需要,起码等到后续才会使用,那么这个时候这些 CSS 这样加载去阻塞内容渲染就不对了。
也就是说,针对优先级不那么高的(暂时用不到)CSS,就应该要想办法让它异步加载,不要阻塞浏览器渲染。
那么怎么弄呢?
老方子
现在介绍第一种老办法:通过 JS 动态插入 link 标签来异步载入 CSS 代码,就像这样:
var myCSS = document.createElement( "link" ); myCSS.rel = "stylesheet"; myCSS.href = "mystyles.css"; document.head.insertBefore( myCSS, document.head.childNodes[ document.head.childNodes.length - 1 ].nextSibling );
这个很好理解吧,就是后续 JS 执行的时候,去创建一个 link 标签来加载 CSS 代码。
还有一个办法呢就是利用 link 上的 media
属性,将它设置为和用户当前浏览器环境不匹配的值,比如:media="print"
,甚至可以设置为一个完全无效的值 media="jscourse"
之类的。
这样一来,浏览器就会认为这个 CSS 文件优先级非常低,就会在不阻塞的情况下进行加载。但是为了让 CSS 规则生效,最后还是要将 media 值改对才行。所以,这个办法落实到代码就是这样:
<link rel="stylesheet" href="cssfile.css" media="jscourse" onload="this.media='all'">
介绍完了老方子,我们再来看看新药方。
新的异步加载方式
新方子就是利用规范中新增加的 rel="preload"
,就像这样:
<link rel="preload" href="cssfile.css" as="style" onload="this.rel='stylesheet'">
通过 preload
属性值就是告诉浏览器这个资源文件随后会用到,请提前加载好。但是这只是加载,所以你看当它加载完毕后,还是需要将 rel 值改回去,这才能让 CSS 生效。
你是不是想问:这和老方子也没多大区别嘛!
看上去确实如此,但是呢,语义上更加好一些。另外就是你仔细点就会发现 as="style"
这个属性,所以 preload 不仅仅可以用在 CSS 文件上,而是可以用在绝大多数的资源文件上。比如:JS 文件
<link rel="preload" href="scriptfile.js" as="script">
然后要用的时候,就创建一个 script 标签指向它:
var script = document.createElement("script");
script.src = "scriptfile.js";
document.body.appendChild(script);
这个时候浏览器就直接从缓存中拿这个文件了,不会再发请求了,因为此前已经加载好了。
那么 preload 中的 as 属性支持哪些资源文件呢?下面这些都可以:
- audio
- document
- embed
- fetch
- font
- image
- object
- script
- style
- track
- worker
- video
是不是迫不及待想去试试了?告诉你个坏消息,目前 preload 只有 Chrome 是完美支持的,其他浏览器惨不忍睹,哎!