views:

527

answers:

5
+13  Q: 

link element onload

Is there anyway to listen to the onload event for a <link> element?

F.ex:

var link = document.createElement('link');
link.rel = 'stylesheet';
link.href = 'styles.css';

link.onload = link.onreadystatechange = function(e) {
    console.log(e);
};

This works for <script> elements, but not <link>. Is there another way? I just need to know when the styles in the external stylesheet has applied to the DOM.

Update:

Would it be an idea to inject a hidden <iframe>, add the <link> to the head and listen for the window.onload event in the iframe? It should trigger when the css is loaded, but it might not guarantee that it's loaded in the top window...

+3  A: 

This is kind of a hack, but if you can edit the CSS, you could add a special style (with no visible effect) that you can listen for using the technique in this post: http://www.west-wind.com/weblog/posts/478985.aspx

You would need an element in the page that has a class or an id that the CSS will affect. When your code detects that its style has changed, the CSS has been loaded.

A hack, as I said :)

Peter Jaric
A: 

Since you didn't like my hack :) I looked around for some other way and found one by brothercake.

Basically, what is suggested is to get the CSS using AJAX to make the browser cache it and then treat the link load as instantaneous, since the CSS is cached. This will probably not work every single time (since some browsers may have cache turned off, for example), but almost always.

Peter Jaric
That is not a bad idea, but I need to support local files (XMLHttpRequest does not support local files in FF 3+)
David
+1  A: 

There's JS library out for that: ensure. Here's a blog which explains how that all works.

BalusC
Sounds like this is exactly what the OP needs, if it can handle local files. +1
Peter Jaric
This library uses http get to cache the CSS, I need a clean solution for local files too.
David
+1  A: 

You either need a specific element which style you know, or if you control the CSS file, you can insert a dummy element for this purpose. This code will exactly make your callback run when the css file's content is applied to the DOM.

// dummy element in the html
<div id="cssloaded"></div>

// dummy element in the css
#cssloaded { height:1px; }

// event handler function
function cssOnload(id, callback) {
  setTimeout(function listener(){
    var el = document.getElementById(id),
        comp = el.currentStyle || getComputedStyle(el, null);
    if ( comp.height === "1px" )
      callback();
    else
      setTimeout(listener, 50);
  }, 50)
}

// attach an onload handler
cssOnload("cssloaded", function(){ 
  alert("ok"); 
});

If you use this code in the bottom of the document, you can move the el and comp variables outside of the timer in order to get the element once. But if you want to attach the handler somewhere up in the document (like the head), you should leave the code as is.

Note: tested on FF 3+, IE 5.5+, Chrome

galambalazs
Why were you down/up/down/up voting everytime? To remove a vote, just click the same orange arrow again.
BalusC
Peter said: "Sounds like this is exactly what the OP needs". The OP said, no it's not what I need. +1 from Peter, -1 from me...
galambalazs
I don't care about that, just trying to be helpful, but you were first downvoting it and then upvoting it and then downvoting it again within the same minute (and maybe once more thereafter). I just had a "wtf"? :)
BalusC
because I'm high... :)
galambalazs
Fine, but why did you downvote Peter's post as well which basically answers the same as you? Is it gaming/gambling? I find it honestly said unfair and egocentric ;)
BalusC
because he offered an **overcomplicated** jQuery solution, which is **bloated** for a simple problem and may not be cross browser. It's all about **quality**. The reason there is an up/down vote is to **promote preferred solutions**. I'm only trying to help the OP, to get the best one.
galambalazs
A: 

This trick is borrowed from the xLazyLoader jQuery plugin:

var count = 0;

(function(){
  try {
    link.sheet.cssRules;
  } catch (e) {
    if(count++ < 100)
      cssTimeout = setTimeout(arguments.callee, 20);
    else
      console.log('load failed (FF)');
    return;
  };
  if(link.sheet.cssRules && link.sheet.cssRules.length == 0) // fail in chrome?
    console.log('load failed (Webkit)');
  else
    console.log('loaded');
})();

Tested and working locally in FF (3.6.3) and Chrome (linux - 6.0.408.1 dev)

Demo here (note that this won't work for cross-site css loading, as is done in the demo, under FF)

sje397
older browsers don't have try-catch. arguments.callee is no longer part of the language. No test in IE???
galambalazs
Nope. IE doesn't run on my operating system, thank god (or takes more effort than I'm willing to put in). For the record tho I think the onload/onreadystatechange events do work in IE. And I didn't see any requirement that it work in browsers that old.
sje397
And callee was [deprecated](https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Functions/arguments/callee) only as a property of Function.arguments in js 1.4, not as a property of the function's local arguments variable.
sje397
your link is a **browser vendor's site** about an **older version**, not the **current language spcification**. let me help you out. The new version (since 2009 December): http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-262.pdf
galambalazs
Yes. It's one of many links that say the same thing. The document you linked to says accessing callee will throw an error *in struct mode* only. That is very different to it 'not being part of the language'.
sje397
"strict mode is the future of the language", as Douglas Crockford (memeber of the ecma committee) stated. it's not forced because it would break most of the sites right now. But the new version called Harmony will be based on the strict mode, and **will definitely break your site**. **Consider the future**. The version you are writing in is from 1999... Just to be clear.
galambalazs
In fact that document states, 'The "callee" property has a more specific meaning for non-strict mode functions...' You'd have to read and understand section 10.6 to know what that meaning is.
sje397
arguments.callee was removed for good reason, because it's not safe.also there is a simple solution for replacing arguments.callee, so...
galambalazs
Ok. So to be clear, it is still part of the language, and some people think it might not be one day. Cool.
sje397
you should care, who you call "some people"... papa corckford will kick your ass.. http://crockfordfacts.com/ :))
galambalazs
ha. :) great link. I guess even Chuck Norris lives in fear...
sje397