spacer

The web professional's online magazine of choice.

Stuff and Nonsense: Strategies for CSS Switching

Got something to say?

Share your comments on this topic with other web professionals

In: Articles

By Christopher Schmitt, Mark Trammell, Ethan Marcotte, Todd Dominey, Dunstan Orchard

Published on July 18, 2005

We wish we had some kung fu–esque robes handy. This is the chapter where we tell our dear readers to forget all that we have taught them about CSS so far, to look beyond the surface of the pool and discover the truth within the truth . . . or something like that.

Honestly, we’re more fun at parties than we might seem.

After seven chapters, it’s worth remembering that as convenient as it is to site designers, cascading style sheets can also drastically improve the online experience for the users of our sites. In Chapter 2, you saw briefly how the cascade was written with our users’ needs in mind, that user style sheets are ultimately given precedence over the author style sheets we write. The authors of the specification didn’t do this to spite those that design for the Web, but rather to empower those who read it.

After all, the true wonder of the Web is its promise of universal access: an avenue through which a user can gain instant and complete entry to any topic, from anywhere in the world. In fact, much of the mantle we don as Web designers is to realize that promise—to make sites that are at once visually compelling and with an interface that presents no barrier to entry.

However, we’ve slowly come to realize that our understanding of our audience has been incomplete at best. While we focused on setting the type on our pages 9 pixels high in the early days of the Web, our development was focused on having sites “look right” on contemporary desktop browsers. But in recent years, our understanding of our users’ needs has matured. People with physical, hearing, visual, or cognitive disabilities have always been using our sites; it’s just taken us some time to realize it. So, it’s only in recent years that our definition of “accessibility” has flowered, and our site-building techniques have followed suit.

While some designers may tell you that building an accessible site means building a boring site, we’d fling their pooh-pooh right back at them. Accessibility isn’t about larger fonts and creating high-contrast guidelines. Some users of the Web can read only smaller texts, while others can see only yellow text on a black background. Rather, many of the design techniques explored throughout this book—semantic, well-structured markup, a separation between content and presentation—can and will afford us incredible leverage in building professional, inspiring designs and simultaneously improve the accessibility of our sites for all of our users, not just a select few. In short, we can better realize the Web’s potential for universal access, and make some ultra-sexy sites to boot.

Ultimately, this chapter is not a manifesto on accessibility, space allotments and our meager skills being the largest impediments. Instead, we will explore different techniques for democratizing our design through the use of style sheet switching. By applying a different CSS file to a markup document, we can drastically change any or all aspects of its design—the layout, typography, or color palette. This technique may hold incredible appeal to designers because it exponentially decreases the amount of overhead required to redesign a site. But, as you’ll see, this technique can wield incredible benefits to our site’s users, allowing them fine-grained control over a page’s presentation and, in turn, better access to the content therein. After all, it’s about throwing the gates as wide open as possible.

Let’s dive right in.

Laying the Foundation

As with other chapters, let’s begin with a valid XHTML document. For the purposes of our style sheet switching experiments, the document in Listing 8-1 will do nicely.

Listing 8-1: The Markup Foundation for Our Style Switcher Experiments


<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="www.w3.org/1999/xhtml">
<head>

<title>Always offer an alternative.</title>

<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

</head>

<body>

<div id="container">
  <div id="content">
    <h1>Always offer an alternative.</h1>
    
    <p><span class="lead">Lorem ipsum dolor sit amet,</span> consectetuer adipiscing elit. Nullam tortor. Integer eros...</p>

    <p id="blurb">This is, as they say, a “pull quote.”</p>

    <p>Donec id nisl...</p>

    <h2>Additionally, you might consider...</h2>

    <p><img src="/img/spacer.gif"> 

By now, this sort of markup should, we hope, feel rather old hat to you. The markup is simple, yet well meaning, with proper heading elements (h1 and h2) applied to suit their position in our (admittedly nonsensical) document’s outline. Paragraphs have been marked up as such via the <p> element, with one earmarked with an id of “blurb” so that we might later style it differently than its siblings. And just to spice up the layout a bit, we’ve included a pixel illustration of one of our authors. Sorry, no door prizes are available for guessing which one it is.

Figure 8-1 shows you just how humble our beginnings are.

Figure 8-1: Our unstyled XHTML document, partying like it’s 1994

And again, as always, we can apply a rough style sheet to this document, and slap a bit of mascara on that otherwise unimpressive wall of serifs. To begin, let’s create a new style sheet called core.css, and include the rules in Listing 8-2.

Listing 8-2: The core.css Style Sheet


/* default font and color information */
body {
  background: #FFF;
  color: #444;
  font: 62.5%/1.6em "Lucida Grande", Verdana, Geneva, Helvetica, Arial, sans-serif;
}
/* END default font and color information */

/* default link rules */
a {
  color: #C60;
}

a:hover {
  color: #F60;
  text-decoration: none;
}
/* END default link rules */

/* headings */
h1, h2 {
  color: #B61;
  line-em;
  font-weight: normal;
  font-family: Helvetica, Arial, Geneva, Verdana, sans-serif;
  margin: 1em 0;
  padding: 0;
}

h1 {
  .2em;
}
/* END headings */

/* container */
#container {
  margin: 0 auto;
  max-em;
}
/* END container */

/* content */
#content h2 {
  .2em;
  text-transform: uppercase;
}

#content p {
  .1em;
  line-.6em;
}

#content img.portrait {
  float: right;
  margin: 0 0 1em 1em;
}

#content span.lead {
  text-transform: uppercase;
}

#content #blurb {
  background: #FFC;
  border: 1px dotted #FC6;
  color: #000;
  .5em;
  line-.4em;
  padding: .5em;
  text-align: center;
}
/* END content */


Pardon us while we pause for breath—that was a bit of a rush, wasn’t it? Rather than adding a few selectors at a time and discussing the visual result, we’re taking a less Socratic approach in this chapter. The focus here is less upon the techniques the style sheet contains than upon the end result gained by switching them. After all, this CSS is merely a placeholder, one that could easily be replaced by your own efforts. With that, we won’t bother to preen over this one. However, following are a few techniques worth briefly describing.

With a better grip on some of the more clever points in our style sheet (as if that says much), we could easily paste this entire chunk of code into a <style type=“text/css”>…</style> block in the head of our document. Of course, that would muddy our markup with presentational information—and honestly, who wants to hunt down style information across a few hundred XHTML documents? That’s right, some call it “adhering to a strict separation between structure and style.” We call it “lazy.”

In either event, let’s create a second style sheet, and name it main.css; at the top of that new file, we’ll use the @import command to invoke our core.css file, like so:

@import url("core.css");

We’ve effectively created a “wrapper” style sheet—a CSS file that acts as a gateway to other style sheets. With this main.css file in hand, we can now include it—and with it, core.css—in our XHTML with one simple link element, placed in the head of our document:


<link rel="stylesheet" class="main.css" type="text/css" />

And voilà! Our rather plain-looking document suddenly gets a bit of personality in Figure 8-2.

Figure 8-2: Applying some basic styles to our XHTML makes it a bit more readable.

After creating this seemingly superfluous main.css file, there might be some head-scratching in the audience. But rest assured, there are some very good reasons for putting this file in place. Although it wasn’t designed as such, the @import rule is a kind of litmus test for a browser’s support of advanced CSS techniques. Legacy browsers that have broken CSS implementations don’t understand the @import rule, and will simply disregard it. This allows us to serve up high-octane style sheet rules to modern browsers, while such antiquated browsers as versions 4 and below of Netscape and Internet Explorer will simply ignore the style sheets that they wouldn’t otherwise understand.

An added benefit to this intermediary style sheet is that we can place multiple @import rules therein. This could come in handy if we needed to break our site’s presentation into multiple files (for example, one for layout, another for color, yet another for typography). Or even better, we can use this technique to manage our various CSS hacks, as we saw in Chapter 2. As you test the CSS in Listing 8-3, you may find that the different versions of Internet Explorer (both on the Macintosh and Windows platforms) break different aspects of the layout. While we could use a battery of style sheet hacks within our core.css file to serve up alternate property values to these browsers’ broken CSS implementations, Listing 8-3 shows how we might use our wrapper style sheet to include browser-specific CSS hack files, which allow us to keep our main.css file clean and hack-free.

Listing 8-3: A Revised core.css File, with Intelligent Hack Management


@import url("core.css");

/* Import WinIEx-only bugs - hide from Mac IE5 \*/
@import url("hacks.win.iex.css");
/* END hide from Mac IE5 */

/* Import Win IE5x hacks */
@media tty {
     i{content:"\";/*" "*/}} @import 'hacks.win.ie5.css'; /*";}
}/* */

/* Import Mac IE5 hacks */
/*\*//*/
@import url("hacks.mac.ie5.css");
/**/

We’ve already discussed the CSS hacks needed to get our page looking good in less-than–CSS-savvy browsers, and triaging the different hacks into browser-specific files is an excellent way to keep our core.css file clean and hack-free. If we ever decide to drop support for a certain browser, we now need to remove only a few lines from main.css—definitely a more appealing thought than scouring our primary style sheet rules line by line, looking for CSS hacks. Again, it’s equal parts “strategic” and “lazy” here at CSS Best Practices Headquarters.

Now that we’ve put our CSS and XHTML firmly in place, we can delve into the mechanics of style sheet switching.

CSS Switching

One fault of our page’s current design is that legibility wasn’t one of our guiding design goals. The contrast is a bit light, as we opted to use a near-black color for the text against the body’s white background. And the default font size of 62.5 percent of the browser’s default (or roughly 10 pixels) might be difficult to read for users suffering from visual impairments. (Even a reader with slight myopia might have to work at reading our content.) How can we improve the design to make it more legible, without sacrificing our original vision?

To begin, let’s create a separate style sheet that addresses some of these possible pitfalls. In Listing 8-4, we’ve created a new CSS file named contrast.css.

Listing 8-4: The contrast.css Style Sheet


body {
  background: #000;
  color: #DDD;
}

h1, h2 {
  color: #FFF;
  font-weight: bold;
}

#content {
  .1em;
}

#content h2 {
  .6em;
  text-transform: none;
}

#content #blurb {
  background: #222;
  border-color: #444;
  color: #FF9;
}

span.lead {
  font-weight: bold;
}

Now let’s simply add a link to our new contrast.css file in the head of our markup, like so:


<link rel="stylesheet" class="main.css" type="text/css" /> 
<link rel="stylesheet" class="contrast.css" type="text/css" />

When we reload the document in our browser, Figure 8-3 shows us that the landscape has changed pretty drastically.

Figure 8-3: Now we’re on our way, as we’ve added a supplementary style sheet that provides heightened contrast and an increased font size.

First and foremost, it’s worth mentioning that because the two CSS files are being included in tandem, we don’t need to use contrast.css (Listing 8-4) to re-declare any of the layout or type rules established in main.css. Rather, we can simply selectively override individual rules and/or property values, and let the rules of specificity handle which rules cascade to the user.

From a purely aesthetic point, we’ve instantaneously changed the presentation of our markup—and all by including the new contrast.css file. The off-black text has been replaced with pure white, the text size has been increased very slightly (from 1em to 1.1em), and the colors on our pull quote have been changed to reflect the new palette. The completed effect feels much more nocturnal—but more important, we’ve created a style sheet that allows users to enjoy a higher level of contrast, as well as a slightly more legible type size.

But we’ve still not settled our original problem. How do we switch between the two style sheets? We grew pretty attached to that white, open design—it would be a real shame to lose it, wouldn’t it?

Oh, at least pretend it’s pretty. Please?

The Mechanics: How It’s Supposed to Work

Thus far, we’ve associated two separate CSS files with one document. Currently, they’re both being read and applied to the document with equal weight, with the rules of specificity resolving any conflicts that may arise between the two. However, to accommodate more complex scenarios than the one we currently have, the HTML and CSS specifications outline structured guidelines for how multiple style sheets interact. Web page authors are given a number of ways to prioritize the style sheets we include via the link element. Let’s examine the three different classes of style sheets (no pun intended), and see how they might apply to our switching scenario.

Persistent Style Sheets

Persistent style sheets are always enabled. Think of them as CSS that is “turned on” by default. The persistent CSS file will be applied in addition to any other style sheets that are currently active, and acts as a set of shared style rules that every other style sheet in the document can draw upon.

Each link element with a rel attribute set to “stylesheet” is a persistent style sheet—and, in fact, we’ve created two already:


<link rel="stylesheet" class="main.css" type="text/css" />
<link rel="stylesheet" class="contrast.css" type="text/css" />

As we add additional kinds of style sheets, any links that we designate as persistent will act as the baseline, sharing their rules with all other included CSS files.

Preferred Style Sheets

By adding a title to a persistent style sheet, we can designate a style sheet as preferred, like so:


<link rel="stylesheet" class="main.css" type="text/css" /> 
<link rel="stylesheet" title="Higher Contrast" class="contrast.css" type="text/css" />

Additionally, we can specify multiple “groups” of preferred style sheets by giving them the same title attribute. This allows the user to activate (or deactivate) these groups of CSS files together. Should more than one group be present, the first group will take precedence.

Much as with persistent style sheets, preferred CSS files are enabled by default. So, in the previous example, our contrast.css file (refer to Listing 8-4) would be enabled when the user first visits our page (borrowing, as it did before, from our persistent main.css file). However, preferred style sheets are disabled if the user selects an alternate style sheet.

Alternate Style Sheets

An alternate style sheet can be selected by the user as, well, alternatives to a CSS file marked as preferred by the site’s author. To designate a link as an alternate style sheet, it must be named with a title attribute, and its rel attribute set to “alternate stylesheet”. As with preferred style sheets, we can group links together by giving them identical title attributes. So, in short, this is what we’ve been looking for—a means through which we can allow users to select the design that best suits their needs. If we do, in fact, want main.css to be the default and contrast.css to be an optional, alternate CSS file, then we should update our two link elements to match:


<link rel="stylesheet" class="main.css" type="text/css" />
<link rel="alternate stylesheet" title="Higher Contrast" class="contrast.css" type="text/css" />

Now, viewing the page in a browser that supports style sheet switching, the user can finally control the display of the page. Browsers such as Firefox or Opera include an option to select our new alternate style sheet, as shown in Figure 8-4.

Figure 8-4: By changing the rel attribute of the second link element to “alternate stylesheet” and supplying a title, we’ve implemented some basic style switching.

Once the user selects Higher Contrast from the menu, the alternate style sheet with that title—namely, contrast.css—becomes active. So, we’ve finally settled on the solution we were looking for. Our original design is the active default, but we’ve created the means through which users can select another design altogether. Using this method, we can add even more alternate CSS options. Let’s create a file named hot.css and use the rules in Listing 8-5.

Listing 8-5: The hot.css Style Sheet


body {
  background: #000 url("bg-stylish.jpg") no-repeat 50% 0;
  color: #DDD;
}

h1, h2 {
  color: #FFF;
  font-weight: normal;
  text-align: center;
  text-transform: none;
}

#content {
  .1em;
}

#content h1 {
  font: 2.6em Zapfino, "Gill Sans", Gill, Palatino, "Times New Roman", Times, serif;
  margin: 200px 0 70px;
}

#content h2 {
  font: 1.6em "Gill Sans", Gill, Palatino, "Times New Roman", Times, serif;
  margin: 1.4em 0;
  text-transform: uppercase;
}

#content #blurb {
  background: #222;
  border-color: #444;
  color: #FF9;
}

span.lead {
  font-weight: bold;
}

And now, by applying what we’ve learned about alternate style sheets thus far, we can easily present hot.css (refer to Listing 8-5) to our users as another user interface option:


<link rel="stylesheet" class="main.css" type="text/css" />
<link rel="alternate stylesheet" title="Higher Contrast" class="contrast.css" type="text/css" />
<link rel="alternate stylesheet" title="Gratuitous CSS" class="hot.css" type="text/css" />

If our users have the ability to select another alternate CSS file from their browsers, then they’ll be able to see our new styles as shown in Figure 8-5. And, as before, the change is a fairly drastic one—but we’ve finally allowed the users to choose an appealing design and tailor our content to meet their needs.

Figure 8-5: With our understanding of how the cascade works, we can build even more complexity into our alternate CSS documents.

Another Solution We (Almost) Can’t Quite Use

As with some of the most promising features of CSS, adoption of alternate style sheets would be more widespread if browser support were more robust. As of this writing, the number of browsers that natively allow users to select alternate style sheets is limited to Gecko-based browsers such as Mozilla or Firefox, and the Opera browser. For example, Apple’s Safari has no way to select alternate or preferred style sheets. And, you guessed it, Internet Explorer (the browser known and loved the world over) won’t allow users to select the alternate user interfaces we build for them. If the world’s most popular browser keeps this feature out of the hands of our users, then we have a bit more work to do yet.

Furthermore, the browsers that do natively support alternate style sheet switching have only a limited switching functionality. While these browsers do allow the user to easily switch between the default CSS and any alternates provided by the author, they do not remember the user’s selection. This means that, if a reader selects an alternate style sheet and then reloads the page or leaves and returns to it, the browser will forget the earlier choice and reinstate the default style.

Obviously, neither of these scenarios will work for our users. We’re lucky that there are some additional steps we can take to bring the full benefits of CSS switching to them.

The Reality: How It Can Work Today

We’ve established that most of our audience won’t be able to use in-browser CSS switching (and identified those who don’t have much functionality available to them) so we must build an interface into our page that allows users to overcome these limitations. Now, you might realize that the two client-side technologies we’ve been studying up to this point aren’t especially well equipped to handle this. While XHTML and CSS excel at describing and styling content, respectively, neither was designed to interact with the user. Sure, we can use XHTML to build a list of links on the page as follows:


<div id="switcher">
  <ul>
    <li id="style-default"><a class="styleswitch.html">Default style</a></li>
    <li id="style-contrast"><a class="styleswitch.html">Higher Contrast</a></li>
    <li id="style-hot"><a class="styleswitch.html">Gratuitous CSS</a></li>
  </ul>
</div>

And we can add some CSS to core.css (refer to Listing 8-2) to style them accordingly, as shown in Figure 8-6:


/* switcher styles */
#switcher ul {
  text-align: right;
  list-style: none;
}

#switcher ul li {
  border-left: 1px solid;
  list-style: none;
  display: inline;
  padding: 0 0 0 1em;
  margin: 0 1em 0 0;
}

#switcher #style-default {
  border-left: 0;
  padding-left: 0;
}

#switcher ul a.now {
  color: #000;
  font-weight: bold;
  text-decoration: none;
}
/* END switcher styles */

Figure 8-6: We’ve added the links for our switcher to the top of our page, but all they can do at the moment is look pretty—and we’re about to change that.

However, what happens when the user clicks on those links? If your answer was something akin to “zilch,” then you win the blue ribbon. XHTML and CSS can’t really do anything when you’re talking about responding to a user’s actions. They can, in turn, affect the content and the presentation of the page, but when the user tries to click a link to change the active style sheet, that’s where we need to turn to the third tool in the standards-savvy designer’s toolkit: JavaScript.

Jumping on the JavaScript Bandwagon

To put it simply, JavaScript was created as a client-side scripting language. JavaScript (or JS, to use the parlance of lazy typists everywhere) is a language designed to add a layer of interactivity into our Web pages. When a user visits a Web page that has some JavaScript code in it, the browser reads the JS, and then follows any instructions that might be contained therein. Those instructions might tell the browser to display helpful messages to a user as he or she completes a form, or to perform basic validation on the data he or she enters there. We can even use JS to instruct the browser to perform a certain action when the user clicks a link. In short, JavaScript is the means through which we bridge the divide between our content and our users, allowing the latter to fully interact with the former.

Sounds intimidating (and more than a little stuffy), doesn’t it? Perhaps it’d be best to just dive right in.

Gathering Requirements

Before we begin a lick of coding, we should make sure that we understand exactly what it is that we’re building. Just as we discussed the benefits of requirements gathering to a client project in Chapter 1, the smallest development gig can benefit from some sort of needs analysis. With a better understanding of what we need to build and the goals it should achieve, we can code more quickly and efficiently—two qualities that will make our clients and us quite happy.

So let’s take a quick inventory of what we’re working with:

  • We have three link elements in the head of our XHTML document that include screen-specific CSS files: a persistent style sheet (main.css), and two alternate style sheets (contrast.css in Listing 8-4 and the ultra-swank hot.css in Listing 8-5).
  • Accordingly, at the top of our document we’ve created a list of three anchors, each corresponding to a different style sheets. Granted, these anchors are about as useful as a road map in the desert, but we’re going to change that shortly.

With this in mind, what exactly should our function do? Ideally, when a user clicks a link:

  1. The function should cycle through each of the link elements in the head of our XHTML, and inspect those that link to style sheets and have a title.
  2. If the link matches the link that the user selected, then it should be set to be the “active” CSS.
  3. Otherwise, the link should be set to “disabled,” which will prevent the browser from loading the style sheet.
  4. Once the function has finished setting the active link element, it should remember the user’s choice. The style sheet the user selected will, therefore, remain “active” as the user browses through the site, and the choice will be remembered if the user returns to our site during a later browsing session.

How, you may ask, will we do all of this? Well, the solution ultimately involves a fair amount of pixie dust and happy thoughts—but we shouldn’t get too far ahead of ourselves.

Building the Switching Function

With our goals firmly in mind, we can begin building our style sheet functions. Let’s create a new file called scripts.js, and include the following markup in the head of our XHTML document:


<script type="text/javascript" src="/img/spacer.gif"> 

Much as we’re using the link element to include external CSS files for our site’s presentation, we can use the script element to reference an external JavaScript file. And, in that file, we can write in the first lines that will power our CSS switcher. If JavaScript syntax looks a bit intimidating, don’t worry. We’ll simply touch on some of the highlights, and get back to that “Professional CSS” malarkey as quickly as possible.


// activeCSS: Set the active stylesheet
function activeCSS(title) {
  var i, oneLink;
  for (i = 0; (oneLink = document.getElementsByTagName("link")[i]); i++) {
    if (oneLink.getAttribute("title") && findWord("stylesheet", oneLink.getAttribute("rel"))) {
      oneLink.disabled = true;
      if (oneLink.getAttribute("title") == title) {
        oneLink.disabled = false;
      }
    }
  }
}

// findWord: Used to find a full word (needle) in a string (haystack)
function findWord(needle, haystack) {
  return haystack.match(needle + "\\b");
}

In this code snippet, we have two JavaScript functions, which are basically discrete chunks of functionality. The two functions we’re looking at here are activeCSS() and findWord(). Each function contains a series of instructions that are passed to the browser for processing. For example, when activeCSS is invoked, it performs the following tasks:

  1. It assembles a list of all link elements in our document (document.getElementsByTagName(“link”)), and proceeds to loop through them.
  2. For each link element found, it checks to see if there is a title available, and then evaluates the rel attribute to see if the word “stylesheet” is present. The findWord() function is used here to search the rel for a whole-word match only. This means that if someone accidentally types rel=“stylesheets” or the like into their link element, our function ignores them.
  3. Each link that meets the criteria in Step 2 will be disabled (oneLink.disabled = true;).
  4. When the function is first invoked, an argument (or variable) is passed with the title of the desired “active” style sheet. So, as the function loops through each of the link elements, it checks to see if the title of the link matches the title of the function’s argument. If so, the link element is reactivated.

Admittedly, this is a bit of a gloss of the functions’ syntax. JavaScript is a robust and rewarding language, but we’re nonetheless forced to breeze through some of its subtleties to get back on the CSS track. However, the preceding list demonstrates the high-level concepts at play in the code we’ve created, and should provide a fine starting point for those interested in further exploring JavaScript’s elegant syntax.

While these two functions enable us to switch our CSS, they simply lie dormant until they are invoked (or called) by our markup. Because we want our switcher to fire when a user selects a link from our #switcher list, the easiest place to do so is within the anchors of our style switcher list:


<div id="switcher"> 
 <ul>
  <li id="style-default"><a class="styleswitch.html">>Default style</a></li>
  <li id="style-contrast"><a class="styleswitch.html">>Higher Contrast</a></li>
<li id="style-hot"><a class="styleswitch.html">>Gratuitous CSS</a></li>
 </ul>
</div>

The onclick attribute we’ve introduced here is called an event handler. When the user performs a certain action or “event” (such as, in this case, a mouse click), the JavaScript contained in the attribute value is fired. So, in the preceding example, the onclick handler will detect when a user clicks on the anchor, and will in turn fire the activeCSS() function.

Strictly speaking, you could argue that use of these event handlers, such as onclick, onblur, onmouseover, and so on, is analogous to relying on the style attribute—that these inline attributes blur the separation of structure and behavior, and can easily increase the cost of maintenance and support. Rather than editing our XHTML to reflect any changes in the JavaScript, it would instead be possible to use more modern JS to automatically generate the event handlers our links will need, and, therefore, keep the necessary divide between our markup and our scripting. For more information, we recommend Peter-Paul Koch’s Separating behavior and structure.

However, as we look closely at the three different event handlers, we can see that each reference to activeCSS() differs slightly. Between the parentheses, we’ve included the title of the style sheet the link should activate. This is the argument we mentioned earlier and is the string of text that the activeCSS() function compares to the title of each link element.

You may have noticed that after the call to the activeCSS() function, the onclick handler contains some additional text: return false;. This plays a very small (but integral) part in our switcher because it tells the handler not to follow the URL referenced in the anchor’s href attribute. Otherwise, the user would end up deposited on styleswitch.html after clicking any of the links.

So, let’s do a bit of role-playing. Let’s just run through the steps that occur when we click a link. For argument’s sake (oh, aren’t we clever), let’s assume that our user selects the third anchor, the onclick handler that contains the activeCSS(‘Gratuitous CSS’); reference:

  1. The three link elements are compiled into an array, and the function proceeds to loop over each of them. Remember that only those links that contain titles and that have a rel attribute that contains the word “stylesheet” will be examined. This leaves us with the links for contrast.css (refer to Listing 8-4) and hot.css (refer to Listing 8-5).
  2. The first link element has a title of “Higher Contrast.” The function disables the link element. Because its title doesn’t match our function’s argument (“Gratuitous CSS”), it stays disabled.
  3. The second link element has a title of “Gratuitous CSS.” The function disables the link element. Because the title does match our function’s argument, the link is immediately reactivated.

And voilà! As you can see in Figure 8-7, we’ve completed the effect. Clicking each anchor activates the alternate style sheet whose title matches the one referenced in the activeCSS() function call.

Figure 8-7: With our JavaScript-enabled style switcher in place, our users can now select a look that best suits their needs.

However, even though we’ve successfully built a function to switch between the different CSS files, we’re only halfway there. If the user refreshes the page or leaves the current one after selecting a new alternate style sheet, the choice is forgotten, and the default style sheet is restored. So, obviously, we’ve a bit more work to do. Let’s see if we can’t put a little memory into our JavaScript functions.

Baking a JavaScript Cookie

As you’ve seen with our not-quite-finished CSS switcher, our browsers don’t seem to remember anything about a page once we’ve left or refreshed it. This is by design. The HTTP standard (which is the protocol over which the Web’s pages are transferred from a server to your desktop) was designed to be “stateless.” This means that each time you visit a page, the Web server considers it to be your first time, every time. Thankfully, we have a way to fill this memory gap. It’s called a cookie, and it’s less fattening than its baked namesake.

A cookie is a small text file that is sent by a Web server to a user’s browser, and contains small bits of important information about that user’s browsing session. Cookies may contain user preferences, registration information, or the items placed in an online shopping cart, and so on. Once it receives a cookie, the browser saves the information on the user’s computer, and sends it back to the Web server whenever the user returns to that Web site.

We’re not just flapping our gums here. We’re mentioning cookies because we can use JavaScript to set and read them. So, armed with this knowledge, we can finally see our way to the finish line. By adding a few more JavaScript functions to those we’ve already written, we can build an improved style sheet switcher, and one that will respect our user’s preferences across multiple pages, or visits to, our site.

From this, we need two tools in our cookie-baking toolkit (we can mix metaphors with the best of them). We need to be able to set a cookie containing our user’s style preference, and to then later read the cookie. So, let’s add a new cleverly named function to our scripts.js file, setCookie():


// Set the cookie 
function setCookie(name,value,days) {
 if (days) {
   var date = new Date();
   date.setTime(date.getTime()+(days*24*60*60*1000));
   var expires = ";expires="+date.toGMTString();
 } else {
   expires = "";
 }
 document.cookie = name+"="+value+expires+";";
}

And now, in our original activeCSS() function, we can add a single line to store our user’s preferences in a cookie on the user’s computer:


// Set the active stylesheet
function activeCSS(title) {
  var i, oneLink;
  for (i = 0; (oneLink = document.getElementsByTagName("link")[i]); i++) {
    if (oneLink.getAttribute("title") && findWord("stylesheet", oneLink.getAttribute("rel"))) {
 oneLink.disabled = true;
      if (oneLink.getAttribute("title") == title) {
         oneLink.disabled = false;
      }
    }
 }
 setCookie("mystyle", title, 365);
}

With this one line, half of our work is finished! The setCookie() function accepts three arguments: a name for the cookie (so that we might later reference it), the value to be stored in the cookie, and the number of days until the cookie expires. So, in the previous code snippet, we’ve created a cookie named “mystyle”, the value of which is set to the value of the title argument of activeCSS(). This means that if a user selects a link that specifies activeCSS(‘Higher Contrast’) in its onclick handler (that is, it invokes activeCSS with a title argument of Higher Contrast), then our “mystyle” cookie will, therefore, have a value of Higher Contrast.

In our setCookie() function, specifying the number of days until cookie expiration is optional. The latter argument is optional. In the preceding example, we’ve arbitrarily decided to set the “mystyle” cookie to expire in 365 days, or one calendar year. Because the argument is optional, we could leave it out entirely. However, omitting it will cause the setCookie() funct

gipoco.com is neither affiliated with the authors of this page nor responsible for its contents. This is a safe-cache copy of the original web site.