何时将样式表添加到document.styleSheets

时间:2011-11-09 04:43:02

标签: javascript jquery css google-chrome stylesheet

我正在尝试使用javascript动态添加css样式表规则,例如示例2 here

它大部分时间都有效,但似乎存在一种竞争条件,有时会导致(至少)Chrome(15.0.874和17.0.933)失败。当缓存为空(或已被清除)时,它很少发生。

这是我能够将其缩小到的范围。首先,我通过将其附加到<head>来加载外部样式表,然后创建一个新的样式表(我将在其中添加规则)。然后我打印document.styleSheets的长度(立即和1秒后)。

$(function() {
    // it doesn't happen if this line is missing.
    $("head").append('<link rel="stylesheet" type="text/css"'+
                     'href="/css/normalize.css" />');

    var stylesheet = document.createElement("style");
    stylesheet.setAttribute("type", "text/css");
    document.getElementsByTagName('head')[0].appendChild(stylesheet);

    var b = $('body');
    b.append(document.styleSheets.length).append('<br/>');
    setTimeout(function() {
        b.append(document.styleSheets.length).append('<br/>');
    }, 1000);
});

(在http://jsfiddle.net/amirshim/gAYzY/13/播放)

当缓存清除时,它有时会打印2然后4(jsfiddle添加它自己的2个css文件),这意味着它不会将任何一个样式表添加到document.styleSheets立即...但可能等待外部文件加载。

这是预期的吗?

如果是这样,Example 2 on MDN(还有很多其他人)被打破了吗?从第27行开始:

var s = document.styleSheets[document.styleSheets.length - 1];

可能会使用document.styleSheets.length == 0

进行评估

请注意,当我不首先加载外部CSS文件时,不会发生这种情况。

2 个答案:

答案 0 :(得分:4)

如果JavaScript位于CSS下面的页面(它几乎总是如此),HTML解析器必须等待JS执行,直到JS和CSS完全加载和解析,因为JS可能会请求样式信息(仅限Chrome)当脚本实际执行此操作时会这样做)。 这有效地使得几乎在所有情况下加载外部CSS都是阻塞的。 当您稍后通过JavaScript插入它们或者页面中没有JS'(或者JS被加载非阻塞)时,CSS异步加载意味着它们被加载和解析而不会阻​​止DOM的解析。 因此,documents.stylesheets计数仅在工作表进入DOM之后才会更新,并且仅在完全加载和解析之后才会发生。

在这种情况下,可能会涉及一些时间差异。 考虑到大多数浏览器只有有限数量的管道来加载数据(有些只有两个像IE6,大多数有6个,有些甚至有12个像IE9),样式表的加载被添加到队列的末尾以便加载。 浏览器仍然在加载东西,因为你在DOMReady上调用了你的功能。 这导致样式表在一秒钟后未完全加载和解析,因此不会影响document.stylesheets.length。

我在网上遇到的所有样式表示例都假设dom已完全解析并加载。 OffDOM样式表甚至不允许插入或检查规则,因为它们可以具有@import规则并且必须从外部加载,因此对于浏览器来说很难确定何时可以安全地与工作表交互,除非它们'完全加载并解析。 OffDOM样式表会公开一个空的图纸属性,但在将图纸添加到DOM之前不会让您与它进行交互。

我总是发现最好动态插入样式表并执行该表中的所有更改并单独保留document.stylesheets。 这具有很大的优势,当您以相同的特异性覆盖样式时,由于插入错误的工作表,您不会遇到麻烦。 由于document.stylesheets是一个实时nodeList,因此每次调用该函数时,document.stylesheets [2]都可以指向另一个工作表(除非存储在var中)。 因此,我倾向于使用动态插入的工作表,只对该工作表进行操作。

答案 1 :(得分:1)

这应该会有所帮助:'When is a stylesheet really loaded'

'实施例2'。如果在调用addStylesheetRules()时加载样式表,它会破坏,当然这是在Chrome中。