A Bulletproof Approach
To simplify the structure of this box, we'll strip away the tables in favor of minimal markup. We'll then
As always, to get things started, let's decide how best to structure the box with markup. THE ENDLESS CHOICES FOR MARKUP
In assessing what we need in terms of markup for this design, let's refamiliarize
Figure 4.5 illustrates the basic framework we're dealing with. We'll need an outer container for the box to hold everything and create the border. Inside, the three teasers each contain an image floated to one side,
Figure 4.5. This wireframe of the structure will help us lay out our example.
Because I know what we'll be up against further on, I know we need an element that also
With that said, we can weigh our options in terms of the markup we choose here. As in most things Web design, there are no wrong choicesonly choices and better choices. USING DEFINITION LISTS
Definition lists are underused in my opinion,
<dl> <dt>This is the Term</dt> <dd>This is the description.</dd> </dl>
In its specification for definition lists (www.w3.org/TR/html4/struct/lists.html#h-10.3) the W3C hints at other uses for these elements, by suggesting that a) definition lists can contain multiple terms and/or definitions and b) that definition lists can also be used for other applications, for example a dialogue that could be
[View full width]
It's b) that I (and other designers) have taken to heart, using definition lists for a variety of markup applications to provide a more meaningful and clearly organized structure.
So, with that in mind, I've
THE MARKUP STRUCTURETo make things more interesting (although I suppose furniture can be interesting), I'll be swapping out the Furniture Shack content for something of my own, featuring a few photos from a recent trip to Sweden. Each tease will consist of a definition list containing the title as the definition term and the image and description as… well, descriptions of that title. As mentioned earlier, we'll also need an outer containing element to set a width and the border that surrounds the entire component. With all of that mapped out, our simple markup structure looks like this:
<div id="sweden">
<dl>
<dt>Stockholm</dt>
<dd><img src="img/gamlastan.jpg" width="80" height="80" alt="Gamla Stan" /></dd>
<dd>This was taken in Gamla Stan (Old Town) in a large square of amazing buildings.</dd>
</dl>
<dl>
<dt>Gamla Uppsala</dt>
<dd><img src="img/uppsala.jpg" width="80" height="80" alt="Gamla Uppsala" /></dd>
<dd>The first three Swedish kings are buried here, under ancient burial mounds.</dd>
</dl>
<dl>
<dt>Perpetual Sun</dt>
<dd><img src="img/watch.jpg" width="80" height="80" alt="Wristwatch" /></dd>
<dd>During the summer months, the sun takes forever to go down. This is a good thing.</dd>
</dl>
</div>
We've given the outer container an id of sweden , and inside we have three definition lists, each containing a title, followed by an associated image and short description. At this point, you may be wondering why we chose to use three separate <dl> s as opposed to one big list. The reasoning here will be revealed a bit later.
note
SANS STYLE
Without any style applied to our markup, the structure is still apparent when
Figure 4.6. With CSS disabled, or not applied, the structure of the example is still readable and easily
|
|
|
A default font of
Arial
has been set on the entire page, with
font-
|
We could have assigned
padding
to this outer container as well, but since we're declaring a set width, we can avoid having to use the Box Model Hack (see Chapter 1, "Flexible Text") to prevent IE5/Win from calculating the wrong dimension. Instead, we'll assign margins to the definition lists that live
within
#sweden
. (Would these lists be
To make things easy to control later on, one step we need to take before going any further is to add a class to each <dd> element that holds the image. Because we'll float the image (and not the second <dd> that holds the description text) we need a way to uniquely identify that element in the markup, so that we may later apply style to it with CSS:
[View full width]
[View full width]
<div id="sweden"> <dl> <dt>Stockholm</dt> <dd class="img" ><img src="img/gamlastan.jpg" width="80" height="80" alt="Gamla Stan" /></dd> <dd>This was taken in Gamla Stan (Old Town) in a large square of amazing buildings.</dd> </dl> <dl> <dt>Gamla Uppsala</dt> <dd class="img" ><img src="img/uppsala.jpg" width="80" height="80" alt="Gamla Uppsala"/></dd> <dd>The first three Swedish kings are buried here, under ancient burial mounds.</dd> </dl> <dl> <dt>Perpetual Sun</dt> <dd class="img" ><img src="img/watch.jpg" width="80" height="80" alt="Wristwatch" /></dd> <dd>During the summer months, the sun takes forever to go down. This is a good thing.</dd> </dl> </div>
With each <dd> that contains the image flagged with a class="img" , we're now prepared to move on.
Let's now apply base styles for each tease, leaving only the positioning of the image to be done a bit later.
To evenly apply 20 pixels of space around the teasers as well as the inside of the box (Figure 4.8), we'll break up the margins between the containing
<div>
and the teasers
#sweden {
width: 300px;
padding: 10px 0;
border: 2px solid #C8CDD2;
}
#sweden dl {
margin: 10px 20px;
padding: 0;
}
note
|
|
Unfortunately, IE5/Win incorrectly calculates the width of a box by subtracting any padding that is added to it. Other browsers correctly
add
padding to any specified width. There are ways around this, most commonly using the Box Model Hack described back in Chapter 1, "Flexible Text," where two different width values can be
|
Figure 4.9 shows the results of adding the margins and padding. We've also zeroed out any default padding that may be attached to definition lists. And the box is already looking better.
#sweden {
width: 300px;
padding: 10px 0;
border: 2px solid #C8CDD2;
}
#sweden dl {
margin: 10px 20px;
padding: 0;
}
#sweden dt {
margin: 0;
padding: 0;
font-size: 130%;
letter-spacing: 1px;
color: #627081;
}
Looking at Figure 4.10, you'll notice that we've increased the size of the title, added the lovely slate-blue
note
|
|
I'm using the Safari browser throughout this example, taking advantage of Mac OS X's beautiful antialiasing of text. You could get similar results using Windows XP with ClearType enabled. Users of other operating systems would receive mixed results. |
We'll also want to add a bit of style to the <dd> elements as well, matching the smaller, gray text from the Furniture Shack example:
#sweden {
width: 300px;
padding: 10px 0;
border: 2px solid #C8CDD2;
}
#sweden dl {
margin: 10px 20px;
padding: 0;
}
#sweden dt {
margin: 0;
padding: 0;
font-size: 130%;
letter-spacing: 1px;
color: #627081;
}
#sweden dd {
margin: 0;
padding: 0;
font-size: 85%;
line-height: 1.5em;
color: #666;
}
Figure 4.11 shows the results, with the short description text now looking smaller and gray. We've also increased the line-height (the space between lines of text) to one and a half times the height of normal text. This lets the description breathe a bit more. Also important is the removal of the default indenting that's often applied to <dd> elements by the browser. We've overridden that by zeroing out margins and padding.
Our next challenge is to position the image to one side of both the title and description. For now, let's worry about
Because of the order in which things appear in the markuptitle, image, then descriptionif we simply just float the image to the left we'll have the title always sitting above everything else (Figure 4.12). What we really want is the top of the image and title to be aligned at the same level.
In the past, I've swapped the order of elements to make this work,
You may remember the "opposing floats" method explained in Chapter 3, "Expandable Rows." Essentially, we used the
float
property to place two elements on
Remember that we've previously tagged <dd> elements that contain the image with a class="img" which allows us to float images within those elements to one side while keeping the descriptions in place.
So, to begin let's float <dt> elements right and images left :
#sweden {
width: 300px;
padding: 10px 0;
border: 2px solid #C8CDD2;
}
#sweden dl {
margin: 10px 20px;
padding: 0;
}
#sweden dt {
float: right;
margin: 0;
padding: 0;
font-size: 130%;
letter-spacing: 1px;
color: #627081;
}
#sweden dd {
margin: 0;
padding: 0;
font-size: 85%;
line-height: 1.5em;
color: #666;
}
#sweden dd.img img {
float: left;
}
By using the opposing floats method, we can position the image to the left of both the title and description, regardless of the fact that the description comes first in the markup (Figure 4.13).
Notice that, while we've successfully positioned the image the description has slipped in between the image and title. To fix this, we need to apply a little math to set up a grid-like layout for each tease.
Quite simply, we just need to assign a width on the <dt> elements, forcing them to span across the top of each description on their own line. To calculate this width, let's start with the total width of the box (300 pixels), minus the margins around each definition list (20 pixels times 2), minus the width of the image (80 pixels). The result is 180 pixels (Figure 4.14).
By simply adding a width of 180px to the declaration for <dt> elements, we ensure that things start falling into their intended places:
#sweden dt {
float: right;
width: 180px;
margin: 0;
padding: 0;
font-size: 130%;
letter-spacing: 1px;
color: #627081;
}
Figure 4.15 shows where we are at this point, having successfully positioned the image, title, and description via opposing floats.
Thus far in the example, each description has been long enough to
When you are first learning how to use floats, understanding how they need to be properly cleared can be tricky. When an element is floated, it is taken out of the normal flow of the document and doesn't affect the vertical stacking of elements that follow it. Floated elements will always extend beyond the height of their containers. If the description happens to be long enough to meet or exceed the bottom of the floated image, then all is right with the world. But if the content next to the floated image is shorter , that's when you'll run into problems.
Figure 4.17 shows the outline of the definition list marked in red. You can see that the image is taller than the title and description combined in the first tease. And since the image is floated left, the next definition list in line will attempt to wrap around it. What we need is a way to clear the floated image before going on to the next tease. For example, in the old days one might add the following to clear any previously declared in the markup: <br clear="all"> . This works, but is rather unnecessary when we're dealing with CSS-based designs, not to mention that the clear attribute is considered invalid in recent XHTML specifications (XHTML 1.0 Strict, XHTML 1.1).
There
are
several ways to clear floats using CSS, and to get a handle on many of them, I
tip
|
|
For more
|
For this example, we'll use the "Set a Float to Fix a Float" method that Eric describes in his article. Essentially, a container will stretch to fit around floated elements within itif the container is also floated.
Taking Eric Meyer's advice, we want to float each <dl> left in order to force each teaser below the floated image above it. In addition, we need to float the entire containing <div> , ensuring that the border will enclose all of the floated elements within it:
#sweden {
float: left;
width: 300px;
padding: 10px 0;
border: 2px solid #C8CDD2;
}
#sweden dl {
float: left;
margin: 10px 20px;
padding: 0;
}
#sweden dt {
float: right;
width: 180px;
margin: 0;
padding: 0;
font-size: 130%;
letter-spacing: 1px;
color: #627081;
}
#sweden dd {
margin: 0;
padding: 0;
font-size: 85%;
line-height: 1.5em;
color: #666;
}
#sweden dd.img img {
float: left;
}
Adding the previous rules to our example, we have properly cleared floats, with each tease ending up below the otherregardless of description length (Figure 4.18).
Our next step is to add a quick fix for both IE/Win and IE/Mac.
When adding a left or right margin to a floated element, IE/Win can have the unfortunate tendency to
double
the margin on the same side as the float direction (i.e., right-hand margin for right floats, left margin for left floats, www.positioniseverything.net/explorer/
Luckily, there's an easy fix, described in an article on the "Position Is Everything" Web site (www.positioniseverything.net/explorer/doubled-margin.html). The article explains that adding the rule
display: inline;
to the floated element mysteriously triggers IE/Win to correctly apply margins. Fortunately, this rule also has no ill effects on other browsers, so simply slide this little rule in and we're ready to move on. We've labeled the fix with a comment, so that others might understand why we added it. You could even go a step further and quarantine this browser-specific fix to a separate part of the stylesheet or even a separate file altogether. I'll go more
#sweden dl {
float: left;
margin: 10px 20px;
padding: 0;
display: inline; /* fixes IE/Win double margin bug */
}
To cure IE/Mac's affliction of stretching floated elements wider than the specified width of their container, we need to add a width to each <dl> element if we want to play nice with IE/Mac fans.
Specifying a width here is rather harmless, since we're already locking this box down to a fixed width. We're more
#sweden dl {
float: left;
width: 260px;
margin: 10px 20px;
padding: 0;
display: inline; /* fixes IE/Win double margin bug */
}
note
|
|
I've come up with a width of 260 pixels by taking our total width for the box of 300 pixels and then subtracting the 20-pixel margin from each side. |
With the clearing of our floats
To put the final polish on this example, let's adjust the spacing between images and text, and later allow for floating the image both to the left and right.
To adjust the spacing between the images and text, we'll just have to add a right margin to the image, then subtract that amount from the width we've defined for the <dt> elements. While we're at it, let's also add a little framed border around each image. We can fold these additions into the master style sheet for this example, where you can see that the CSS remains rather compact:
#sweden {
float: left;
width: 300px;
padding: 10px 0;
border: 2px solid #C8CDD2;
}
#sweden dl {
float: left;
width: 260px;
margin: 10px 20px;
padding: 0;
display: inline; /* fixes IE/Win double margin bug */
}
#sweden dt {
float: right;
width: 162px;
margin: 0;
padding: 0;
font-size: 130%;
letter-spacing: 1px;
color: #627081;
}
#sweden dd {
margin: 0;
padding: 0;
font-size: 85%;
line-height: 1.5em;
color: #666;
}
#sweden dd.img img {
float: left;
margin: 0 8px 0 0;
padding: 4px;
border: 1px solid #D9E0E6;
border-bottom-color: #C8CDD2;
border-right-color: #C8CDD2;
background: #fff;
}
Figure 4.20 shows the results of the new styles added. We've added an 8-pixel margin to the right of each floated image, as well as 4 pixels of padding and a 1-pixel border around the image itself to create a frame. Since we've added this extra width, we have to add all that up, then subtract that total from the width we previously set on <dt> elements. The math goes like this: 8-pixel right margin + 4-pixel padding on both sides + 1-pixel border on both sides = 18 pixels. So, as you can see, we've dropped the width for <dt> elements down to 162 pixels to accommodate the extra space that the image will now take up.
For the border around the image, we've chosen to make the right and bottom edges a slightly
Another aspect of the original Furniture Shack example that we'll want to replicate is that the side to which each image floats swaps back and forth. One tease will have the image aligned left, while another will have it aligned right. We want to build in the ability to change this at will, with a simple class="alt" added to the <dl> when a swap is desired.
First, we tag the <dl> that we'd like to change float direction on. We've chosen the second teaser:
[View full width]
[View full width]
<div id="sweden"> <dl> <dt>Stockholm</dt> <dd class="img"><img src="img/gamlastan.jpg" width="80" height="80" alt="Gamla Stan" /></dd> <dd>This was taken in Gamla Stan (Old Town) in a large square of amazing buildings.</dd> </dl> <dl class="alt" > <dt>Gamla Uppsala</dt> <dd class="img"><img src="img/uppsala.jpg" width="80" height="80" alt="Gamla Uppsala" /></dd> <dd>The first three Swedish kings are buried here, under ancient burial mounds.</dd> </dl> <dl> <dt>Perpetual Sun</dt> <dd class="img"><img src="img/watch.jpg" width="80" height="80" alt="Wristwatch" /></dd> <dd>During the summer months, the sun takes forever to go down. This is a good thing.</dd> </dl> </div>
Having added the alt class to the second tease, we can now include a few rules at the end of our style sheet that will override the default, which currently aligns the image to the left. The alt style will reverse the direction, floating the image on the right . This class could be swapped in and out at will, giving site editors easy control over the layout of the box.
The following CSS should be placed after the previous declarations we've already written:
/* reverse float */
#sweden .alt dt {
float: left;
}
#sweden .alt dd.img img {
float: right;
margin: 0 0 0 8px;
}
Here we're telling the browser that it should do the following:
For <dt> elements within a <dl> marked with the alt class, float those left (instead of the default right).
Float images within the alt class right (instead of the default left).
Change the 8-pixel margin that was to the right of the image over to the left instead.
Figure 4.22 shows the results of adding these two little declarations to the style sheet. Because the second tease is marked with the alt class, its image is aligned to the right. The idea here is that we can add or remove a simple class at any time to assign the float direction for a particular image.
If we were dealing with longer descriptions (or if the
This could be the intended effect, but if a more column-like grid is what you're after, applying a margin to the description will keep the text and images away from each other.
The width of the margin that we'll add to the description should equal the width of the image, plus padding, borders, and margin already specified between the image and description (Figure 4.24).
So by adding a left margin of
98px
to all
<dd>
elements, and then overriding that value to
for
<dd class="img">
elements (since we don't want the
image
to have a margin, yet it resides inside a
<dd>
) we'll in a sense be creating
To reverse the margins for the alt class when the image is floated right instead of left, we need to add another rule to our "reverse float" section at the end of the style sheet:
#sweden {
float: left;
width: 300px;
padding: 10px 0;
border: 2px solid #C8CDD2;
}
#sweden dl {
float: left;
width: 260px;
margin: 10px 20px;
padding: 0;
display: inline; /* fixes IE/Win double margin bug */
}
#sweden dt {
float: right;
width: 162px;
margin: 0;
padding: 0;
font-size: 130%;
letter-spacing: 1px;
color: #627081;
}
#sweden dd {
margin: 0 0 0 98px;
padding: 0;
font-size: 85%;
line-height: 1.5em;
color: #666;
}
#sweden dl dd.img {
margin: 0;
}
#sweden dd.img img {
float: left;
margin: 0 8px 0 0;
padding: 4px;
border: 1px solid #D9E0E6;
border-bottom-color: #C8CDD2;
border-right-color: #C8CDD2;
background: #fff;
}
/* reverse float */
#sweden .alt dt {
float: left;
}
#sweden .alt dd {
margin: 0 98px 0 0;
}
#sweden .alt dd.img img {
float: right;
margin: 0 0 0 8px;
}
Notice that we've added a declaration that resets the margin value to
for
<dd>
elements that are flagged with
class="img"
. This will override the
right
margin set in the "reverse float" section further down the style sheet. It will also save us from repeating the override after the
#sweden .alt dd
declaration
Figure 4.25 shows the results of the previous additions to the style sheet. You can see that with the text size significantly increased, and/or with longer descriptions, the text and image both stick to their respective "columns," as if we'd used a table here for layout.
As a final touch to this example, let's trade in the solid blue border that surrounds the box for a background image that fades to white. We'll create the image in Photoshop, at a width of 304 pixels (300 pixels + a 2-pixel border on both sides).
Figure 4.26 shows the completed image, which we created by filling a bordered box with a lighter shade of blue and then using the Gradient tool (Figure 4.27) to fade white to transparent from bottom to top.
To reference this image in our style sheet, we just adjust the declaration for the main containing <div> :
#sweden {
float: left;
width: 304px;
padding: 10px 0;
background: url(http://flylib.com/books/2/68/1/html/2/img/bg.gif) no-repeat top left;
}
We've adjusted the width of the container from 300 pixels to 304 pixels to account for the loss of the 2- pixel border (which is now part of the background image) and we've aligned the fade top and left. Because it fades to white (the background color of the page) and is aligned at the top, we need not worry about what's contained in the box; it will accommodate any height, with its contents just spilling out of the fade. Another plus is that I happen to think it just looks cool (Figure 4.28).
If we zoom in on the top image, you can see that the