Previous Page
Next Page

Style Sheet Switcher

One of the most powerful uses of JavaScript is the ability to modify, on the fly, which style sheet is being used. For example, you can offer your site's visitors the ability to choose the style and size of the text on your site. Some people like to read tiny, sans-serif text that gets lots of words on the screen (Figure 14.10), while others prefer larger, serif text that's a bit more readable (Figure 14.11). Now you can make both kinds of visitors happy. And to make it even more useful, this script also uses cookies to store the user's choice for future visits.

Figure 14.10. Some visitors prefer to read smaller, sans-serif text that can get more text on the page.


Figure 14.11. Other visitors will be glad to choose larger, serif text that they find more readable.


To allow the user to switch between style sheets:

1.
<link href="sansStyle.css" rel="stylesheet" rev="stylesheet" title="default" />



Script 14.15 shows a standard link to bring in an external style sheet, with one new twist: it has a title attribute, "default". That comes into play later.



Script 14.15. This page has the content for the page and the user controls, and it calls the external style sheets that the user can choose.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
     <title>Style Changer</title>
     <link href="script06.css" rel="stylesheet" rev="stylesheet" />
     <link href="sansStyle.css" rel="stylesheet" rev="stylesheet" title="default" />
     <link href="serifStyle.css" rel="alternate stylesheet" rev="alternate stylesheet" 
title="serif" />
     <script src="script06.js" language="javascript" type="text/javascript"></script>
</head>
<body>
     <div class="navBar"><p>Change your font:</p>
        <form action="#">
           <input type="button" class="typeBtn" value="Sm Sans" id="default" />&nbsp;&nbsp;
           <input type="button" class="typeBtn2" value="Lg Serif" id="serif" />
        </form>
        <br clear="all" />
     </div>
     <p>Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean lacus elit,
 volutpat vitae, egestas in, tristique ut, nibh. Donec congue lacinia magna. Duis tortor
 justo, dapibus vel, vulputate sed, mattis sit amet, leo. Cras purus quam, semper quis,
 dignissim id, hendrerit eget, ante. Nulla id lacus eget nulla bibendum venenatis. Duis
 faucibus adipiscing mauris. Integer augue. In vulputate purus eget enim. Nam odio eros,
 porta vitae, bibendum sit amet, iaculis nec, elit. Cras egestas scelerisque pede. Donec a
 tellus. Nullam consectetuer fringilla nunc.</p>

     <p>Nam varius metus congue ligula. In hac habitasse platea dictumst. In ut ipsum a 
pede rhoncus convallis. Sed at enim. Integer sed metus quis est egestas vestibulum. Quisque
 mattis tortor a lorem. Nam diam. Integer consequat lectus. Donec molestie elementum nisl.
 Donec ligula sapien, volutpat eget, dictum quis, mollis a, odio. Aliquam augue enim,
 gravida nec, tempor ac, interdum in, urna. Aliquam mauris. Duis massa urna, ultricies id,
 condimentum ac, gravida nec, dolor. Morbi et est quis enim gravida nonummy. Cum sociis
 natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Mauris nisl
 quam, tincidunt ultrices, malesuada eget, posuere eu, lectus. Nulla a arcu. Sed
 consectetuer arcu et velit. Quisque dignissim risus vel elit.</p>

     <p>Nunc massa mauris, dictum id, suscipit non, accumsan et, lorem. Suspendisse non 
lorem quis dui rutrum vestibulum. Quisque mauris. Curabitur auctor nibh non enim. Praesent
 tempor aliquam ligula. Fusce eu purus. Vivamus ac enim eget urna pulvinar bibendum.
 Integer porttitor, augue et auctor volutpat, lectus dolor sagittis ipsum, sed posuere
 lacus pede eget wisi. Proin vel arcu ac velit porttitor pellentesque. Maecenas mattis
 velit scelerisque tellus. Cras eu tellus quis sapien malesuada porta. Nunc nulla. Nullam
 dapibus malesuada lorem. Duis eleifend rutrum tellus. In tempor tristique neque. Mauris
 rhoncus. Aliquam purus.</p>

     <p>Morbi felis quam, placerat sed, gravida a, bibendum a, mauris. Aliquam porta diam.
 Nam consequat feugiat diam. Fusce luctus, felis ut gravida mattis, ante mi viverra sapien,
 a vestibulum tellus lectus ut massa. Duis placerat. Aliquam molestie tellus. Suspendisse
 potenti. Fusce aliquet tellus a lectus. Proin augue diam, sollicitudin eget, hendrerit non
, semper at, arcu. Sed suscipit tincidunt nibh. Donec ullamcorper. Nullam faucibus euismod
 augue. Cras lacinia. Aenean scelerisque, lorem sed gravida varius, nunc tortor gravida
 odio, sed sollicitudin pede augue ut metus. Maecenas condimentum ipsum et enim. Sed nulla.
 Ut neque elit, varius a, blandit quis, facilisis sed, velit. Suspendisse aliquam odio sed
 nibh.</p>
</body>
</html>

2.
<link href="serifStyle.css" rel="alternate stylesheet" rev="alternate stylesheet"
 title="serif" />



Here's another style sheet, again using the link tag. However, the rel and rev attributes aren't set to the usual stylesheet; instead, they're set to alternate stylesheet. This is because this style sheet isn't actually in useinstead, it'll only be used if the user chooses it.

3.
<input type="button" class="typeBtn" value="Sm Sans" id = "default" />&nbsp;&nbsp;
<input type="button" class= "typeBtn2" value="Lg Serif" id = "serif" />



There are two buttons: Sm Sans and Lg Serif. Clicking the former puts all the text on the page into a small sans-serif font, while clicking the latter puts all the text on the page into a larger, serif font. If supported by the browser, the styles in Script 14.16 cause the buttons to themselves appear in the destination font, giving the user a signal as to what they will see if they choose that button.

Script 14.16. This Cascading Style Sheet contains the styles that always load.

body {
     margin: 0 20px;
     padding: 0;
     background-color: white;
     color: black;
}

div.navBar {
     background-color: #CCC;
     width: 175px;
     position: relative;
     top: -1.0em;
     right: -20px;
     float: right;
     padding: 20px 0 0 20px;
     border-left: 2px groove #999;
     border-bottom: 2px groove #999;
}

.typeBtn {
     font: 9px/10px verdana, geneva, arial, helvetica, sans-serif;
}

.typeBtn2 {
     font: 14px/15px Times New Roman, Times, serif;
}

4.
body, p, td, ol, ul, select, span, div, input {
  font: .9em/1.1em verdana, geneva, arial, helvetica, sans-serif;
}



Script 14.17 (better known as sansStyle.css), just tells the browser that when it's loaded, every tag that it covers should be displayed in .9em Verdana (or one of the other sans-serif fonts on the user's computer).



Script 14.17. This style sheet, sansStyle.css, changes all the text to a smaller, sans-serif font.

body, p, td, ol, ul, select, span, div, input {
     font: .9em/1.1em verdana, geneva, arial, helvetica, sans-serif;

}

5.
body, p, td, ol, ul, select, span, div, input {
  font: 1.1em/1.2em Times New Roman, Times, serif;
}



In a complementary way, Script 14.18 (also better known as serifStyle.css) tells the browser that every tag that it covers should be displayed in 1.1em Times New Roman (or again, any other serif font the browser can find).

Script 14.18. This style sheet, serifStyle.css, changes the page text to a larger serif font.

body, p, td, ol, ul, select, span, div, input {
     font: 1.1em/1.2em Times New Roman, Times, serif;
}

6.
var thisCookie = cookieVal("style");
var title = (thisCookie) ? thisCookie: getPreferredStylesheet();
setActiveStylesheet(title);



The initStyle() function in Script 14.19 is loaded when the page runs, and its goal is to initialize everything that the page needs. Here, we're checking to see if the user has a cookie already set that saved their preferred style. Our old buddy the cookieVal() function comes back from Chapter 10 to read the cookies and see if there's one called "style". If there is, its value is the style sheet we want; if not, getPreferredStylesheet() is called. Once the desired style sheet is known, setActiveStylesheet() is called to set the wanted appearance.



Script 14.19. This script handles setting the active style sheet.

window.onload = initStyle;
window.onunload = unloadStyle;

function initStyle() {
     var thisCookie = cookieVal("style");
     var title = (thisCookie) ? thisCookie : getPreferredStylesheet();
     setActiveStylesheet(title);

     var allButtons = document. getElementsByTagName("input");
     for (var i=0; i<allButtons.length; i++) {
        if (allButtons[i].type == "button") {
           allButtons[i].onclick = setActiveStylesheet;
        }
     }
}

function unloadStyle() {
     var expireDate = new Date();
     expireDate.setYear(expireDate. getFullYear()+1);
     document.cookie = "style=" + getActiveStylesheet() + ";expires=" + expireDate.
toGMTString() + ";path=/";
}
function getPreferredStylesheet() {
     var thisLink, relAttribute;
     var linksFound = document. getElementsByTagName("link");
     for (var i=0; i<linksFound.length; i++) {
        thisLink = linksFound[i];
        relAttribute = thisLink. getAttribute("rel");
        if (relAttribute.indexOf("style") > -1 && relAttribute.indexOf("alt") == -1 && 
thisLink.getAttribute("title")) {
           return thisLink.getAttribute ("title");
        }
     }
     return "";
}

function getActiveStylesheet() {
     var thisLink;
     var linksFound = document. getElementsByTagName("link");

     for (var i=0; i<linksFound.length; i++) {
        thisLink = linksFound[i];
        if (thisLink.getAttribute("rel"). indexOf("style") > -1 && thisLink. getAttribute(
"title") && !thisLink. disabled) {
           return thisLink.getAttribute ("title");
        }
     }
     return "";
}

function setActiveStylesheet(inVal) {
     var thisLink;
     var linksFound = document. getElementsByTagName("link");

     var title = (inVal) ? ((typeof inVal == "string") ? inVal : inVal.target.id) : window
.event.srcElement.id;
     for (var i=0; i<linksFound.length; i++) {
        thisLink = linksFound[i];
        if (thisLink.getAttribute("rel"). indexOf("style") > -1 && thisLink. getAttribute(
"title")) {
           thisLink.disabled = true;
           if (thisLink.getAttribute("title") == title) {
              thisLink.disabled = false;
           }
        }
     }
}

function cookieVal(cookieName) {
     var thisCookie = document.cookie. split("; ");
     for (var i=0; i<thisCookie.length; i++) {
        if (cookieName == thisCookie[i]. split("=")[0]) {
           return thisCookie[i].split("=")[1];
        }
     }
     return "";
}

7.
var allButtons = document. getElementsByTagName("input");
for (var i=0; i<allButtons.length; i++) {
  if (allButtons[i].type == "button") {
     allButtons[i].onclick = setActiveStylesheet;
  }
}



The initStyle() function also needs to add event handlers to our buttons. Here, we tell them both to call setActiveStylesheet() when they're clicked.

8.
function unloadStyle() {
  var expireDate = new Date(); expireDate.setYear(expireDate. getFullYear()+1);
  document.cookie = "style=" + getActiveStylesheet() + ";expires=" + expireDate.
 toGMTString() + ";path=/";
}



When the page is unloaded, we need to set the cookie for the future. The cookie's expiration date is set to one year from today, getActiveStylesheet() is called to establish what the user currently has, and the cookie is written out for future use.

9.
function getPreferredStylesheet() {
var thisLink, relAttribute;
var linksFound = document. getElementsByTagName("link");



If, when the page is loaded, there's no cookie saying which style the user has previously chosen, our script needs to be able to figure out what the preferred style sheet is. That's the goal of the getPreferredStylesheet() function in this step and the next.

10.
for (var i=0; i<linksFound.length; i++) {
  thisLink = linksFound[i];
  relAttribute = thisLink. getAttribute("rel");
  if (relAttribute.indexOf ("style") > -1 && relAttribute. indexOf("alt") == -1 && 
thisLink.getAttribute("title")) {
    return thisLink.getAttribute ("title");
  }
}



This function loops through each link tag, looking to see if each has a rel attribute, if that attribute has a value that contains "style", if that attribute has a value that does not contain "alt", and if the tag has a title attribute. If one is found that matches all these criteria, that's the preferred style sheet, and its title attribute is returned.

To see which of the actual tags in our code is the preferred style sheet, look at the link tags in our HTML file. While there are three link tags, only two of them have title attributes. And of those two, one has a rel attribute of "stylesheet", while the other is "alternate stylesheet". Consequently, the preferred style sheet has to be default.

11.
for (var i=0; i<linksFound.length; i++) {
  thisLink = linksFound[i];
    if (thisLink.getAttribute ("rel").indexOf("style") > -1 && thisLink.getAttribute (
"title") && !thisLink. disabled) {
    return thisLink.getAttribute ("title");
  }
}



As mentioned above, we're going to want to use a cookie to store the user's chosen style sheet when they leave this site, so that they'll be greeted with their favorite font when they return. While we could write out a cookie every time they click the style button, it's a better idea to only write it out once when they leave the site. Here, the getActiveStylesheet() function (which is called when the page is unloaded, as we saw above) looks through all the link tags, chooses the one that's currently enabled, and returns the title of that style.

12.
function setActiveStylesheet(inVal) {
   var thisLink;
   var linksFound = document. getElementsByTagName("link");

   var title = (inVal) ? ((typeof inVal == "string") ? inVal : inVal.target.id): window.
 event.srcElement.id;



As seen above, when the user loads this page, the setActiveStylesheet() function is called and passed a parameter that's referred to inside the function as inVal. When setActiveStylesheet() is called after a button is clicked, however, there may or may not be a parameter passed, depending on which browser is being used and how it handles events. Here's where we do a little checking to figure out how we got here and what the user wants to do. There are three possibilities:

  • initStyle() called this function and passed it a string containing the preferred stylesheet. In this case, inVal exists and it's a string, so title is set to inVal.

  • A style button was clicked in a browser that supports W3C style events. In this case, inVal is automatically set to the event that triggered the function, so inVal will exist but it won't be a string. When that happens, we know that the target of the event (what caused the event to trigger) is the button that was clicked, and the id of that button stores the style desired.

  • A style button was clicked in a browser that doesn't support W3C standards but does support the IE event model. If that's the case, the inVal variable won't exist, so we instead grab the style desired from window.event.srcElement.id.

13.
thisLink = linksFound[i];
if (thisLink.getAttribute("rel"). indexOf("style") > -1 && thisLink.getAttribute("title")) {
  thisLink.disabled = true;
  if (thisLink.getAttribute ("title") == title) {
    thisLink.disabled = false;
  }
}



The setActiveStylesheet() function loops through all the link tags in the document, checking each one to make sure that it has both a rel attribute that contains "style" and an existing title attribute. If both of these are true, the link is first disabled and then (and only then) re-enabled if the title attribute is set to the title value.

So, if the current style sheet being used has the title attribute of "default", and the user clicks the Lg Serif button, JavaScript sees that it should load the serif style sheet. There's one link tag with a title of "serif", so all others (i.e., the default style sheet, in this case) are disabled, and only the serif style sheet is turned on.


Previous Page
Next Page