我想实现异步加载 CSS 文件以获得更快的性能。不过我也想要安全性,所以我希望我的网站有 CSP。
<link rel="stylesheet" media="print" class="AOcssLoad" .... onload="this.onload=null;this.media='all';" />
无需详细说明,它希望我避免像
onload
和许多其他属于元素一部分的 JS。
我希望它看起来像这样
<link rel="stylesheet" media="print" class="AOcssLoad" href="" />
请建议一种无需上面使用的内联 JS 即可实现异步 CSS 文件的方法。
我们可以使用内联
<script>
标签或单独的 JS 文件。
我尝试了以下代码作为内联 JS。下面是 JS 的 HTML,
<script nonce="" type="text/javascript" data-exclude="true">
var Script = document.getElementsByClassName("AOcssLoad");
for (var i = 0 ; i < Script.length; i++) {
this.className += " Loading";
Script[i].addEventListener("load", function({
this.onload=null;this.media="all";
this.className += " OnLoad";
});
}
</script>
虽然它有效,但非常不可靠。
我无法理解这个问题,但我想说它只在 50% 的情况下有效,有时只需重新加载页面就可以解决/打破问题,而对 css/html/cache 没有明显的更改。
请帮助我改进这一点,或者为此建立更好的方法。
编辑:
按照评论中的建议,我尝试了不同的方法,包括 GitHub 上其他资源的链接。
这些方法并不可靠,我想说它们的成功率不到 50%。 不过,我尝试对所有 css 文件使用
jQuery(document).ready()
和 add media="all"
,但这会增加 TBT(总阻塞时间),从而影响我的网站性能
编辑2:
正如你们中的许多人在答案中反复指出的那样,使用 DOMcontentLoaded 和许多其他方法可以帮助完成我想要实现的事情。
然而,这些方法都会导致TBT(总阻塞时间)的显着增加。
如果有一种不损害 TBT 的方法,我们将不胜感激。
我建议使用
fetch().then()
并将其作为 style
元素注入:
var stylesheetURLS = ["style.css", "style2.css"]
stylesheetURLS.forEach(url => {
fetch(url).then(response => response.text()).then(stylesheet => {
var styleElement = document.createElement("style");
styleElement.textContent = stylesheet;
document.head.append(styleElement);
});
});
我不确定
fetch
是否很慢,但如果是的话我也不会感到惊讶。
替代
fetch
:XMLHttpRequest
var stylesheetURLS = ["style.css", "style2.css"];
stylesheetURLS.forEach(url => {
var request = new XMLHttpRequest();
request.open("GET", url);
request.send();
request.onload = function() {
var styleElement = document.createElement("style");
styleElement.textContent = request.responseText || request.response;
document.head.append(styleElement);
}
});
我再次不确定这是否比
fetch
更快
您可以使用基于 jQuery 的vanilla JS 函数
.ready()
:
document.addEventListener("DOMContentLoaded", () => {
document.querySelectorAll(".AOcssLoad").forEach(el => {
el.media = "all"
console.log(`Loaded: ${el.href}`)
})
});
<link rel="stylesheet" media="print" class="AOcssLoad" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" />
<link rel="stylesheet" media="print" class="AOcssLoad" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap-utilities.min.css" />
<link rel="stylesheet" media="print" class="AOcssLoad" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap-reboot.min.css" />
<link rel="stylesheet" media="print" class="AOcssLoad" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap-grid.min.css" />
<h1>Hello world!</h1>
但是,无论您选择哪种解决方案,请注意您都必须处理无样式内容的 Flash (FOUC)。考虑管理样式表文件的其他方法。
为什么不注射它
<script>
document.write("<link rel=\"stylesheet\" media=\"print\" class=\"AOcssLoad" href=\"\" />
");
</script>
并将
<script>
标签放置在您想要放置 <link>
标签的位置的正上方。
或者只是
<link rel="stylesheet" media="print" class="AOcssLoad" href="" />
除了 css 将异步加载并且您可以使用 csp 之外,什么都没有发生
你的脚本就是错误的,而且它根本无法工作,甚至 50% 的情况下都无法工作。
var Script = document.getElementsByClassName("AOcssLoad");
for (var i = 0 ; i < Script.length; i++) {
this.className += " Loading"; // here `this` is `window`
Script[i].addEventListener("load", function({ // <-- this is an Object
this.onload=null;this.media="all"; // <-- this is a syntax error
this.className += " OnLoad";
});
}
这是您可能想要编写的内容的重写,其中还包括检查链接是否在脚本运行之前加载,以防万一(例如缓存)。
const links = document.getElementsByClassName("AOcssLoad");
for (const link of links) {
link.className += " Loading";
if(link.sheet) { // "already loaded"
oncssloaded.call(link);
}
else {
link.addEventListener("load", oncssloaded, { once: true });
}
}
function oncssloaded() {
this.media = "all";
this.className += " OnLoad";
}
<link rel="stylesheet" media="print" class="AOcssLoad" href="data:text/css,body{color:green}" />
Some green text
我知道这个帖子已经很老了,但我会把它扔掉,因为这是我目前在 WordPress 中使用的东西......
首先,使用标准 WordPress 工具添加样式表 (
wp_enqueue_style()
)。
然后:
add_filter('style_loader_tag', 'optimize_async_style',10,4);
function optimize_async_style(string $tag, string $handle, string $src, string $media): string
{
$nonce = wp_create_nonce();
$nonce = " nonce='{$nonce}'" : "";
$tag = "<link rel='preload' id='{$handle}-css' href='{$src}' as='style' media='{$media}'{$nonce}>\n".
"<script{$nonce}>document.getElementById('{$handle}-css').addEventListener(".
"'load',(e)=>{e.currentTarget.rel='stylesheet';},{once:true});".
"</script><noscript>" . trim($tag) . "</noscript>\n";
return $tag;
}
style_loader_tag
过滤器让我们可以用link
更改rel='preload'
标签,后跟script
标签,加载后将其更改为rel='stylesheet'
。这提供了样式表的异步加载。另请注意,我们为 CSP 的 link
和 script
标签分配了一个随机数。
输出应类似于:
<link rel='preload' id='AOcssLoad-1' href='...' as='style' media='all' nonce='4783a68661'>
<script nonce='4783a68661'>document.getElementById('AOcssLoad-1').addEventListener('load',(e)=>{e.currentTarget.rel='stylesheet';},{once:true});</script>
<noscript><link rel='stylesheet' id='AOcssLoad-1' href='...' media='all' /></noscript>
然而,这是使用 id 而不是 class。