Creating a Simple Style Switcher
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.
See the Pen Simple Style Switcher (1) by SitePoint (@SitePoint) on CodePen.
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.
See the Pen Simple Style Switcher (2) by SitePoint (@SitePoint) on CodePen.
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:
See the Pen Simple Style Switcher (3) by SitePoint (@SitePoint) on CodePen.
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.
See the Pen Simple Style Switcher (4) by SitePoint (@SitePoint) on CodePen.
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.
See the Pen Simple Style Switcher (5) by SitePoint (@SitePoint) on CodePen.
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.