动态插入外部样式表
相比于动态插入外部脚本,
动态插入外部样式表(<link rel="stylesheet">
)的行为简单很多:
只要插入到当前 DOM 树时,浏览器总会异步地立即下载并应用该样式表,
被从 DOM 树移除时样式消失并立即触发重绘。
内联样式表(这里指
<style>
标签)除了不需要去下载之外,其他行为与外部样式表相同。 因此下文略过对内联样式表的讨论。
插入方式
鉴于浏览器的样式处理模型,即使是以innerHTML
的方式插入的 <link>
也会被解析为 外部样式表资源 并立即开始下载。
所以下面两种插入方式效果上等价:
方式一
document.body.innerHTML = '<link rel="stylesheet" href="foo.css">';
方式二
var link = document.createElement('link');
link.rel = 'stylesheet';
link.href = "foo.css";
document.body.appendChild(link);
上述情形对
<script>
却会不一样,<script>
会被解析但不会执行。 详细的讨论见在DOM中动态插入脚本。
触发下载
可能你不会注意到外部样式表的下载是有条件的,浏览器以此来避免下载不必要的样式文件。
最为重要的一个条件是<link>
必须与当前浏览上下文相连接,
也就是说新创建的 <link>
标签必须在插入到当前 DOM 树之后才会触发下载,
或者为已经在 DOM 树中的 <link>
改变其资源地址。
参见 WHATWG link type "stylesheet"
The appropriate times to obtain the resource are:
When the external resource link is created on a link element that is already browsing-context connected.
When the external resource link's link element becomes browsing-context connected.
…
例如下面的 HTML 中创建了一个<link>
标签:
<html>
<body>
<script>
var link = document.createElement('link');
link.rel = 'stylesheet';
link.href = "foo.css";
</script>
</body>
</html>
这时浏览器还不会去下载foo.css
,只有插入到 DOM 时浏览器才会立即开始下载:
document.body.appendChild(link);
加载状态
如果需要在脚本中获取外部样式表的加载状态,可以绑定其onload
和onerror
事件。
为了兼容 IE 还可以绑定 onreadystatechange
事件。
需要注意的是<link>
元素是没有readyState
属性的(除了IE)。
document.body.appendChild(link);
link.onload = link.onerror = link.onreadystatechange = function(e) {
console.log('loading state changed:', e.type);
};
细心的读者可能会发现上述代码在插入到 DOM 之后才绑定事件, 由于样式的下载是异步的,所以这是没有问题的。 关于资源载入时机更详细的讨论请参考: 异步渲染的下载和阻塞行为
本文采用 知识共享署名 4.0 国际许可协议(CC-BY 4.0)进行许可,转载注明来源即可: https://harttle.land/2017/01/16/dynamic-link-insertion.html。如有疏漏、谬误、侵权请通过评论或 邮件 指出。