reptile7's JavaScript blog
Tuesday, November 22, 2011
The Joys of Tables
Blog Entry #233

In today's post we'll tuck into HTML Goodies' "Web Developer Class: Build Your Own JavaScript Content Rotator" tutorial, which is authored by Curtis Dicken. The "Build Your Own JavaScript Content Rotator" tutorial is an outgrowth of the "Build Your Own Image Viewer with Scrollbar" tutorial, also authored by Mr. Dicken, that we discussed in Blog Entries #228 and #229. The latter tutorial codes an "image viewer" - more specifically, a 400px-by-400px image (placeholder) flanked vertically by a caption and a description therefor - that is manipulated by an image scrollbar; the former tutorial reframes the image viewer (sans scrollbar) and animates it:

My Content Slide Show
This is some text about the Grasslands image above. This caption can be as long as you want it to be.
The "Content Rotator" tutorial doesn't provide a demo so I thought I would give you one here and now. Per the tutorial code, the demo cycles three sets of image data. Mousing over the content area will stop the rotation so that you can take a closer look at an image and its description; mousing out from the content area will restart the rotation.

We'll begin our analysis with a look at the new frame's HTML/CSS and then we'll deconstruct the rotation JavaScript in detail - as we'll see, there's plenty of room for tightening up the code in both areas.

The new frame

At the end of the Function - rotateContent section on the tutorial's second page the author says:
Tip: This technique works [the content rotator can be structured] with other elements like div, although I prefer to always use tables and cells so that I can have my rotating content in a nicely aligned and framed area of my page.
The content rotator is housed in a three-row, three-cells-per-row table, whereas each rotation "slide" itself comprises a three-row, one-cell-per-row table. Extensive style information is specified for these tables and it is not at all difficult to convert them to a corresponding div structure; doing this would allow us to shrink the volume of frame HTML. Moreover, it's debatable as to whether the table element is semantically the right choice for structuring the content rotator anyway.

But let's stick with the table framing for the time being. The outer frame table in particular could use some work: no fewer than seven of its nine cells are purely 'spacer' elements that contain no content. For example, here's the outer table's first row:

<table border="0" cellpadding="5" cellspacing="0" style="width: 410px; height: 600px;">
<td style="width: 50px; height: 50px; background-color: black;"></td>
<td style="width: 310px; height: 50px; background-color: black; text-align: center;">
<span style="font-size: 24pt; color: #ffff66;">My Content Slide Show</span></td>
<td style="width: 50px; height: 50px; background-color: black"></td>

We've got a 50px-by-50px spacer square followed by a 310px-by-50px "My Content Slide Show" title cell followed by another 50px-by-50px spacer square. There's no need to use three cells when one will do:

table { border: none; }
#table1 { width: 410px; height: 600px; background-color: black; }
#table1row1, #table1row3 { height: 50px; }
#titleCell { font-size: 24pt; color: #ffff66; }
<table id="table1" cellpadding="5" cellspacing="0">
<tr id="table1row1">
<th id="titleCell">My Content Slide Show</th>

Style for the content rotator tables is in all cases specified at the level of inline markup - I'll be separating it out as we go along.

A generic title is not quite a "header" in my book but more resembles a header than it does data, so I've switched the title cell from a td element to a th element; doing this will allow us to subtract the cell's text-align:center; alignment. The th markup will also bold the title, which I think is appropriate.

The outer table's contentless third row - that would be the solid black bottom part of the frame - can similarly be coded as:

<tr id="table1row3"><td></td></tr>
<!-- Even this seems kind of inefficient, doesn't it? We'll get to the div thing in due course. -->

The outer table's middle row is somewhat more interesting. The middle row comprises a central 310px-by-500px content cell flanked by 50px-by-500px spacer cells. I was originally hoping to subtract the spacer cells, keep the content cell width at 310px, and then center the content cell by giving its parent tr element a text-align:center; style; in the event, Firefox and Opera gave a centered cell once I gave the cell an inline-block display whereas Safari and Chrome gave a row-spanning (width:410px;) cell no matter what I did*. Alternatively and preferably, we can let the content cell span its parent row, not worry about centering it, and transfer its width, height, and white background color to its slide table children.

*I see that HTML 4.01's definition of the width attribute of the td/th element reads, This attribute supplies user agents with a recommended cell width [emphasis added], i.e., there's no ironclad guarantee that a user agent will give you the width you want.

The content cell holds all three rotation slides, which have id identifiers set to contentArea1, contentArea2, and contentArea3, respectively. Here are the start-tags for the content cell and the first slide:

<td style="width: 310px; height: 500px; text-align: center;" onmouseover="rotationStop( );" onmouseout="rotationStart( );">
<table id="contentArea1" border="0" cellpadding="2" cellspacing="0" style="width: 300px; display: inline; position: relative;">

• The first slide is initially given a display:inline; style - tables are normally block-level elements - that in combination with the content cell's text-align:center; style serves to horizontally center the first slide in the content cell. (This is not a large effect when the spacer cells are present: removing the display:inline; declaration shifts the slide two pixels to the left.) However, I see no point in 'inline-izing' the slide table** given that (a) there's no content on either side of the slide and (b) we can horizontally center it by setting its margin-left and margin-right properties to auto.

**There's actually a special inline-table display value for giving a table an inline-level formatting, but again, we don't need it.

• The slides have all been given a position:relative; style, which serves no purpose and should be thrown out.

In sum, my preferred CSS for the outer table's content cell and for the slide table elements is:

#contentCell { height: 500px; }
#contentArea1, #contentArea2, #contentArea3 {
width: 310px; height: 500px; background-color: white; margin-left: auto; margin-right: auto; }

The second and third slides are initially zeroed out by setting their displays to none; this can be carried out scriptically, as can the registrations of the rotationStop( ) and rotationStart( ) event listeners with the content cell:

window.onload = function ( ) {
    document.getElementById("contentArea2").style.display = "none";
    document.getElementById("contentArea3").style.display = "none";
    document.getElementById("contentCell").onmouseover = rotationStop;
    document.getElementById("contentCell").onmouseout = rotationStart; }

The slide tables

There are three parts to each slide table: a caption, an image, and a description; each part gets its own row/cell (that's how it was in the "Image Viewer" tutorial, so this part of the structure is not really "new"). For example, here's the contentArea1 table's caption markup:

<td style="text-align: center;">
<span style="font-size: 16pt;"><strong>Grasslands</strong></span></td>

The Grasslands caption is centered, given a 16pt font-size, and bolded; if we mark it up as a th element, as we should, then we can throw out the text-align:center; style*** and the strong element:

.captionCell { font-size: 16pt; }
<tr><th class="captionCell">Grasslands</th></tr>

***Was this style necessary in the first place? Recall that the outer table's contentCell cell was also given a text-align:center; alignment; as text-align is an inherited property, you might think that the td caption text would be centered as is. In practice, the contentCell cell's text-align:center; style is not passed on to the slide tables - at least it isn't with the browsers on my computer - so yes, it is necessary to explicitly center the caption text, assuming that you do want to center it.

The slide images (img placeholders) have a common width, height, and border (perversely specified in a non-shorthand way); their src URLs respectively point to the imagePath[0], imagePath[1], and imagePath[2] images of the demo for the "Build Your Own Image Scrollbar" tutorial on which the "Image Viewer" tutorial builds.

<!-- The Grasslands image row: -->
<img height="300" src="" style="border-right: 1px solid; border-top:
1px solid; border-left: 1px solid; border-bottom: 1px solid;" width="300" />

If we download the images and rechristen them image1.jpg, image2.jpg, and image3.jpg, then we can alternatively write:

.slideImage { width: 300px; height: 300px; border: 1px solid; }
<tr><td class="imageCell"><img class="slideImage" src="image1.jpg" alt="" /></td></tr>

Lastly, the author wanted the description text to be left-justified and therefore gave the description cells

<td class="descriptionCell" style="text-align: left;">This is some text about the Grasslands image above. This caption can be as long as you want it to be.</td>

a text-align:left; style, which is redundant because (a) the align attribute of the td element has a left default value (for a left-to-right language) and (b) the description cells won't be inheriting the contentCell cell's text-align:center; style, if present (vide supra).

Vertical alignment

You may have noticed in the demo at the outset of the post that the slide tables are vertically centered in the contentCell cell: this is because the valign attribute of the td element has a middle default value.

The height of the original slide tables is about 400 pixels. Maximizing the slide table height to 500px - the contentCell cell height, towards the end of reducing the outer table's middle row to a single cell - redistributes the contentCell cell's excess vertical padding evenly among the slide table cells, thereby pushing apart the slide table cell content. The resulting display is still somewhat centered vertically but doesn't look as nice:

[The 'Grasslands' slide with its added padding when we give it a height of 500px]

(Because the outer table has a cellpadding="5" attribute, increasing the slide table height to a full 500px will add another 10px to the height of the display; you can keep the total display height at 600px by setting the slide table height to 490px.)

The caption, image, and description are all vertically centered in their new cells, although you wouldn't know that without giving the cells a border. Anyway, we can easily scrunch the slide table parts back to their original positions via the following style rules:

.captionCell { vertical-align: bottom; }
.imageCell { height: 306px; }
.descriptionCell { vertical-align: top; }

We're ready to go after the JavaScript part of the tutorial code, and we'll do that in the next entry.


Comments: Post a Comment

<< Home

Powered by Blogger

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