JavaScript判断CSS文件加载完成的跨浏览器解决方案

作者:窗边听雨

时间:2026-10-27

浏览:209

本文详细解析了如何在不同浏览器中准确判断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。本次分享至此,希望对各位的开发与学习有所助益!

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章