Loading stylesheets at runtime.


Posted by Trka in Code, Javascript on Jun 25, 2017

What we're doing: In an HTML page, after the document has loaded - at userspace runtime - we'll use javascript to load and then reload an additional document-level stylesheet.

What we're not doing: We're not using JS to set element styles. That's a different topic. 

Prerequisites and Assumptions: This is a pretty fundamental topic. You'll need only the most basic understanding of what javascript and css are, and how they work. Being a fundamental, I'm tossing in some more advanced syntax, etc to prompt further reading. Those things are explained in place, and I'm highlighting the meat to avoid burying the lead. 

There are a few applications for this, but the moral of the story is: "Javascript can set or reset page stylesheets". That's kind of a big deal. We can use this in production to let users choose their own site 'skin' or any number of other things, or we can use it in dev to see different styles side-by-side. 

That's the ends. Let's jump into it.

The plunker below has a dead-simple html - just an h1 and a button that triggers a javascript method. The document has a default style, and an additional link element that our js will be tinkering with.

The magic is in load-css.js, but what does it do? We have 50-ish lines of javascript, but it really boils down to a one-liner link.href = string and a whole lot of sugar. When we set link.href with javascript, it sets that link element's source file, which triggers an http request much like when the page initially loaded. Our sugar is to sort of illustrate two distictly different approaches in one example. When working with link.href, you can 

  • addNewCss() creates a new link element and appends it to the dom. This doesn't affect already loaded stylesheets; it appends your new one to the stack.

     * Creates a new link element, sets its params according to what we want, add appends it to the document head
    function addNewCss() {
        var head = $.getElementsByTagName('head')[0];
        //-- using the dom api to create a new link element
        var link = $.createElement('link');
        link.id = user_cssnodeid;
        link.rel = 'stylesheet';
        link.type = 'text/css';
        link.href = new_usercss;
        link.media = 'all';
  • resetCss() finds an already-there head link and resets its href entirely. This effectively unloads that sheets and replaces it with your new one.  

     * since the element with our target id is there, we don't need to create it. 
     * simply select it and set its href attribute.
    function resetCss() {
        var link = $.getElementById(user_cssnodeid);
        link.href = new_usercss;
        link.media = 'all';

In both methods, we see the header color go from black to red to green and back to red. The low-level mechanics are illustrated, if you pay close attention when toggling red-green-red. Outside of main.css and other-main.css, our h1 has browser-default color. When you toggle the link's href, you see a flash of black text. This is because you've unloaded the previous sheet and the browser is creating an http request to load-in the new one. The flash of black shows that we're not setting style rules on the element; rather, we are, in fact, removing and adding document-level stylesheets. 

The red-green-red example is a crude oversimplification, of course. If that was your endgame, this certainly isn't the solution for it. We did illustrate using the browser's dom api to do what could - with the same or smaller code - have been a very powerful thing, though.

Featured Image Credit: https://pixels4kids.files.wordpress.com/