JavaScript判断CSS文件加载完成的跨浏览器解决方案
本文详细解析了如何在不同浏览器中准确判断CSS文件是否加载完成。针对IE6-9利用attachEvent事件,而Firefox和WebKit内核浏览器则需通过轮询sheet.cssRules属性来实现。文章提供了SeaJS与Diego Perini的参考代码,并探讨了动态创建Link节点及处理404状态等边界情况,为前端动态加载样式提供实用方案。
判断CSS加载完成的跨浏览器方案
要判断CSS文件是否加载完毕,各浏览器的实现机制存在显著差异。其中IE浏览器的处理相对直观,我们可以直接利用onload方法来处理CSS加载完成后的后续逻辑。
代码如下:
// 代码节选至seajs
function styleOnload(node, callback) {
// for IE6-9 and Opera
if (node.attachEvent) {
node.attachEvent('onload', callback);
// NOTICE:
// 1. "onload" will be fired in IE6-9 when the file is 404, but in
// this situation, Opera does nothing, so fallback to timeout.
// 2. "onerror" doesn't fire in any browsers!
}
}
然而,在其他浏览器中判断CSS是否加载完成则较为复杂。Firefox和WebKit内核浏览器可以通过检查node.sheet.cssRules属性是否存在来判断加载状态,但这种方法需要配合setTimeout进行间隔轮询。
代码如下:
// 代码节选至seajs
function poll(node, callback) {
if (callback.isCalled) {
return;
}
var isLoaded = false;
if (/webkit/i.test(navigator.userAgent)) {//webkit
if (node['sheet']) {
isLoaded = true;
}
}
// for Firefox
else if (node['sheet']) {
try {
if (node['sheet'].cssRules) {
isLoaded = true;
}
} catch (ex) {
// NS_ERROR_DOM_SECURITY_ERR
if (ex.code === 1000) {
isLoaded = true;
}
}
}
if (isLoaded) {
// give time to render.
setTimeout(function() {
callback();
}, 1);
}
else {
setTimeout(function() {
poll(node, callback);
}, 1);
}
}
setTimeout(function() {
poll(node, callback);
}, 0);
SeaJS完整处理逻辑
SeaJS给出的完整处理逻辑如下:
代码如下:
function styleOnload(node, callback) {
// for IE6-9 and Opera
if (node.attachEvent) {
node.attachEvent('onload', callback);
// NOTICE:
// 1. "onload" will be fired in IE6-9 when the file is 404, but in
// this situation, Opera does nothing, so fallback to timeout.
// 2. "onerror" doesn't fire in any browsers!
}
// polling for Firefox, Chrome, Safari
else {
setTimeout(function() {
poll(node, callback);
}, 0); // for cache
}
}
function poll(node, callback) {
if (callback.isCalled) {
return;
}
var isLoaded = false;
if (/webkit/i.test(navigator.userAgent)) {//webkit
if (node['sheet']) {
isLoaded = true;
}
}
// for Firefox
else if (node['sheet']) {
try {
if (node['sheet'].cssRules) {
isLoaded = true;
}
} catch (ex) {
// NS_ERROR_DOM_SECURITY_ERR
if (ex.code === 1000) {
isLoaded = true;
}
}
}
if (isLoaded) {
// give time to render.
setTimeout(function() {
callback();
}, 1);
}
else {
setTimeout(function() {
poll(node, callback);
}, 1);
}
}
动态创建Link节点实现以下是我动态创建Link节点的函数实现:
function createLink(cssURL,lnkId,charset,media){
var head = document.getElementsByTagName('head')[0],
linkTag = null;
if(!cssURL){
return false;
}
linkTag = document.createElement('link');
linkTag.setAttribute('id',(lnkId || 'dynamic-style'));
linkTag.setAttribute('rel','stylesheet');
linkTag.setAttribute('charset',(charset || 'utf-8'));
linkTag.setAttribute('media',(media||'all'));
linkTag.setAttribute('type','text/css');
linkTag.href = cssURL;
head.appendChild(linkTag);
}
function loadcss(){
var styleNode = createLink('/wp-content/themes/BlueNight/style.css');
styleOnload(styleNode,function(){
alert("loaded");
});
}其他参考方案与总结
在参考SeaJS代码时,我想起了Diego Perini提出的另一种解决方案:
代码如下:
/*
* Copyright (C) 2010 Diego Perini
* All rights reserved.
*
* cssready.js - CSS loaded/ready state notification
*
* Author: Diego Perini <diego.perini at gmail com>
* Version: 0.1
* Created: 20100616
* Release: 20101104
*
* License:
* https://www.jb51.net * Download:
* http://javascript.nwbox.com/cssready/cssready.js
*/
function cssReady(fn, link) {
var d = document,
t = d.createStyleSheet,
r = t ? 'rules' : 'cssRules',
s = t ? 'styleSheet' : 'sheet',
l = d.getElementsByTagName('link');
// passed link or last link node
link || (link = l[l.length - 1]);
function check() {
try {
return link && link[s] && link[s][r] && link[s][r][0];
} catch(e) {
return false;
}
}
(function poll() {
check() && setTimeout(fn, 0) || setTimeout(poll, 100);
})();
}
实际上,若参考jQuery中domready事件的判断逻辑,其原理相似,均通过setTimeout轮询来检测DOM节点是否加载完成。此外,Facebook的做法是在动态创建的CSS样式中嵌入一个固定样式(如#loadcssdom,该样式高度为1px),随后动态生成一个DOM对象并应用此样式,再通过setTimeout轮询该DOM元素是否具备1px高度。关于此处理方案的详细解决思路,可参考《CSSP: Loading CSS with Javascript – and getting an onload callback.》一文。而《JavaScript Patterns》作者Stoyan在博客中深入探讨了《When is a stylesheet really loaded?》。阅读上述内容后,或许会感叹:目前判断CSS是否加载完毕并非易事!本文旨在抛砖引玉,因为在开发中,除动态加载CSS外,还需处理动态加载JavaScript及HTML等操作。后续我将撰写关于动态加载JavaScript的文章,在此之前,建议查阅以下资源:《ensure – Ensure JavaScripts/HTML/CSS are loaded on-demand when needed》,该库专为按需动态加载HTML、CSS和JavaScript而设计。正如作者所述:ensure是一个轻量级JavaScript库,提供便捷的ensure函数,允许按需加载JavaScript、HTML和CSS,并执行相关代码。ensure确保在使用相关JavaScript和HTML片段前,它们已存在于浏览器DOM中。此外,www.jb51.net也提供了相关ensure实现。《Tell CSS that JavaScript is available ASAP》一文指出,当页面某些部分的样式和功能取决于JavaScript是否可用时,无需再纠结:When you're styling parts of a web page that will look and work differently depending on whether JavaScript is available or not。本次分享至此,希望对各位的开发与学习有所助益!
anime.js 快速入门:怎么引入库并编写第一个 DOM 动画
2026-11-05 14:22:43
在线JS解密后变量名仍乱码?结合浏览器DevTools调试还原
2026-11-04 20:26:01
怎么在浏览器中运行JavaScript代码并查看输出结果
2026-11-04 09:07:33
JS 获取屏幕分辨率:window.screen.width 与 height 用法
2026-11-04 08:52:48
为什么推荐用DOMContentLoaded代替window.onload初始化JS
2026-11-04 08:42:33
