简体   繁体   中英

On Chrome document.styleSheets is not updated when I add a stylesheet

Apparently there is an issue with the property document.styleSheets in Google Chrome. The property is not updated after a new stylesheet is added. To reproduce the issue simply run the following code:

    // Create the link element
    var element = document.createElement("link");
    element.setAttribute("rel", "stylesheet");
    element.setAttribute("type", "text/css");
    element.setAttribute("href", "external.css");

    // Add the link element
    console.log('Before add: ' + document.styleSheets.length);
    document.getElementsByTagName("head")[0].appendChild(link);
    console.log('After add: ' + document.styleSheets.length);

When running in FireFox the console will show something like:

    Before add: 4
    After add: 5

When running in Chrome the console will show something like:

    Before add: 4
    After add: 4

Interestingly, the following code works correctly (return the same results) on both browsers:

    console.log('Before add: ' + document.getElementsByTagName("head")[0].children);
    document.getElementsByTagName("head")[0].appendChild(link);
    console.log('After add: ' + document.getElementsByTagName("head")[0].children);

Is this a bug or I'm doing something wrong?

I discovered this issue while writing and testing the following function to dynamically add CSS files to a web page:

function requiresCSS( name ) { 
    var sheets = document.styleSheets; 
    for (var i = 0; i < sheets.length; i++) { 
        if (sheets[i].href && sheets[i].href.indexOf(name) !== -1) { 
            return; 
        } 
    }

    var link = document.createElement("link"); 
    link.rel = "stylesheet";
    link.type = "text/css"; 
    link.href = name; 
    document.getElementsByTagName("head")[0].appendChild(link); 
}    

When trying to add CSS twice, the function works perfectly on Firefox but fails on Chrome.

You're adding an external file and then checking for it immediately. It's not surprising that you wouldn't see it yet, the HTTP request is probably still outstanding. If you check back later, once the HTTP request is complete and the styles parsed and applied, you'll see it in document.styleSheets .

According to the HTML5 specification , you can use the load event on the link element to get a notification of when the resource has been loaded. So:

element.addEventListener("load", function() {
    console.log('After add: ' + document.styleSheets.length);
}, false);
console.log('Before add: ' + document.styleSheets.length);
document.getElementsByTagName("head")[0].appendChild(link);

Of course, loading and parsing/applying may not be simultaneous, so if you still see a disparity, you may need a setTimeout in there:

element.addEventListener("load", function() {
    setTimeout(function() {
        console.log('After add: ' + document.styleSheets.length);
    }, 0);
}, false);
console.log('Before add: ' + document.styleSheets.length);
document.getElementsByTagName("head")[0].appendChild(link);

Re your function that tries to avoid adding a stylesheet twice, since the element is there reliably even if the entry in document.styleSheets isn't, I'd just look for the element:

function requiresCSS( name ) { 
    // If we already have an element for this stylesheet, return
    if (document.querySelector('link[rel=stylesheet][href="' + name + '"]') {
        return;
    }

    // Add it
    var link = document.createElement("link"); link.rel = "stylesheet";
    link.type = "text/css"; link.href = name; 
    document.getElementsByTagName("head")[0].appendChild(link); 
}    

(You could also use querySelector for finding head , it'd be a bit more concise. querySelector / querySelectorAll are supported on all modern browsers, and also IE8.)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM