Loading CSS Dynamically using Require.js

Deferred loading of resources can tremendously increase the percievable load time of a web page. That can be easily done with Javascript files which is described here or with HTML5’s async attribute.

If we do not use the async attribute, we

  • create a script element,
  • assign the element’s src property to the value of the URL of the script,
  • assign the onload or onreadystatechange handler function to determine when the script has actually loaded
  • attach the newly created <script> element to the head element of the document

However that is not so easy with CSS stylesheets. Actually, the main problem is that link element does not always have the onload event to determine whether the element has loaded. It is important when we have to perform the necessary initialization operations, like removing the “loading” screen etc.

As a workaround, we use polling: create a well-known stylesheet rule with an element on our page that we monitor after we add the link element to the page. When we detect the known property change of the element, we trigger the callback function. This method has already been described on the require.js home page as well, however the thing they lack is actual code to do this 🙂

The code

I wrote a require.js plugin, called “require-css”, which is available on Github. To use it, all you have to do is to (1) add CSS rule to your stylesheet sample.css that defines the height property: .sample-css-loaded { height: 1px; }, and (2) call the require function as follows:

require(['css!css/sample.css'], function() {
    alert('Stylesheet has been loaded');
});

What this CSS loading plugin does is:

  • creates the link element with the necessary attributes and adds to the document’s head element
  • creates an absolutely off-screen positioned (to avoid any visual glitches on the page) dummy div element and adds to the document’s body element
  • in window.setInterval callback function, monitors the test element’s offsetHeight property and when it is greater than zero, clears the interval, removes the dummy element, and calls the require.js’ callback method;

Additional notes

The plugin can be extended by assigning any arbitrary CSS property to monitor, something like

require(['css!css/sample.css#offsetWidth'], function() {
    ...
});

offsetWidth could be replaced by any other property whose value type is length.

I guess, that would be useful when user of the plugin has no control over the CSS he or she wants to load, however I haven’t had such a use case yet.

Leave a Reply

Your email address will not be published. Required fields are marked *