关于动态CSS载入

        在平时的项目中,特别是一些要求高度模块化的项目里,经常会遇到需要动态载入CSS的情况;比如,在V4版微博的改造过程中,因为采用bigpipe技术,页面被划分成了多个彼此相互独立的pagelet模块,这时就要求不同的模块有着相互独立的样式表与JS文件。

        而他们的加载顺序一般为,优先加载CSS文件,其后是HTML的写入,最后加载模块所需JS文件;这时候就会遇到一个问题,就是怎样去检测CSS文件是否已经加载完毕;因为Link标签是动态创建的,不会产生阻塞效果,所以这时候我们就需要通过程序的方式去监听CSS文件的加载状态;

        我们知道,IE实现了link标签的onload与onreadystatechange事件,可以很方便的让我们去知道什么时候加载完毕;但是其他浏览器却无能为力;

        目前在网上看到了一些解决方式:

        1、检测link标签的属性:

var CSSload = function(link, callback) {
    var cssLoaded = false;
    try{
        if ( link.sheet && link.sheet.cssRules.length > 0 ){
            cssLoaded = true;
        }else if ( link.styleSheet && link.styleSheet.cssText.length > 0 ){
            cssLoaded = true;
        }else if ( link.innerHTML && link.innerHTML.length > 0 ){
            cssLoaded = true;
        }
    }
    catch(ex){ }
    if ( cssLoaded ){
        callback();
    }else{
        setTimeout(function(){
            CSSload(link);
        }, 100);
    }
};

Chrome / Safari:
    linkNode.sheet 在 css 文件下载完成并解析好后才有值,之前为 undefined
    linkNode.sheet.cssRules 同域时返回 CSSRuleList, 跨域时返回 null

  Firefox:
    linkNode.sheet 在 css 插入 DOM 中后立刻有值,插入前为 undefined
    linkNode.sheet.cssRules 在文件还未下好时,抛出 NS_ERROR_DOM_INVALID_ACCESS_ERR
                            在文件下载并解析好后,
                              同域时返回 cssRuleList
                              跨域时抛出 NS_ERROR_DOM_SECURITY_ERR

  IE6-9 / Opera:
    linkNode.sheet 和 cssRules 在 css 插入 DOM 后都立刻可访问,cssRules 为 []
    当文件下载完成时,cssRules 为 cssRuleList
    IE 下,无论成功失败,都会触发 onload
    Opera 只在成功时才触发 onload

  缺陷:Opera 遇到 404 时,需要降级到 timeout

引自:http://lifesinger.org/lab/2011/load-js-css/

        2、利用img的onerror事件

var loadCSS = function(url, callback){
    var link = document.createElement('link');
        link.type = 'text/css';
        link.rel = 'stylesheet';
        link.href = url;

    document.getElementsByTagName('head')[0].appendChild(link);

    var html = document.getElementsByTagName('html')[0];
    var img = document.createElement('img');
        img.onerror = function(){
            if(callback) callback(link);
            html.removeChild(img);
        }

    html.appendChild(img);
    img.src = url;
}

这个...方式不靠谱;他利用img标签的src属性去尝试再次加载link的src,在解析的时候因为mime类型不对,绝对是触发img的onerror事件,但是同样的...如果src不存在,或者其他的错误情况,也会触发onerror事件;

        最后一种方式也是我们项目中用到的方式,比起前两章,在实现上与稳定性上都要靠谱很多,要取一个名字的话,就叫CSS属性检测方式;

        3、CSS属性约定检测方式:

        这种方式的使用也许会受到一定程度的制约,但是在v4版微博内却成为了最合适的方式;因为v4版微博内每个模块都有一个独立的标识,并且模块间独立性很强;所以,我们提供了一个函数,在动态写入link标签后,轮训的去检测一个视野外的div元素的一个css属性(我们用的是height),而且css文件的最后一行,都有对这个div的样式定义,因为每个模块对应一个css,所以要做操作的这个div元素的标识也是唯一的,这样就避免的同时多个css文件载入时,造成冲突,当一个css文件载入后,同时会将这个用于检测的div元素删除掉;具体的代码实现过于简单,就不在列举了;

        这种方式在使用上最为简单和可靠,但是相应的需要css的开发者与JS人员做好约定;如果管理不当也许会造成出现错误后,极难排查的情况;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值