Forms allow users to interact with web sites. HTML forms consist of controls ( buttons , checkboxes, input fields, menus , and so on) that users modify before submitting for processing. Forms act as containers for controls, which in turn can act as containers for other options like select menus. Form optimization is often overlooked, but it can accelerate web pages by saving clicks, HTTP calls, and file space by using client-side processing and eliminating or shunting code to the server.
JavaScript and forms are a powerful combination. You can save both extra clicks and a trip to the server by using a gracefully degrading JavaScript to process your forms (see Listing 4.9).
<script language="text/javascript"> <!-- function jmp(form) { var thesrc = form.url.selectedIndex; // grab the selected index if (thesrc >= 0) { // check if valid location = form.url.options[thesrc].value; // jump to that option's value } } --> </script> </head> <body> <FORM METHOD="POST" ACTION="/cgi-bin/redirect.cgi" onSubmit="return false"><SMALL>Pick a topic:</SMALL><BR> <SELECT NAME="url" onChange="jmp(this.form)"> <OPTION VALUE="/3d/">3D Animation <OPTION VALUE="/dlab/">Design ... </SELECT><INPUT TYPE="SUBMIT" VALUE="Go" onClick ="jmp(this.form)"> </FORM>
The key is to not rely entirely on JavaScript. Always gracefully degrade for the 11 percent of users who don't have JavaScript. [8]
The GET method is more efficient than POST because it takes one less trip to the server. When security is not paramount, using GET (or non-parsed headers) can mean faster form processing for your users. You learn more about CGI- related issues in Chapter 17, "Server-Side Techniques."
Users interact with forms through controls. Two controls in particular offer opportunities for optimization: input and select .
Input controls often are used to interact with server-based scripts like search engines or email newsletter subscriptions. HTML authors typically place default values for scripts within hidden input fields like this:
<form method="get" action="/cgi-bin/search.cgi"> <input type="hidden" name="what" value="local"> <input type="hidden" name="engine" value="au"> <input type="hidden" name="summary" value="1"> <input type="hidden" name="startnumber" value="0"> <input type="hidden" name="batchsize" value="25"> <input type="hidden" name="relevancethreshold" value="50"> <input type="text" name="query" size="12"> </form>
A better way to set defaults is to shunt these hidden fields to the server inside the CGI script. Then you end up with something like this:
<form method="get" action="/cgi-bin/search.cgi"> <input type="text" name="query" size="12"> </form>
Done properly, authors can still override these CGI-based defaults if hidden fields exist. Chapter 17 shows you how.
Select menus are frequently used to offer users options for navigation and other alternatives. The select element creates a multiple-choice menu or scrolling list. This element can contain one or more option elements. It also can contain one or more optgroup elements that group related choices logically, and can create cascading menus. These can replace complex DHTML, Java, or Flash cascading menus with smaller, standards-based code.
The optgroup element defines a logical group of options to create submenus. Until recently this element was poorly supported. With the advent of HTML 4 standards-compliant browsers like NS6, IE6, and OP6, optgroup can be used to group related options under one label.
This feature can be especially helpful when users must choose from a long list of options. You can group related choices, making it easier for users to understand and remember selections. In HTML 4, optgroup elements cannot be nested; however, in the specification, they leave the possibility open for the future nesting of optgroup elements.
The sole attribute of optgroup is label , which can be used for hierarchical menus, as you see here:
Label = text Defines a label to be used when displaying the submenu.
Here's an example (see Listing 4.10):
<form method="get" action="/cgi-bin/go.cgi"> <select name="nav"> <optgroup label="DHTML"> <option value="/dhtml/">DHTML <option value="/dhtml/hiermenus">Hiermenus Central <option value="/dhtml/dynomat/">Tools </optgroup> <optgroup label="JavaScript"> <option value="/js/">JavaScript <option value="/js/tips/">JavaScript Tips <option value="/js/tools/">Tools </optgroup> <optgroup label="XML"> <option value="/xml/">XML <option value="/xml/tools">Tools </optgroup> </select> <input type="submit" value="submit"> </form>
For standards-compliant browsers like IE5 Mac, IE5.5 Win, NS6, and OP6, each optgroup creates a category header. Older browsers ignore the unrecognized optgroup element and display the option s as before. IE5 Mac displays a cascading menu like the one shown in Figure 4.7.
IE6 and NS6/7 display a visually nested menu, as shown in Figure 4.8.
optgroup elements offer a standards-compliant alternative for two-level DHTML hierarchical menus that gracefully degrade. They are an excellent alternative to DHTML hierarchical menus, which can become quite code- intensive .
Real-world examples of nested menus are hard to come by. Figure 4.9 shows one from A List Apart, an online magazine for developers.
Listing 4.11 shows the HTML.
/* Based on Charity Khan's article, Menu Maker Update, on Builder.com http://www.builder.com/Programming/Scripter/123097/ */ function buildArray() { var a = buildArray.arguments; for (i=0; i<a.length; i++) { this[i] = a[i]; } this.length = a.length; } var urls1 = new buildArray("", "http://www.alistapart.com/stories/indexAccessibility.html", "http://www.alistapart.com/stories/indexBusiness.html", "http://www.alistapart.com/stories/indexBrowsers.html", "http://www.alistapart.com/stories/indexCrossPlatform.html", "http://www.alistapart.com/stories/indexCSS.html", "http://www.alistapart.com/stories/indexDHTMLDOM.html", "http://www.alistapart.com/stories/indexFlash.html", "http://www.alistapart.com/stories/indexGeneral.html", "http://www.alistapart.com/stories/indexHTMLXHTML.html", "http://www.alistapart.com/stories/indexJavaScript.html", "http://www.alistapart.com/stories/indexSMIL.html", "http://www.alistapart.com/stories/indexWMLWAP.html", "http://www.alistapart.com/stories/indexXML.html", "http://www.alistapart.com/stories/indexContent.html", "http://www.alistapart.com/stories/indexCulture.html", "http://www.alistapart.com/stories/indexDesign.html", "http://www.alistapart.com/stories/indexIndustry.html", "http://www.alistapart.com/stories/indexUsability.html"); function go(which, num, win) { n = which.selectedIndex; if (n != 0) { var url = eval("urls" + num + "[n]") if (win) { openWindow(url); } else { location.href = url; } } } function stdStatus() { window.status = "A List Apart, for people who make websites."; return true; } <form action="null" method="post"> <fieldset><legend> </legend> <select class="butt" name="selectCategory"> <option selected>Select category...</option> <option>Accessibility</option> <option>Business</option> <optgroup label="Code"> <option>Browsers</option> <option>Cross-platform testing</option> <option>CSS</option> <option>DHTML/DOM</option> <option>Flash</option> <option>General</option> <option>HTML/XHTML</option> <option>JavaScript</option> <option>SMIL</option> <option>WML/WAP</option> <option>XML</option> </optgroup> <option>Content</option> <option>Culture</option> <option>Design</option> <option>Industry</option> <option>Usability</option> </select> <input class="butt" type="button" name="goButton" value="go" onClick="go(this.form. selectCategory, 1, false)"> </fieldset> </form>
Notice that the designers use the selected index number to access the array of URLs, instead of embedding the URLs within the form itself. This saves space by shunting the URLs into the external cached JavaScript file and bypasses some bugs in older browsers. This form could be modified to gracefully degrade by adding a fall-back CGI redirect script for browsers without JavaScript. The CGI script could map option values to URLs, similar to the preceding JavaScript.