I have some code (it's actually not mine but the SlickGrid library) that creates a <style>
element, inserts it into the DOM, then immediately tries to find the new stylesheet in the document.styleSheets collection.
In WebKit this sometimes fails. I don't actually have any idea what the circumstances are, but it's nothing that's consistently reproducible. I figured I could work around it by changing the code so the check for the StyleSheet object doesn't happen until the load
event on the style element, like so:
$style = $("<style type='text/css' rel='stylesheet' />").appendTo($("head"));
var rules = ...;// code to create the text of the rules here
if ($style[0].styleSheet) { // IE
$style[0].styleSheet.cssText = rules.join(" ");
} else {
$style[0].appendChild(document.createTextNode(rules.join(" ")));
}
$style.bind('load', function() {
functionThatExpectsTheStylesheet();
});
and functionThatExpectsTheStylesheet attempts to locate the actual stylesheet object like so:
var sheets = document.styleSheets;
for (var i = 0; i < sheets.length; i++) {
if ((sheets[i].ownerNode || sheets[i].owningElement) == $style[0]) {
stylesheet = sheets[i];
break;
}
}
but sometimes even at that point, the stylesheet object is not found.
So, my question is this:
load
event in fact not guarantee that the styleSheet object will be available? Is it a bug?Dynamically loading CSS stylesheets is still an area filled with browser quirks, unfortunately. In Webkit, <style>
and <link>
elements will both fire load
and error
events when loading stylesheets. However, the load
event itself means only that the stylesheet resource has been loaded, not necessarily that it has been added to document.styleSheets
.
The require-css RequireJS loader deals with this issue by branching its loading mechanism based on userAgent sniffing (it is nearly impossible to feature-detect whether or not the <link>
tag will fire its load
event properly). Specifically for Webkit, the detection resorts to using setTimeout
to find when the StyleSheet object has been attached to document.styleSheets
var webkitLoadCheck = function(link, callback) {
setTimeout(function() {
for (var i = 0; i < document.styleSheets.length; i++) {
var sheet = document.styleSheets[i];
if (sheet.href == link.href)
return callback();
}
webkitLoadCheck(link, callback);
}, 10);
}
So while the load
event will fire on Webkit, it is unreliable for the purposes of being able to access the corresponding StyleSheet
instance.
Currently the only engine that supports stylesheet load
events properly is Firefox 18+.
Disclosure: I am a contributor to require-css
References:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With