Creating a Simple Style Switcher

James Hibbard

One way to enhance your site’s user experience is to allow your visitors to personalize certain aspects of it. This could be anything from increasing font size, to selecting an appropriate language or locale. As a developer, the challenge in implementing this is twofold. You have to enable the user to make the personalizations in the first place, as well as remember them the next time they visit. This tutorial will teach you how to create a style switcher and use local storage to remember your user’s preferences.

The Basics

The first thing we’ll need is a basic HTML page with a bit of content and styling. I’ll also add a select element which will enable the visitor to change between styles. An example of what this page might look like is shown below.

Reacting to Events

Since a dropdown menu is used to switch between styles, we need to attach an event listener to the select element that reacts appropriately each time the user selects a new style. According to the W3C DOM Level 2 Event Model, the standard way to register event handlers is as follows:

element.addEventListener(<event-name>, <callback>, <use-capture>);

The meaning of each argument is:

  • event-name – A string representing the name or type of event that you would like to listen for.
  • callback – A function that is invoked whenever the event fires.
  • use-capture – A Boolean declaring whether the callback should be fired in the capture phase. This is when the event flows from the document’s root to the target.

Unfortunately, IE8 and its predecessors don’t adhere to this model. Instead they provide an alternative attachEvent() method for the same purpose. Whether or not you choose to support these older versions of IE is up to you, and depends on your visitor metrics. You should weigh the cost of supporting older browsers against the benefits this will bring. In this particular case, it’s a matter of using a simple polyfill, so supporting IE8 is not a big deal. The following code sample shows how the select element’s change event is handled across all browsers.

Within the switchStyles() function, it’s important to note that this refers to the element that triggered the event (in this case the select element). Consequently, this.options will give us access to the select element’s option elements, and this.options[this.selectedIndex] will give us access to the currently selected one. From there it is simple to access the option‘s value attribute.

Also notice that the code uses a console.log(), instead of an alert(). This is done because an alert() blocks the UI, and needs to be dismissed before JavaScript execution can resume. In this example that’s not too bad, but in more complex cases (such as examining the elements of a sizable array), this approach can be very ugly. If you are unsure about how to open your browser’s console, you can find out here. If you would like to learn a little more about using the console for JavaScript debugging, you can do so here.

Changing Styles

Now it’s time to add some simple styles to our page which the user will be able to choose between. Add the following CSS code to your project:

/* High contrast */
body.high-contrast{
    background-color: DarkBlue;
    color: yellow
}

body.high-contrast h1{
    text-shadow: none;
}

/* Print */
body.print h1{
    text-shadow: none;
}

body.print img{
    display: none;
}

When a user selects a different style from the drop-down, we’re going to apply the appropriate class directly to the body, removing all other classes:

function switchStyles() {
  var selectedOption = this.options[this.selectedIndex],
      className = selectedOption.value;

  document.body.className = className;
}

At this point, we have a fully functional style switcher, as shown in the following demo:

Working at the Sheet Level

Swapping out class names serves us well for this demonstration. However, if you are dealing with a larger number of styles, it is preferable to put them in external style sheets. You can then swap out the style sheets instead of individual classes. The following code, which assumes a single style sheet per page, shows how this is done.

function switchStyles() {
  var linkTag = document.getElementsByTagName('link')[0],
      currentStylesheet = linkTag.href.replace(/^.*[\\\/]/, ''),
      newStylesheet = this.options[this.selectedIndex].value + '.css';

  linkTag.href = linkTag.href.replace(currentStylesheet, newStylesheet);
}

Remembering User Preferences

At this point, we have a functional style switcher. Unfortunately, when the page is reloaded, any changed styles will be lost. To circumvent this problem we will use client-side storage to save the user’s preferences. We can then restore these preferences each time the page is loaded.

There are a variety of client-side storage technologies available to choose from. You can find a good overview of them in the article, HTML5 Browser Storage: the Past, Present and Future. For the purposes of this example, we’re going to use local storage. Local storage enjoys wide browser support and provides us with up to 5MB of persistent storage. And, unlike cookies, the information stored in local storage is never transferred to the server. If you do need to support ancient browsers (poor you), there are polyfills available to make your life easier. Also, please note that some browsers, such as IE8, don’t support local storage with the file:// protocol.

The basic syntax of local storage is shown below.

// is localStorage available?
if (typeof window.localStorage != 'undefined') {
    // store
    localStorage.setItem('hello', 'Hello World!');
 
    // retrieve
    console.log(localStorage.getItem('hello'));
 
    // delete
    localStorage.removeItem('hello');
}

To implement this on our page, we’ll need to save the user’s preferred styles every time the value of the select element changes:

localStorage.setItem('bodyClassName', className);

We’ll also need to check for the presence of this key value pair on page load and, if we find them, set the body’s class name accordingly. We can do this by first attempting to retrieve the key value pair:

// this will be null if not present
var storedClassName = localStorage.getItem('bodyClassName');

If the item is present, we can iterate over the select element’s options and compare their value to what we have retrieved from local storage. If they match, then we can set our select element’s selected index property accordingly:

if (storedClassName) {
  for(var i = 0; i < styleSwitcher.options.length; i++){
    if (styleSwitcher.options[i].value === storedClassName){
      styleSwitcher.selectedIndex = i;
    }
  }
}

The following demo incorporates these changes.

We can now change the styles via the dropdown menu. Additionally, when we refresh the page, the drop-down menu is restored to the previous selection. However, on reload, the styles don’t change to match those of the drop-down selection. What gives?

Well, when we alter the select element programatically, the event handler attached to it is not executed. Let’s remedy that with our own trigger function:

function trigger(action, el) {
  if (document.createEvent) {
    var event = document.createEvent('HTMLEvents');

    event.initEvent(action, true, false);
    el.dispatchEvent(event);
  } else {
    el.fireEvent('on' + action);
  }    
}

We can pass this function an action we would like to trigger, as well as an element to trigger it on. The function then checks if the browser responds to document.createEvent() (which all modern, standards-compliant browsers do). If so, then it uses dispatchEvent() to trigger the action. Otherwise, it reverts to using fireEvent(). You can read more about creating custom events in this article: How to Create Custom Events in JavaScript

The final piece of the puzzle is to add this line of code:

trigger('change', styleSwitcher);

After adding this line, the final code is shown in the following demo.

Conclusion

This tutorial has shown you how to allow your users to customize parts of the page. You have also learned how to remember your users’ preferences in order to enhance their overall experience of your site. Used correctly, this is a powerful technique which can make your site stand out from the crowd. I’d be interested to hear if you are employing this technique in the comments, along with any success (or horror) stories.

Free book: Jump Start HTML5 Basics

Grab a free copy of one our latest ebooks! Packed with hints and tips on HTML5's most powerful new features.

  • http://www.blueliquiddesigns.com.au/ Jake Jackson

    I don’t deny jQuery would certainly be simpler to use, but why load a whole library if you don’t need to? This vanilla javascript approach is a great lightweight alternative.

    • ckdesign

      That argument is ridiculous, people wrote libraries for a reason, so they don’t have to write getElementByID and other redundant calls twenty bazillion times.

      If you are using JavaScript on your site you’re probably using the library for a lot more then swapping out a css documents.

      The next argument I usually here from ‘vanilla-ists’ is, “but you can just make your own library for the simple calls that you do use.” That sounds like a great idea until you realize how much of a pain in the butt it is to maintain your wild west library. That’s all well and good for a personal website, but if you are working for anyone else but yourself it is a bad idea because your scripting needs will very from project to project and instead of starting that library over from scratch, you’ll add on to it, then some day you’ll have a mess on your hands and you’ll have the urge to rewrite it. That’s healthy and educational but it also wastes time and money, clients shouldn’t have to pay for pet projects.

      The better advice to give someone is ‘there are lighter weight libraries then jQuery that are worth learning too’. I would whole hardheartedly accept that, but coding ‘vanilla’ is bad advice when you get into MVCs and the like. If C# and Java developers are not embarrassed to use third party libraries that help them program faster, then why should we fall back to vanilla?

      Seven years ago people got this revolutionary idea in their heads that they should start working together and make nice libraries that are more universal or more specialized for specific types of projects. I don’t want to relive the 2000′s in the from of a client that paid for something brand new two months ago that doesn’t quite work, only for me to find out the previous developer decided to use some obscure mess of a personal library to make the project, just because ‘jQuery is FAT and bloated!’

      There is no good reason to go back to vanilla, there are many more reasons why using a popular, well maintained libraries are better then writing vanilla, and we shouldn’t be ashamed of using libraries no mater if it’s jQuery or a lighter weight alternative.

      • http://www.blueliquiddesigns.com.au/ Jake Jackson

        I would point out your argument is equally ridiculous, but based on your response you would take no notice anyway and continue with your single-view resolve.

        • ckdesign

          If you have nothing to contribute then of course I will keep my view, because you haven’t really given me examples of how my argument is flawed.

          Elaborate, expand my view..

  • Aw555000

    Thanks, I’m currently in the middle of a complete redesign which will be a lot less headache inducing lol

  • Señor Naugles

    The sad thing here is that browsers are supposed to provide a native way for users to select from different developer-provided style sheets. Netscape did this and Firefox used to. But I think they got rid of it. I had coded some sites years ago to allow users to select different style sheets but they didn’t know about the native browser capability which allowed this. Tragically, many developers also did not know about it.