如何异步加载 CSS

我试图消除2 CSS 文件渲染阻塞在我的网站-他们出现在谷歌网页速度洞察。我用过不同的方法,但都不成功。但是,最近,我发现了一篇关于 异步思维的文章,当我应用这个代码时: <script async src="https://third-party.com/resource.js"></script>it 确实消除了这个问题。

但是,在发布之后,页面丢失了样式。我不太清楚是怎么回事,因为代码工作,但它的样式后,上传不工作。如果你能帮忙,我会很感激的。谢谢

163171 次浏览

你可以尝试用很多方法得到它:

1. 在足部使用 media="bogus"<link>

<head>
<!-- unimportant nonsense -->
<link rel="stylesheet" href="style.css" media="bogus">
</head>
<body>
<!-- other unimportant nonsense, such as content -->
<link rel="stylesheet" href="style.css">
</body>

2. 用旧方法插入 DOM

<script type="text/javascript">
(function(){
var bsa = document.createElement('script');
bsa.type = 'text/javascript';
bsa.async = true;
bsa.src = 'https://s3.buysellads.com/ac/bsa.js';
(document.getElementsByTagName('head')[0]||document.getElementsByTagName('body')[0]).appendChild(bsa);
})();
</script>

如果你可以尝试插件,你可以尝试 LoadCSS

<script>
// include loadCSS here...
function loadCSS( href, before, media ){ ... }
// load a file
loadCSS( "path/to/mystylesheet.css" );
</script>

触发异步样式表下载的技巧是使用一个 <link>元素并为 media 属性设置一个无效值(我使用 media = “ none”,但任何值都可以)。当媒体查询的计算结果为 false 时,浏览器仍然会下载样式表,但不会等到内容可用后再呈现页面。

<link rel="stylesheet" href="css.css" media="none">

样式表完成下载后,必须将 media 属性设置为有效值,这样样式规则将应用于文档。Onload 事件用于将媒体属性切换为 all:

<link rel="stylesheet" href="css.css" media="none" onload="if(media!='all')media='all'">

这种载入 CSS 的方法将比标准方法更快地向访问者提供可用的内容。关键的 CSS 仍然可以使用通常的阻塞方法(或者您可以内联它以获得最终的性能) ,非关键的样式可以逐步下载,并在稍后的解析/呈现过程中应用。

这种技术使用 JavaScript,但是您可以通过在 <noscript>元素中包装等效的阻塞 <link>元素来迎合非 JavaScript 浏览器:

<link rel="stylesheet" href="css.css" media="none" onload="if(media!='all')media='all'"><noscript><link rel="stylesheet" href="css.css"></noscript>

您可以在 Www.itcha.edu.sv中看到操作

enter image description here

来源于 http://keithclark.co.uk/

下面的函数将创建所有希望异步加载的样式表并将其添加到文档中。(但是,由于使用了 Event Listener,所以只有在加载了窗口的所有其他资源之后才会这样做。)

请参阅以下内容:

function loadAsyncStyleSheets() {


var asyncStyleSheets = [
'/stylesheets/async-stylesheet-1.css',
'/stylesheets/async-stylesheet-2.css'
];


for (var i = 0; i < asyncStyleSheets.length; i++) {
var link = document.createElement('link');
link.setAttribute('rel', 'stylesheet');
link.setAttribute('href', asyncStyleSheets[i]);
document.head.appendChild(link);
}
}


window.addEventListener('load', loadAsyncStyleSheets, false);

2020年最新情况


答案很简单(完全支持浏览器) :

<link rel="stylesheet" href="style.css" media="print" onload="this.media='all'">

文档化的答案(带有可选的预加载和禁用脚本的备份) :

 <!-- Optional, if we want the stylesheet to get preloaded. Note that this line causes stylesheet to get downloaded, but not applied to the page. Use strategically — while preloading will push this resource up the priority list, it may cause more important resources to be pushed down the priority list. This may not be the desired effect for non-critical CSS, depending on other resources your app needs. -->
<link rel="preload" href="style.css" as="style">


<!-- Media type (print) doesn't match the current environment, so browser decides it's not that important and loads the stylesheet asynchronously (without delaying page rendering). On load, we change media type so that the stylesheet gets applied to screens. -->
<link rel="stylesheet" href="style.css" media="print" onload="this.media='all'">


<!-- Fallback that only gets inserted when JavaScript is disabled, in which case we can't load CSS asynchronously. -->
<noscript><link rel="stylesheet" href="style.css"></noscript>

预加载和异步组合:

如果您需要预加载的和异步的 CSS,这个解决方案只是将上面文档中的答案中的两行结合起来,使它稍微简洁一些。同样,正如上面的文档回答所详述的那样,预加载实际上可能并不是有益的。

<link href="style.css" rel="preload" as="style" onload="this.rel='stylesheet'">
<noscript><link rel="stylesheet" href="style.css"></noscript>

其他考虑:

注意,一般情况下,如果要异步加载 CSS,通常建议内联 关键的 CSS,因为 CSS 是呈现阻塞资源 是有原因的

感谢长丝集团的众多异步 CSS 解决方案。

启用内容安全策略时,此方法可能无法工作。

如果你有一个严格的内容安全策略,不允许 @ Vladimir-salguero回答,你可以使用这个(请注意脚本 nonce) :

<script nonce="(your nonce)" async>
$(document).ready(function() {
$('link[media="none"]').each(function(a, t) {
var n = $(this).attr("data-async"),
i = $(this);
void 0 !== n && !1 !== n && ("true" == n || n) && i.attr("media", "all")
})
});
</script>

只需在样式表引用中添加以下内容: media="none" data-async="true":

<link rel="stylesheet" href="../path/script.js" media="none" data-async="true" />

JQuery 的例子:

<link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/themes/smoothness/jquery-ui.css" type="text/css" media="none" data-async="true" crossorigin="anonymous" /><noscript><link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/themes/smoothness/jquery-ui.css" type="text/css" /></noscript>

请注意更新的答案,因为以上所有未能留下深刻的印象谷歌网页速度洞察力现在。

根据 谷歌,这是实现 CSS 异步加载的方法

 < 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>

使用 media="print"onload

长丝组织最近(2019年7月)发表了一篇文章 ,给出了他们关于如何异步加载 CSS 的最新建议。尽管他们是流行的 Javascript 库 LoadCSS的开发者,他们实际上还是推荐这种不需要 Javascript 库的解决方案:

<link
rel="stylesheet"
href="/path/to/my.css"
media="print"
onload="this.media='all'; this.onload = null"
>

使用 media="print"将向浏览器指示不要在屏幕上使用此样式表,而是在打印时使用。浏览器实际上会下载这些打印样式表,但是是异步的,这正是我们想要的。我们还希望在下载样式表之后使用它,为此我们设置了 onload="this.media='all'; this.onload = null"。(有些浏览器会调用 onload两次,为了解决这个问题,我们需要设置 this.onload = null。)如果您愿意,您可以为少数没有启用 Javascript 的用户添加 <noscript>备份。

原创文章值得一读,因为它比我在这里讲的更详细。这篇文章发表在 csswizdry.com 上也值得一读。

异步 CSS 加载方法

有几种方法可以让浏览器异步加载 CSS,尽管没有一种像您期望的那么简单。

<link rel="preload" href="mystyles.css" as="style" onload="this.rel='stylesheet'">

如果需要以编程方式和异步方式加载 CSS 链接:

// https://www.filamentgroup.com/lab/load-css-simpler/
function loadCSS(href, position) {
const link = document.createElement('link');
link.media = 'print';
link.rel = 'stylesheet';
link.href = href;
link.onload = () => { link.media = 'all'; };
position.parentNode.insertBefore(link, position);
}

我曾尝试使用:

<link rel="preload stylesheet" href="mystyles.css" as="style">

它可以很好地工作,但是它也增加了累积的布局转移,因为当我们使用 rel = “ preload”时,它只是下载 css,而不是立即应用。

例如,当 DOM 加载一个包含 ul,li 标签的列表时,在 li 标签之前默认有一个项目符号,然后应用 CSS 将这些项目符号移除到自定义样式中以便列出。 因此,累积的布局变化正在这里发生。

有什么解决办法吗?

使用 rel="preload"使其独立下载,然后使用 onload="this.rel='stylesheet'"将其应用于样式表(将其应用于样式表必须使用 as="style",否则 onload将无法工作)

<link rel="preload" as="style" type="text/css" href="mystyles.css" onload="this.rel='stylesheet'">