Link element load event support for CSS Style Sheet includes, finally!

In the long history of developer attempts at creating a method of loading CSS Style Sheets via LINK tags with load event support, there has been a lot of FAIL and almost no WINNING! Oddly enough, Internet Explorer has supported a load event on LINK tags for as long as I can remember, but Firefox and the Webkit bunch…not so much.

What are people doing currently to service this need? Well here’s an example of half-baked solutions that have surfaced over the last couple of years on Stack Overflow (I have added my solution to the list, so up-vote it!). Most developer have been reduced to loops that look for the new sheet in the StyleSheet object at short intervals or even loading the link tag in an iframe and using the frame’s onload event, two methods that cause me to puke on my shoes on principle.

The Solution

Well web devs, today is the day. Yup, CSS Style Sheet loading via LINK tags with pretty damn legit load event support is a reality:

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 img = document.createElement('img');
        img.onerror = function(){
            if(callback) callback(link);
        }
        img.src = url;
}

The code above creates a LINK tag for your CSS file and inject it into the head of the document, there’s certainly nothing odd about that. Next comes the interesting part, it creates an IMG tag and adds your CSS file location as src parameter of the element then injects it into the page. The browser parser downloads the file and attempts to parse it, which predictably fails as it is the wrong MIME type. That failure triggers the error event on the image element. We know the file is present at that point, so the load event you pass to the function is fired from inside the image element error event, the image element is then deleted from the document. Whether cached or not, this method will fire your load event for any CSS file you include, when the file is in the cache it is called immediately – which is a huge benefit.

Try it out!

Here it is a live demo, I have added an alert as the load event default for example sake:

23 comments
MLaZz
MLaZz

Just adding my two cents.


TL;DR

Sometimes onerror.. will not fire (even as it should). In my case some CSS files fired onload event on img object. 


More details:

I am working on a webapp that dynamically load JS and CSS assets. Since there is quite a lot of different components (each has it's own JS and CSS) on the page there is also a lot of requests for CSS files and I need to know when something has loaded.

Your workaround for onload event on link elements is great but while testing with stock browser on Android 4.3 (Samsung Galaxy S III) I noticed that sometimes (and in my case always for the same CSS file) onerror.. event is not fired.

On a hunch I also added onload event (which presumably should never fire) to the img object and guess what... That specific file fired onload event instead of onerror...

nyteschayde
nyteschayde

An alternative version using Q/promises and providing a quick short circuit if the tag already exists and an id is provided. This allows you to do something akin to loadCSS(url, id).then(function(tag) {...});

nyteschayde
nyteschayde

Promises aren't for everyone but the don't repeat if it already exists is useful.

gztomasa
gztomasa

The onerror. handler gets called as soon as a reponse is received from the server, it happens some time before the file is fully received. That time is the receiving time and depends on the file size.

ryan beard
ryan beard

I've implemented this solution in a project I'm working on, and it fails in Safari 4.x and 5.0.2 on mac. Might have to write an ajax version instead...

David
David

1. Whether or not the file is "cached" is not really relevant most times, you also want to know when the styles have applied. 2. The onerror. will also fire on 404, so it’s not really reliable.

Pretty
Pretty

although it works, it isn't pretty. funny to see ie does something right this time.

Martin Grigorov
Martin Grigorov

Hi, Here is my optimized version:             var img = document.createElement('img');             img.onerror. = function() {                 load(link);             }             img.src = link.href; There is no need to append the image to the body and remove it. Just assing 'onerror.' callback before assigning 'src' attribute. martin-g

Michele Carino
Michele Carino

Dude good work, i just want to add img.style.display="none";

Kristopher Giesing
Kristopher Giesing

You can also use XHR to retrieve the contents of the CSS file, then inject a style tag in the head rather than a link tag.

zzlang
zzlang

When the css file isn't found,it also can trigger the img element's onerror. event.How can you be sure that the css file can be loaded successfully?