Example 4-22. CSS for the 2x1 container #con2x1.default { float: left; width: 750px; overflow: hidden; } #con2x1.default .con2x1pri { float: left; display: inline; width: 370px; overflow: hidden; margin-right: 10px; } #con2x1.default .con2x1sec { float: left; width: 370px; overflow: hidden; } #con2x1.minimum { float: left; width: 310px; overflow: hidden; } #con2x1.minimum .con2x1pri { float: left; display: inline; width: 150px; overflow: hidden; margin-right: 10px; } #con2x1.minimum .con2x1sec { float: left; width: 150px; overflow: hidden; } Example 4-23 shows how you could use the default version of the 2x1 container within the primary content section of the Results layout presented earlier. From this example, coupled with what we observed in Chapter 3 about constructing an information ar- chitecture to create reusable modules, you can begin to see how a page built from a layout, with containers inserted as needed, and modules inserted into the layout and various containers, helps build modular web applications in which components are reusable, maintainable, and reliable. Layouts and Containers | 81 Example 4-23. The default version of the 2x1 container within the Results layout <div id="layres"> <div class="layreshdr"> </div> <div class="layresmaj"> <div class="layrespri"> <div id="con2x1" class="default"> <div class="con2x1pri"> </div> <div class="con2x1sec"> </div> </div> </div> <div class="layressec"> </div> <div class="layrester"> </div> </div> <div class="layresftr1"> </div> <div class="layresftr2"> </div> </div> Other Practices To ensure browsers render your presentations in a pixel-perfect manner, use the fol- lowing practices to help write reliable CSS as you develop large web applications. The goals of these practices are to establish a consistent platform on which to apply your styles and to address inconsistencies with the way browsers render fonts. 82 | Chapter 4: Large-Scale CSS Browser Reset CSS All browsers provide a default set of styles on which your own styles will be layered. Unfortunately, default styles are inconsistent across various browsers. Without a com- mon starting point on which to layer the application’s own presentation, you end up making many more adjustments in CSS for particular browsers to maintain consistency. Fortunately, Yahoo! makes some CSS rules available in its YUI (Yahoo! User Interface) library to reset modern browsers to a consistent set of neutral styles. You can download the library and read its complete documentation at http://developer.yahoo.com/yui. To apply this CSS, simply add the following link before any CSS of your own: <link href="http://yui.yahooapis.com/2.7.0/build/reset/reset-min.css" rel="stylesheet" type="text/css" media="all" /> Because it is helpful to see which properties must be reset, Example 4-24 lists the CSS. Alternatively, you can place this CSS directly in your own CSS file to avoid the addi- tional server request with the previous link. Example 4-24. Browser reset CSS from the YUI library /* Copyright (c) 2009, Yahoo! Inc. All rights reserved. Code licensed under the BSD License: http://developer.yahoo.net/yui/license.txt version: 2.7.0 */ html { color: #000; background: #FFF; } body, div, dl, dt, dd, ul, ol, li, h1, h2, h3, h4, h5, h6, pre, code, form, fieldset, legend, input, button, textarea, p, blockquote, th, td { margin: 0; padding: 0; } table { border-collapse: collapse; border-spacing: 0; } fieldset, img { border: 0; } address, caption, cite, code, dfn, em, strong, th, var, optgroup { font-style: inherit; font-weight: inherit; } del, ins Other Practices | 83 { text-decoration: none; } li { list-style: none; } caption, th { text-align: left; } h1, h2, h3, h4, h5, h6 { font-size: 100%; font-weight: normal; } q:before, q:after { content: ''; } abbr, acronym { border: 0; font-variant: normal; } sup { vertical-align: baseline; } sub { vertical-align: baseline; } legend { color: #000; } input, button, textarea, select, optgroup, option { font-family: inherit; font-size: inherit; font-style: inherit; font-weight: inherit; } input, button, textarea, select { *font-size: 100%; } 84 | Chapter 4: Large-Scale CSS Font Normalization The ways in which browsers render fonts, especially when it comes to font size, are not consistent. Fortunately, Yahoo! makes CSS available in its YUI library to normalize fonts within the modern browsers. To apply this CSS, add the following link before any CSS of your own: <link href="http://yui.yahooapis.com/2.7.0/build/fonts/fonts-min.css" rel="stylesheet" type="text/css" media="all" /> Example 4-25 lists the CSS for font normalization. As with the browser reset CSS shown earlier, you can place this CSS directly in your own CSS file to avoid the additional server request with the previous link. Example 4-25. Font normalization CSS from the YUI library /* Copyright (c) 2009, Yahoo! Inc. All rights reserved. Code licensed under the BSD License: http://developer.yahoo.net/yui/license.txt version: 2.7.0 */ body { font: 13px/1.231 arial, helvetica, clean, sans-serif; *font-size: small; *font: x-small; } select, input, button, textarea, button { font: 99% arial, helvetica, clean, sans-serif; } table { font-size: inherit; font: 100%; } pre, code, kbd, samp, tt { font-family: monospace; *font-size: 108%; line-height: 100%; } Assuming you use the CSS from Example 4-25, Table 4-1 specifies the percentage to specify in your CSS to render a font in the number of pixels listed for today’s browsers. Research conducted at Yahoo! across many versions of the most popular browsers has shown that fonts render the most consistently across browsers when you specify font sizes using percentages as opposed to points or ems. This is the reason that we use percentages for fonts throughout this book. Other Practices | 85 Table 4-1. Font sizing in modern browsers, assuming normalization from the YUI library To render in pixels Use this percentage 10 77% 11 85% 12 93% 13 100% 14 108% 15 116% 16 123.1% 17 131% 18 138.5% 19 146.5% 20 153.9% 21 161.6% 22 167% 23 174% 24 182% 25 189% 26 197% 86 | Chapter 4: Large-Scale CSS CHAPTER 5 Large-Scale JavaScript The behaviors supported by JavaScript in a web application form a distinct layer beyond the information architecture defined by HTML and the presentation defined by CSS. Although in many web applications it’s important to consider how the application would operate without the behavior layer (for reasons of accessibility, printing, and search engine optimization, for example), the widespread use of Ajax has made the behavior layer in many large web applications more important than ever. In many cases, the designs for large web applications have advanced to the point that user experience designers, product managers, and engineers will agree that certain parts of an applica- tion, or even the entire application, will only make sense with a fully functioning be- havior layer. Think of Google Maps, in which tiles are requested from the server as you interact with the map. This application only makes sense with a strong layer dedicated to behavior using JavaScript. JavaScript has been around for a long time, of course, but early web applications rarely made much use of its powerful object-oriented features. Most developers simply wrote functions to accomplish various tasks, paying little attention to JavaScript’s capabilities for developing systems of loosely coupled, highly encapsulated objects using prototype- based inheritance (see Chapter 2). A more advanced use of object-oriented JavaScript is an important aspect of achieving Tenet 5 from Chapter 1: Tenet 5: Large-scale JavaScript forms a layer of behavior applied in a modular and object- oriented fashion that prevents side effects as we reuse modules in various contexts. We begin this chapter by exploring some fundamental techniques for writing modular JavaScript. We’ll look at ways to include JavaScript in an HTML file and establish a scope in which the JavaScript for a module can operate without conflicting with other JavaScript in use within the application. Next, we’ll explore some important methods for working with the DOM, which JavaScript applications have to manipulate in order to handle web pages in the structured manner we need. This includes a discussion of several important methods that all major browsers support as well as a look at methods in some popular JavaScript libraries that standardize other helpful DOM operations. We’ll follow this with a look at techniques for improving event handling in large web 87 applications and some examples of JavaScript animation. Finally, we’ll explore an ex- ample of modular JavaScript for implementing chained selection lists. Modular JavaScript Once we have divided the components of a web page into reusable modules that reflect the information architecture (see Chapter 3) and have added a layer of presentation with CSS (see Chapter 4), we can focus on writing an additional layer to implement dynamic behaviors with JavaScript. As mentioned in Tenet 5, the JavaScript for a mod- ule, like the CSS for a module, should: • Have distinct modules of its own that apply to specific parts of the architecture (in other words, it should be well targeted), and • Not produce unexpected consequences as a module is reused in various contexts (in other words, it should be free of side effects). Once you separate most of your JavaScript methods into modules, you’ll find that it takes only a small amount of JavaScript unique to each page to stitch them together. Including JavaScript Let’s look at three ways to include JavaScript in a web application: linking, embed- ding, and inlining. Although linking is generally the most desirable of these options, it is common to find some combination of these methods in use across a large web ap- plication, even within a single page, since each method has some benefit depending on the specific situation. Linking Linking allows you to place JavaScript in a file, which you then include by placing a script tag with a src attribute in an HTML file. As with CSS files, this has desirable effects: architecturally, multiple pages can share the same JavaScript, while in terms of performance, the browser can cache the file after downloading it the first time. Al- though it’s common to place a linked JavaScript file in the head section at the top of an HTML file, Chapter 9 presents some very good reasons related to performance for placing linked JavaScript at the end of the body tag (i.e., at the bottom of the page). The following example links a JavaScript file: <script src="http:// /sitewide.js" type="text/javascript"> </script> Once you modify a file that browsers may have already cached, you need to make sure browsers know when to bust the cache and download the new copy. Version numbers help you manage this situation. Incorporating a date stamp into the JavaScript file’s name works well, and you can add a sequence number when updating the JavaScript file more than once a day (or you could use the version number from your source control 88 | Chapter 5: Large-Scale JavaScript system instead of the date stamp). For each new copy, simply bump up the version number as shown here: <script src="http:// /sitewide_20090422.js" type="text/javascript"> </script> Of course, each page that includes a link to the JavaScript file must also be updated to refer to the new version. Chapter 7 presents information on managing this in a cen- tralized way. Embedding Embedding places JavaScript directly within a page. One benefit of this approach is that you can conveniently generate and include JavaScript programmatically as you build the page. While it’s common to place embedded JavaScript in the head section at the top of an HTML file, Chapter 9 presents some very good reasons related to per- formance for placing embedded JavaScript at the end of the body tag (i.e., at the bottom of the page). Example 5-1 illustrates some embedded JavaScript. Example 5-1. Embedding JavaScript <head> </head> <body> <script type="text/javascript"> // Embedded JavaScript is JavaScript contained within script tags. var GreenSearchResultsModel.MReg = new Array(); var GreenSearchResultsModel.VReg = new Array(); </script> </body> Inlining Inlining JavaScript lets you add small amounts of JavaScript for event handlers to HTML elements within the HTML itself. These stubs of JavaScript usually call upon other JavaScript that has been included using linking or embedding. The following illustrates the inlining of some JavaScript for an onclick handler: <img class="btnl" src="http:// /slide_arrow_l.gif" width="14" onclick="picsld.slideL();" /> Modular JavaScript | 89 Rather than using inline JavaScript, it is almost always preferable to register for events using methods within JavaScript that is linked or embedded (see the discussion later in this chapter about YAHOO.util.Event.addListener). Scoping with JavaScript In Chapter 7, we’ll examine techniques for creating modules as self-contained compo- nents of the user interface. These modules will encompass everything needed (e.g., HTML, CSS, and JavaScript) to make an independently functioning and cohesive unit that you can use in a variety of contexts across various pages. To accomplish this, the JavaScript for a module needs to form a nicely encapsulated bundle as well. In this section, we’ll look at how the use of objects in JavaScript makes this possible. Namespaces with JavaScript JavaScript objects provide a natural way to create namespaces in which to place the data and methods for specific modules. Once you have defined a method for an object, you invoke it directly through the object itself. For example, the following invokes the slideL method on the picsld instance of PictureSlider, an object that implements the behavior layer for a module that displays images in a slideshow or carousel-type filmstrip: picsld = new PictureSlider(); picsld.slideL(); You should notice two important things here: • Because slideL is a member of picsld (as opposed to the global window object), you can be sure that this use of slideL will not conflict with any other use in your web application. • The slideL method will have access to data members within PictureSlider, which provides better encapsulation and abstraction for the event handler than a global one does. A good convention for naming JavaScript objects that correspond to modules is to name them the same as the class used to manage the module on the server. For example, in Chapter 7 we’ll look at an example of a slideshow module called PictureSlider, which encapsulates the HTML, CSS, and JavaScript for the module neatly within a PHP class. The PHP class is called PictureSlider, so we’ve created a JavaScript object called PictureSlider to address the behavior layer for the module. This convention works well, but the exact convention is not what is important here; establishing a system of unique qualification that clearly preserves modularity is the key. 90 | Chapter 5: Large-Scale JavaScript . widespread use of Ajax has made the behavior layer in many large web applications more important than ever. In many cases, the designs for large web applications have advanced to the point that user. 167% 23 174% 24 182% 25 189% 26 197% 86 | Chapter 4: Large- Scale CSS CHAPTER 5 Large- Scale JavaScript The behaviors supported by JavaScript in a web application form a distinct layer beyond the information. pixel-perfect manner, use the fol- lowing practices to help write reliable CSS as you develop large web applications. The goals of these practices are to establish a consistent platform on which