home | O'Reilly's CD bookshelfs | FreeBSD | Linux | Cisco | Cisco Exam  


Previous Section Next Section

12.4 Offering Body Text Size Choices to Users

NN 6, IE 5

12.4.1 Problem

You want to let users choose the relative font size for the content of the page.

12.4.2 Solution

Create a user interface element that lets users select from three or four different font sizes. Each choice invokes the changeSizeStyle( ) function shown in the Discussion. This function enables a style sheet whose ID is passed as an argument and disables the rest. All of the related style sheets apply themselves to the body element. As an added bonus, the changeSizeStyle( ) function calls upon the cookies.js library (Recipe 1.9) to preserve the setting to be applied to the page the next time the user visits.

12.4.3 Discussion

This is a three-part solution, involving HTML for the font size controller, style sheets, and scripts. The result is a small controller on the page that lets users select from three font size bases upon which the rest of the page renders, as shown in Figure 12-1.

Figure 12-1. Text size controller for users
figs/jsdc_1201.gif

HTML for the controller defines one surrounding div element and several nested img elements. Three of the img elements are surrounded by links, whose onclick event handlers invoke the changeSizeStyle( ) function. To prevent blank space from occurring between the images, avoid source code line breaks between elements. The following HTML code inserts line breaks inside element tags:

<div id="textSizer">
<img src="fontSizer.jpg" height="18" width="72" alt="Font Sizer"><a 
href="" onclick="changeSizeStyle('smallStyle'); return false"><img 
class="textSize" src="fontSmall.jpg" height="18" width="18" 
alt="Smallest" /></a><a href="" onclick="changeSizeStyle(''); return false"><img 
class="textSize" src="fontMedium.jpg"  height="18" width="18" alt="Default" /></a><a 
href="" onclick="changeSizeStyle('largeStyle'); return false"><img 
class="textSize" src="fontLarge.jpg" height="18" width="18" alt="Biggest" /></a>
</div>

The style sheet portion of this solution consists of several distinct style elements (or they could be imported via link elements). Each style element has an id attribute assigned to it that comes into play during script execution. By default, the controller is not rendered, but scripts take care of this, as discussed shortly:

<style id="normalStyle" type="text/css">
body {font-family:Verdana, Helvetica, sans-serif;
      font-size:small}
#textSizer {margin-left:80%; display:none}
.textSize {border:1px solid black}
</style>
<style id="sizer" type="text/css" disabled="disabled">
    @import url("textSizer.css");
</style>
<style id="smallStyle" type="text/css" disabled="disabled">
    @import url("smallFont.css");
</style>
<style id="largeStyle" type="text/css" disabled="disabled">
    @import url("largeFont.css");
</style>

Each of the imported style sheets consists of a single rule. One, textSizer.css, is for the controller:

#textSizer {display:block}

The smallFont.css file consists of the following rule:

body {font-size:xx-small}

The largeFont.css file has the following:

body {font-size:large}

The JavaScript portion relies on the cookies.js library (Recipe 1.9) and consists of two functions and a statement that executes one of the functions while the page loads:

<script type="text/javascript" src="cookies.js"></script>
<script type="text/javascript">
// enable/disable  style sheet per cookie setting
function setSizeStyle( ) {
    if (document.getElementById) {
        document.getElementById("sizer").disabled = false;            
        var styleCookie = getCookie("fontSize");
        var styleIDs = ["smallStyle", "largeStyle"];
        for (var i = 0; i < styleIDs.length; i++) {
            if (styleCookie =  = styleIDs[i]) {
                document.getElementById(styleIDs[i]).disabled = false;            
            } else {
                document.getElementById(styleIDs[i]).disabled = true;    
            }
        }
    }
}
// set active style now, before content renders
setSizeStyle( );
   
// invoked by clicking on sizer icons
function changeSizeStyle(styleID) {
    setCookie("fontSize", styleID, getExpDate(180, 0, 0));
    setSizeStyle( );
}
</script>

Users' choices are preserved as a cookie value so that the previous setting is applied on the next visit to the page.

Despite the comparatively small amount of CSS, HTML, and JavaScript code involved for this solution, there is quite a bit going on here so that the application runs well in most modern browsers, yet degrades gracefully in older browsers.

The controller consists entirely of images so that even as the body font size is adjusted, the label's text won't change as well. While the label could be given an inline style attribute to override the more remote style settings, using an image is easier. If the label text were allowed to resize, the position of the clickable images would shift with each click, driving users crazy. While the example here uses a non-positioned element and a percentage length for the left margin, you might find it more appealing to turn it into an absolute-positioned element that is keyed to some other relative-positioned wrapper element in your design.

Style sheet definitions are set up to allow a default font size to govern the page for even the older browsers that may respect style sheets but not the W3C DOM syntax used for style sheet manipulation. Notice that this example does not specify a specific font size in any unit. Font sizing is always a problem in browsers due to their quirky behavior with regard to user settings in the browser and operating system. Using relative sizes suggests that we let users determine their default sizes outside of our application, and they can choose to display your font sets either in a smaller or larger font than the default. This also assumes that more detailed font size settings throughout each page's document are also relative, rather than absolute. Thus, top-level headlines may be specified in em units to derive the desired larger size, but always relative to the surrounding body element's current size. In a way, this approach embraces the flaws of the browser world, leaving the precise display up to the user. Your job as designer is to make sure the content flows appropriately in a variety of sizes.

Three initially disabled style elements provide alternative display characteristics (using the backward-compatible, yet XHTML-friendly syntax for the disabled attribute). For example, while the default style sheet completely hides the size controller, one of the three disabled style sheets has the power—when enabled—to show the controller to the user. The same is true for either of the other body font style sheets. Because all three of these style elements come after the default style sheet, if any one of them is enabled, the last specification for a particular style property wins the competition (according to CSS cascading precedence rules). The job for the script is to enable or disable the extra style sheets as needed. Redirection to an imported style sheet is needed to keep Navigator 4 from applying the style rule, regardless of the disabled attribute setting.

To make the user choice stick on the next visit by the user, the scripts call upon the cookie reading and writing routines from the cookies.js library shown in Recipe 1.9. Make sure that this library is loaded ahead of the scripts that control the font sizing.

Most of the work is handled by the setSizeStyle( ) function. Using the presence of the document.getElementById( ) method in the browser as a threshold point (thus limiting this to IE 5 or later and NN 6 or later), the function immediately enables the style sheet that lets the controller be visible. Next it looks for the existence of the cookie from a previous visit. If it's there, the value (the ID of the style sheet used) becomes the ID of the style sheet to enable, while the other alternate is disabled. There is no need to disable the default style because the new one overrides the font-size property, while leaving all other default settings intact. The mechanism shown in the example allows for additional size settings in case you wish to offer more than the three shown here. Simply add the style element with its own unique ID, and add that ID to the array inside the function, as well as to the parameter of the onclick event handler of the new image's surrounding hyperlink element.

Because the only objects that the setSizeStyle( ) function operates on are style elements defined earlier in the page, the function can run before the body and its objects are part of the current object model. As shown in the preceding script, a single call to setSizeStyle( ) immediately following the function's definition invokes the method as the head portion loads.

When a user clicks on one of the sizer images, the onclick event handler invokes the changeSizeStyle( ) function, passing the ID of the style sheet to apply to the content. This function changes the cookie setting and then calls setSizeStyle( ) to finish the job. The setSizeStyle( ) function becomes a vital module for the entire application.

12.4.4 See Also

Recipe 1.9 for cookie utilities; Recipe 11.4 for importing style sheets.

    Previous Section Next Section