什么时候将样式表添加到document.styleSheets [英] When is a stylesheet added to document.styleSheets

查看:198
本文介绍了什么时候将样式表添加到document.styleSheets的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想使用javascript动态添加CSS样式表规则,例如2
此处



它大部分时间都在工作,但似乎有一个竞争条件,使其失败,有时在(至少)Chrome(15.0.874和17.0.933)。当高速缓存为空(或已被清除)时,它不常发生。



这是我已经能够缩小到。首先我加载一个外部样式表到< head> 然后我创建一个新的样式表(我将添加规则)。然后我打印长度 document.styleSheets (立即和1秒后)。

  $(function(){
//如果没有这行,就不会出现
$(head)。append('< link rel =stylesheettype =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 立即...但可能等待外部文件加载。



这是否是预期的? p>

如果是,请关于MDN的示例2 (和许多其他在那里)打破?从第27行起:

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

可能会评估 document.styleSheets.length == 0



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

解决方案

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



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



所有样式表示例i' ve在web上假设dom被完全解析和加载。
OffDOM样式表甚至不允许插入或检查规则,因为它们可以具有@import规则,并且这些规则必须在外部加载,因此对于浏览器,很难确定何时可以安全地与其交互除非他们完全加载和解析。
OffDOM样式表确实暴露了一个空的工作表属性,但不会让它与它进行交互,直到工作表添加到DOM。



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


I'm trying to dynamically add a css stylesheet rule using javascript, something like example 2 here.

It works most of the time, but there seems to be a race condition that makes it fail sometimes in (at least) Chrome (15.0.874 and 17.0.933). It happens infrequently when the cache is empty (or has been cleared).

Here's what I've been able to narrow it down to. First I load an external stylesheet by appending it to <head> and then I create a new stylesheet (where I would add rules). I then print the length of document.styleSheets (immediately and after 1 second).

$(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);
});

(play with it at http://jsfiddle.net/amirshim/gAYzY/13/)

When the cache is clear, it sometimes prints 2 then 4 (jsfiddle adds it's own 2 css files), meaning it doesn't add either of the style sheets to document.styleSheets immediately... but probably waits for the external file to load.

Is this expected?

If so, is Example 2 on MDN (and many others out there) broken? Since line 27:

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

might evaluate with document.styleSheets.length == 0

Note that this doesn't happen when I don't load the external CSS file first.

解决方案

If JavaScript is in the page below the CSS (which it almost always is) the HTML parser must wait with JS execution until the JS and CSS is fully loaded and parsed because of the fact that JS might request styling information (Chrome only does so when the script actually does this though). This effectively makes the loading of external CSS blocking in almost all cases. When you insert them later via JavaScript or there are no JS' in the page (or the JS is loaded non-blocking) CSS loads asynchronously meaning they're loaded and parsed without blocking the parsing of the DOM. Therefor the documents.stylesheets count only gets updated after the sheet is inside the DOM and that only happens after it is fully loaded and parsed.

In this situation there might be some timing differences involved. Considering most browsers only have a limited number of pipes through which they load data (some have only two like IE6, most have 6 and some even have 12 like IE9) the loading of the stylesheet is added at the end of the queue to be loaded. The browser is still loading things because you call you function on DOMReady. Which results in the stylesheet not being fully loaded and parsed one second later, so not affecting the document.stylesheets.length.

And all stylesheet examples i've run into on the web assume the dom is fully parsed and loaded. OffDOM stylesheets don't even allow rules to be inserted or checked due to the fact that they can have @import rules and those have to be loaded externally, so for browsers it's pretty hard to determine when its safe to interact with the sheet unless they're fully loaded and parsed. OffDOM stylesheets do expose an empty sheet property but won't let you interact with it until the sheet has been added to the DOM.

I've always found it better to insert a stylesheet dynamically and execute all changes in that one sheet and leaving the document.stylesheets alone. This has the great advantage that when you override styles with the same specificity you wont run into trouble because of insertion in the wrong sheet. Since document.stylesheets is a live nodeList, document.stylesheets[ 2 ] can point to another sheet every time you call the function (unless stored in a var). So I tend to use a dynamically inserted sheet and only operate on that one.

这篇关于什么时候将样式表添加到document.styleSheets的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆