reptile7's JavaScript blog
Wednesday, December 12, 2007
Drop-Down ULs
Blog Entry #97

Believe it or not, we have never, not once, worked with HTML lists at this blog - we'll do that today! As noted at the end of our last episode, this post will reformulate HTML Goodies' "Drop-Down Menu" tutorial script with a nested list structure. Let me kick things off by giving you some relevant references:
(1) HTML Goodies covers HTML lists in its "So You Want Indents and Lists, Huh?" tutorial.
(2) In the HTML 4.01 Specification, HTML lists are detailed in Chapter 10 ("Lists").
(3) On the style front, HTML lists are addressed in Section 12.5 of the CSS 2.1 Specification.

The list HTML

Here's the list HTML we'll use for the "Drop-Down Menu" tutorial script:

<ul id="outerlist">
<li id="heading1" onclick="displayList(1);">Goodies Tutorials</li>
<ul id="innerlist1">
<li><a href="">Frames</a></li>
<li><a href="">Tables</a></li>
<li><a href="">DHTML/Layers</a></li>
<li><a href="">Forms</a></li>
<li id="heading2" onclick="displayList(2);">Great Sites</li>
<ul id="innerlist2">
<li><a href="">The Straight Dope</a></li>
<li><a href="">Project Gutenberg</a></li>
<li><a href="">HowStuffWorks</a></li>
<li><a href=""></a></li>
<li id="heading3" onclick="displayList(3);">News Sites</li>
<ul id="innerlist3">
<li><a href="">CNN</a></li>
<li><a href="">New York Times</a></li>
<li><a href="">BBC</a></li>
<li><a href="">Agence France-Presse</a></li>

The above code has been adapted from the code appearing in the "Can I put these together?" section of the aforecited HTML Goodies tutorial. A parent id="outerlist" ul element has as children
(a) three id="heading#" li elements that respectively hold the Goodies Tutorials, Great Sites, and News Sites menu headings; and
(b) three id="innerlist#" ul elements whose li children hold the menu links (these are the same links that I used for my demo in the previous entry).

A couple of points regarding Joe's tutorial code:
• The li elements lack closing </li> tags; this is allowed in HTML but you'll need to add these tags if you're shooting for XHTML-compliance.
• The ul list items are prefaced not with disc/square/circle markers (the ul type attribute for setting these values has been deprecated) but with blue triangular Joe's blue triangular li marker images; this can't be done with HTML but can with CSS, bringing us to...

The style sheet

#outerlist {
list-style-image: url(littlex.gif);
list-style-position: inside; }
/* This rule set can be shorthanded to:
#outerlist { list-style: inside url(littlex.gif); } */

#innerlist1, #innerlist2, #innerlist3 {
list-style-image: url(littledash.gif);
margin-top: 0; margin-bottom: 0; }

#heading1, #heading2, #heading3 { font-weight: bold; }

a:link { color: black; text-decoration: none; }
a:hover { color: blue; text-decoration: underline; }
The a:link rule set runs counter to the traditional rendering of links by most browsers, whereas the a:hover rule set is redundant vis-à-vis that rendering; my preference is to comment them out.

The list-style-image property sets the image that will be used as the list item marker; the URL value in parentheses can be quoted or not quoted. The The small plus image littlex.gif image that will mark the outerlist menu headings is available here and the The small minus image littledash.gif image that will mark the innerlist# menu links is available here.

(BTW, Joe uses a
ul { list-style-image:url("../img/bullet-2005.gif"); }
rule in a style sheet here to set his Joe's blue triangular li marker ul li markers; the bullet-2005.gif image itself is available here.)

The list-style-position:inside; declaration that is applied to the outerlist list (actually, it's also applied to the innerlist# lists, because list-style-position is an inherited property) places the littlex.gif markers in the same CSS "principal block boxes" that hold the heading# li elements; consequently, the onclick="displayList(#);" triggers for the displayList( ) function (vide infra), which drops down and pulls up the menu links, will apply to both the heading# headings and the littlex.gif markers that precede them. In other words, without this declaration the user would not be able to display the links by clicking on the outerlist list markers but could still do so by clicking on the outerlist list items.

Regarding vertical alignment within the li element boxes, the image markers are given a top positioning by MSIE 5.1.6 on my computer, whereas Netscape 7.02 gives them a baseline positioning; I would prefer that they have a middle positioning, but the W3C warns, CSS 2.1 does not specify the precise location of the marker box, and several attempts on my part to shift vertically the marker location came to naught.

Finally, the margin-top and margin-bottom properties for the innerlist# ul elements have been set to 0. Without these declarations, MSIE inserts 'blank lines' between the menu headings and sets of links

An image showing the default innerlist# margins when using MSIE 5.1.6

but Netscape, whose html.css file already contains a
ul ul { margin-top:0;margin-bottom:0; }
rule set, does not. (A tip of the hat to Eric Meyer and his interesting "Really Undoing html.css" essay for helping me sort out this issue.)

The script element

<script type="text/javascript">

document.getElementById("innerlist1").style.display = "none";
document.getElementById("innerlist2").style.display = "none";
document.getElementById("innerlist3").style.display = "none";

function displayList(num) {
if (document.getElementById("innerlist" + num).style.display == "none") {
document.getElementById("innerlist" + num).style.display = "block";
document.getElementById("heading" + num).style.listStyle = "inside url(littledash.gif)"; }
else {
document.getElementById("innerlist" + num).style.display = "none";
document.getElementById("heading" + num).style.listStyle = "inside url(littlex.gif)";
} }

Like the previous post's displayx( ) function, on which it is patterned, the displayList( ) function handles all three innerlist# menus. Note that the list-style property can be written at the li element level as well as at the ul/ol element level (this is also true for the list properties shorthanded by list-style).

Strangely, if I delimit the littledash.gif/littlex.gif URL values with single quotes, e.g.,

document.getElementById("heading" + num).style.listStyle = "inside url('littledash.gif')";

then MSIE replaces the original heading# image markers with disc markers (and gives them a baseline vertical alignment - go figure), as though the list-style images were not available - disc is the initial value of the list-style-type property, which specifies [the] appearance of the list item marker if 'list-style-image' has the value 'none' or if the image pointed to by the URI cannot be displayed; this problem does not arise if the list-style URLs are unquoted or delimited with \" sequences:

document.getElementById("heading" + num).style.listStyle = "inside url(\"littledash.gif\")";

With all three URL quote formats, Netscape toggles the heading# image markers without incident.

If you'd like the links to open in new browser windows, then you could somewhat tediously add target="_blank" attributes to all of the anchor element start-tags in the list HTML, but you can also accomplish this via a single line of JavaScript:

for (i = 0; i < document.links.length; i++) { document.links[i].target = "_blank"; }
/* Validation note: for XHTML-compliance, externalize the script element code if the above line is included. */


Try it all out in the div below; per the discussion/code above, you can drop down and pull up the Goodies Tutorials, Great Sites, and News Sites menu links by clicking on the heading The small plus image/The small minus image image markers or on the headings themselves:

We'll return to HTML Goodies' JavaScript Script Tips in the next post and take up the Script Tips #79-80 Script, which subtracts markup tags from a document or document fragment.


Does this work in Firefox?
Just now I tried out the demo with Firefox 3.0.4 - it works fine.
Post a Comment

<< Home

Powered by Blogger

Actually, reptile7's JavaScript blog is powered by Café La Llave. ;-)