CSS style sheet switcher using Prototype

A recent project had a requirementfor a style switcher allowing a visitor to control font size on the site as needed. (Many do not know how to change it through a browser, and most sites are not designed to allow for font size changes without completely trashing presentation.)

Because the project in question was a dynamic site I wanted to make a style sheet switcher that didn’t force a page reload and it seemed like most examples on the net required a page to reload with a new stylesheet. (After PHP or some other scripting language decided which css sheet to render the page with.) This meant additional calls to the server to repopulate data grids and other info, after re-running a query and parsing in PHP. To me this was truly unacceptable load on a server to simply change font sizes on a page.


I found one example that looked attractive to me, so my solution was driven from what I found at http://www.fastfwd.be/journal/28/Prototype_CSS_stylesheet_switcher. However this example switched between two styles, and I wanted a small – medium – large switch.

You can view my sample HERE.

So, here we go:
First, I started by defining my style sheets:

site.css
 
body,html {
    margin: 0;
    font-family: Verdana, Arial, Helvetica, sans-serif;
    font-size: 100%;
    color: #000;
}
 
.header {
	font-size: 120%;
}
 
#head {
	width: 600px;
	height: 120px;
	padding: 15px;
}
 
/* Page Structure */
#styleSwitcher {
	float: right;
	position: absolute;
	top: 50px;
	left: 300px;
	height: 33px;
	width: 60px;
	background: url(images/style_switcher_small.gif); /* I also created a medium and large */
	background-repeat: no-repeat;
}
 
#styleSwitcher a {
	float: left;
	padding: 2px;
	width: 16px;
	height: 30px;
	text-decoration: none;
}

Now make two copies of this sheet, but change the font-size in the body,html portion of the sheet to be 90% and rename the background image for styleSwitcher to ‘medium’ in one (site_minux_10.css) and 110% and rename the background image for styleSwitcher to ‘large’ in the other (site_plus_10.css). I put all three style sheets in a directory appropriately named ‘styles’.

Second, I created an image that displayed the sizes in a meaningful way for the selector. I actually made three of them, so the style sheets would change it depending on which style sheet was selected.

CSS Selector Small
CSS Selector Medium
CSS Selector Large

I put these images into a directory named ‘images’.

Third, let’s get all of our magical Javascript ready for it’s task. We will need the Prototype framework, and a small bit of our own magic that uses it. You can download the newest version of Prototype HERE. (Please note that we are going to be using evalJSON(), so this means we need at least version 1.5.1 of the framework.)

Now we will put together own own script file:

main.js
 
Event.observe(window, 'load', function() {
	var valueElement = "rel";
	var browserName = navigator.appName;
 
	// define where the active style sheet needs to be changed
	var styleObj = $$('head link[type=text/css][rel=stylesheet]')[0];
 
	// create array of the links with class loadStyle
	$$('a.loadStyle').each(function(a) {
		// create observers for each link
		Event.observe(a, 'click', function(event) {
			// when a click happens and the rel element has a value
			if(a.hasAttribute(valueElement))
			{
				// create a JSON string out of the rel value for use
				var valueObj = new String('{'+ a.getAttribute(valueElement) +'}').replace(/(\\[|\\])/g, '"').evalJSON();
 
				// catch possible problem
				if(typeof valueObj.sheet == 'undefined') return alert('Sorry, no stylesheet defined'); false;
 
				// if no problem, change the style sheet
				if(typeof styleObj !== "undefined")
				{
					if(browserName == 'Microsoft Internet Explorer')
					{
						document.styleSheets[0].href = valueObj.sheet;
					}
					else
					{			
						styleObj.setAttribute('href', valueObj.sheet);
					}
				}
				else return alert('switchStyle: stylesheet definition not found on this page'); false;
			}
			Event.stop(event);
		}, false);
	});
});

I put both the Prototype and this file in a directory appropriately named ‘js’.

Fourth, we now are ready for the HTML that you can get from the download file or from the sample HERE.

Please note that in the HTML we are not defining all three stylesheets. I found that Internet Explorer did not like switching between the three stylesheets when they are all defined in the HTML, while Firefox happily accepted it. This causes a slight blip on the screen when switching to a style initially, but due to cache you do not need to load the same sheet twice.

Of course this will go into the root of the public_html.

Fifth, now that we have the switcher in place working fine wouldn’t it be nice if the site remembered what size the visitor selected? Of course it would! So here is how I implemented Cookies to remember:

In the main.js file I added a few small lines of code to our existing javascript, and added two functions borrowed from http://www.quirksmode.org/js/cookies.html for the actual cookie handling:

main.js -(new and improved with cookies)
 
Event.observe(window, 'load', function() {
	var valueElement = "rel";
	var cookieName = 'geekyStyles';
	var browserName = navigator.appName;
 
	// define where the active style sheet needs to be changed
	var styleObj = $$('head link[type=text/css][rel=stylesheet]')[0];
 
	// create array of the links with class loadStyle
	$$('a.loadStyle').each(function(a) {
 
		// base current style based on previous visit from cookie
		if(readCookie(cookieName))
		{
			var pastStyle = readCookie(cookieName);
 
			if(browserName == 'Microsoft Internet Explorer')
			{
				document.styleSheets[0].href = pastStyle;
			}
			else
			{			
				styleObj.setAttribute('href', pastStyle);
			}
		}
 
		// create observers for each link
		Event.observe(a, 'click', function(event) {
			// when a click happens and the rel element has a value
			if(a.hasAttribute(valueElement))
			{
				// create a JSON string out of the rel value for use
				var valueObj = new String('{'+ a.getAttribute(valueElement) +'}').replace(/(\\[|\\])/g, '"').evalJSON();
 
				// catch possible problem
				if(typeof valueObj.sheet == 'undefined') return alert('Sorry, no stylesheet defined'); false;
 
				// if no problem, change the style sheet
				if(typeof styleObj !== "undefined")
				{
					if(browserName == 'Microsoft Internet Explorer')
					{
						document.styleSheets[0].href = valueObj.sheet;
					}
					else
					{			
						styleObj.setAttribute('href', valueObj.sheet);
					}
 
					// set a 30 day cookie to remember the latest selection
					createCookie(cookieName, valueObj.sheet, 30);
				}
				else return alert('switchStyle: stylesheet definition not found on this page'); false;
			}
			Event.stop(event);
		}, false);
	});
});
 
// cookie functions by http://www.quirksmode.org/js/cookies.html
function createCookie(name,value,days)
{
	if (days)
	{
		var date = new Date();
		date.setTime(date.getTime()+(days*24*60*60*1000));
		var expires = "; expires="+date.toGMTString();
	}
	else var expires = "";
	document.cookie = name+"="+value+expires+"; path=/";
}
 
function readCookie(name)
{
	var nameEQ = name + "=";
	var ca = document.cookie.split(';');
	for(var i=0;i < ca.length;i++)
	{
		var c = ca[i];
		while (c.charAt(0)==' ') c = c.substring(1,c.length);
		if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
	}
	return null;
}

Viola! A completed Style Switcher using CSS, Prototype, HTML, and dabble of DOM.

To download all of the files for this, you can get them HERE.

Enjoy!

Published by

Adam

Application Architect from Florida

Leave a Reply

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