A List Apart

Menu
Issue № 136

A Backward Compatible Style Switcher

by Published in CSS, JavaScript, Accessibility, Usability

In ALA Issue 126, Paul Sowden famously introduced the joys of alternate Style Sheets per W3C specs. Not content to elucidate theory, Sowden devised a compliant Style Sheet Switcher built with a few lines of JavaScript, and presented it to ALA’s readers and the entire design /  development community as an Open Source gift.

Article Continues Below

That was cool – really neat actually – and fit perfectly into the vision of an accessible web. When the article broke, I was building a new site and wanted to include this gadget, but I faced two problems:

  1. I’m incapable of directly copying someone else’s code.
  2. I had also had the idea rumbling about in my head of writing my own Style Switcher – and I believed I could make it work even in Netscape Navigator 4.

A Style switcher that works in Netscape 4?

Ridiculous! Impossible! Why on earth would you want to? Go back to your cave, Neanderthal!

All these responses are valid, but I have a peculiar angle on the situation. I do all my web design, however impractical it sounds, using CSS layout that displays reasonably well in Netscape 4. And I saw no reason to change now.

I also thought the goal interesting – the benefits and shiny newness of Style Sheets implemented so simply and fundamentally that even poor NN4 could understand.

Keeping it simple

The finished product has only two JavaScript components: the part that picks a Style Sheet according to the cookie, and the function that sets the cookie. Then the HTML form that calls the function. It’s amazingly straightforward, using old–style programming and ridiculously few lines of code. It will, however, require you to customize it to suit your site.

Loading the style

The concept that drives this style switcher is that the link tag for the Style Sheet will be printed into the document as it loads. The JavaScript code will therefore have to be included in the <head> of each page of the site. It is useful then to simply embed a single JavaScript file per site like so:

<script language="JavaScript" type="text/JavaScript" 
src="../includes/script.js"></script>


The JavaScript code in the <head> will call the document.write() function and then submit the tag as a string:

document.write('');

As this is a JavaScript command for writing tags into the document as it is being loaded, we can control it depending on which Style Sheet we want to use. This requires a separate “if” statement for each style sheet available. (You might be able to build this into a loop, but with fewer than five style sheets, it may not be worth it.) We will also want to include a default Style Sheet to use if a choice isn’t specified:

if(***choose style1***)
  
document.write('<link rel="stylesheet" type="text/css" href="../includes/style1.css">\n');
	else if (***choose style 2***)
  
document.write('<link rel="stylesheet" type="text/css" href="../includes/style2.css">\n');
	else document.write('<link rel="stylesheet" type="text/css" href="../includes/style0.css">\n');


For the conditional statements deciding which Style Sheet will be used, we want to search for a cookie. Here we will use a cookie called, funnily enough, “style,” and will assume that it has been set equal to “1” for Style Sheet “style1.css” and so on.

The statement to be evaluated then will look something like document.cookie.indexOf(‘style=1’)>=0 and the entire code in the <head> will be adjusted accordingly.

if(document.cookie.indexOf('style=1')>=0) 
  
document.write('<link rel="stylesheet" type="text/css" href="../includes/style1.css">\n');
	else if (document.cookie.indexOf('style=2')>=0)
  
document.write('<link rel="stylesheet" type="text/css" href="../includes/style2.css">\n');
	else document.write('<link rel="stylesheet" type="text/css" href="../includes/style0.css">\n');

That’s all you need. Two lines of code (possibly even one) per alternate Style Sheet and one for a default Style Sheet… and the style switcher itself.

Set the Cookie

We need a function to set a cookie and a form to call it.
First the function (again, remember that lines in the example below wrap to fit ALA’s format):

function chooseStyle (newstyle){
  
	var expdate = new Date();
	  
	expdate.setTime(expdate.getTime() + (1000*3600*24*365));
	  
	document.cookie = 'style=' + newstyle + '; expires=' + expdate.toGMTString() + '; path=/';
	  
	alert ('This style choice will persist for a year unless changed again.\n You may need to reload the page.');
	  
	self.location = self.location;
  
}

As an argument, it accepts the number or name of the style sheet that is tested for in the <head> JavaScript. The second two lines calculate the expiry date of the cookie by taking today’s date in milliseconds and adding a year to it. The next line simply adds it all together and sets it as a cookie: the name, value and expiry date and the domain that it applies to (in this case the root domain). The next line is optional; it tells the visitor what is happening. The last line reloads the page and gives the code we put in the <head> a chance to pick up on the change. Sometimes this will not reload entirely and needs to be manually reloaded – thus the popup message.

The form is also remarkably basic (it would have to be, for NN4). A simple button for each Style Sheet calls the cookie – setting function and gives it a value. (If you use names, you would have to enclose the arguments in quotation marks as strings. Using numbers is slightly simpler.)

<form action="">
  
	<input type="button" value="Old Style" onClick="chooseStyle(0);"><br>
	  
	<input type="button" value="Big Style" onClick="chooseStyle(1);"><br>
	  
	<input type="button" value="Invert Style" onClick="chooseStyle(2);">
  
</form>

That’s it. Truly. A few lines to print the tag, a function to set a cookie and a form to name it.

The rest is optional and depends on want you want. Feel free to play around and see what works and what doesn’t. A few options you might want to consider are listed below. Each one is a slight variation on the <head> code, no changes to the function or the form.

Excluding Feeble Browsers

If you don’t want the feeble browsers to be able to switch Style Sheets (for their own good, of course) but you want to use this Style Sheet switcher purely because of the fewer lines of code, there is a solution. Simply have the first line of code in the <head>, test for feeble browsers and shunt them off to a limited Style Sheet.

The following conditional statement tests for the existence of the getElementById function, a technique borrowed from webstandards.org.
Use your own browser sniffer if you feel like it.

if(!document.getElementById) document.write('<link rel="stylesheet" type="text/css" href="../includes/stylenn.css">\n');
	
	else if(document.cookie.indexOf('style=1')>=0) document.write('<link rel="stylesheet" type="text/css" href="../includes/style1.css">\n');
	
	else if (document.cookie.indexOf('style=2')>=0) document.write('<link rel="stylesheet" type="text/css" href="../includes/style2.css">\n');
	
	else document.write('<link rel="stylesheet" type="text/css" href="../includes/style0.css">\n');

Including Feeble Browsers

If you want feeble browsers to be able to switch Style Sheets for font and color purposes, but are worried they won’t be able to handle the CSS layout, there is another solution: create a feeble and non–feeble Style Sheet for each look. Then test for each of the two different scenarios:

if(!document.getElementById && document.cookie.indexOf('style=1')>=0) document.write('<link rel="stylesheet" type="text/css" href="../includes/feeblestyle1.css">\n');
	
	else if(document.cookie.indexOf('style=1')>=0) document.write('<link rel="stylesheet" type="text/css" href="../includes/style1.css">\n');
	
	else if (!document.getElementById && document.cookie.indexOf('style=2')>=0) document.write('<link rel="stylesheet" type="text/css" href="../includes/feeblestyle2.css">\n');

	else if (document.cookie.indexOf('style=2')>=0) document.write('<link rel="stylesheet" type="text/css" href="../includes/style2.css">\n');
	
	else if (!document.getElementById && document.cookie.indexOf('style=0')>=0) document.write('<link rel="stylesheet" type="text/css" href="../includes/feeblestyle0.css">\n');

	else document.write('<link rel="stylesheet" type="text/css" href="../includes/style0.css">\n');

W3C standards after all

Paul Sowden pointed out in his article that MSIE/Win doesn’t yet offer a menu option for switching between alternate style sheets according to W3C specifications. Mozilla (my browser of choice) does offer this option in the view menu. Of course, changing the style sheet from the menu doesn’t carry across your entire site (no cookie), but it does follow W3C guidelines. The style switcher we have been building however does not use the W3C specs for multiple style sheets and does not take advantage of the small group of mozilla browsers that would be able to use the “View > Use Stylesheet” menu option. Did you guess? There IS a solution!

Simply expand the lines of code to be written into the document for each option:

if(document.cookie.indexOf('style=1')>=0) document.write('<link rel="stylesheet" type="text/css" href="../includes/style1.css">\n' + '<link rel="alternate stylesheet" type="text/css" href="../includes/style2.css" title="second">\n' + '<link rel="alternate stylesheet" type="text/css" href="../includes/style0.css" title="default">\n');
	
	else if (document.cookie.indexOf('style=2')>=0) document.write('<link rel="stylesheet" type="text/css" href="../includes/style2.css">\n' + '<link rel="alternate stylesheet" type="text/css" href="../includes/style1.css" title="first">\n' + '<link rel="alternate stylesheet" type="text/css" href="../includes/style0.css" title="default">\n');
	
	else document.write('<link rel="stylesheet" type="text/css" href="../includes/style0.css">\n' + '<link rel="alternate stylesheet" type="text/css" href="../includes/style1.css" title="first">\n' + '<link rel="alternate stylesheet" type="text/css" href="../includes/style2.css" title="second">\n');

Is this thing on?

I’ve nothing else to say, but this spot cries out for a concluding message. I could wish you luck in customizing this style switcher for your personal use. I could encourage you to play around and learn what will and won’t work on your own. I could mention that one manifestation of this style switcher is used on the Westdale Secondary School site, and might even be so bold as to ask you to email me if you like. Else, all the above.

No Comments

  1. Sorry, commenting is closed on this article.