Publishers of technology books, eBooks, and videos for creative people

Home > Articles > Web Design & Development > Usability

  • Print
  • + Share This
This chapter is from the book

A Bulletproof Approach

To simplify the structure of this box, we’ll strip away the tables in favor of minimal markup. We’ll then turn to our friend CSS to replicate the grid-like layout of the teasers (the image/title/description grouping), while still creating a compelling design.

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 ourselves with our goal by sketching out what we need in the way of structure.

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, alongside a title and short description.

Figure 4.5

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 surrounds each teaser. This element will group each image, title, and description together as a unit. And semantically, this makes sense as well, isolating each discrete chunk (or teaser) with a containing element.

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 choices—only choices and better choices.

Using definition lists

Definition lists are underused in my opinion, especially for applications that aren’t an obvious title and description pairing (as they are commonly used for). A definition list consists of an outer <dl> element, with any number of definition terms <dt> and descriptions <dd>:

<dl>
  <dt>This is the Term</dt>
  <dd>This is the description.</dd>
</dl>

In its specification for definition lists (http://www.w3.org/TR/html5/grouping-content.html#the-dl-element), the W3C hints at other uses for these elements by suggesting that a) definition lists can contain multiple terms and/or definitions and b) definition lists can also be used for “...terms and definitions, metadata topics and values, questions and answers, or any other groups of name-value data.” Or also, for example, a dialogue that could be marked up like so:

<dl>
  <dt>Younger Cop</dt>
  <dd>And was there anything of value in the car?</dd>
  <dt>The Dude</dt>
  <dd>Oh, uh, yeah, uh... a tape deck, some Creedence tapes, and there was a, uh... uh, my briefcase.</dd>
  <dt>Younger Cop</dt>
  <dd>[expectant pause] In the briefcase?</dd>
  <dt>The Dude</dt>
  <dd>Uh, uh, papers, um, just papers, uh, you know, uh, my papers, business papers.</dd>
  <dt>Younger Cop</dt>
  <dd>And what do you do, sir?</dd>
  <dt>The Dude</dt>
  <dd>I'm unemployed.</dd>
</dl>

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 chosen to use a series of definition lists to structure each image, title, and description.

The markup structure

To 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 past 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:

<article 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>
</article>

We’ve given the outer <article> (a new HTML5 element) 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.

Sans style

Without any style applied to our markup, the structure is still apparent when viewed in a browser (Figure 4.6).

Figure 4.6

Figure 4.6 With CSS disabled, or not applied, the structure of the example is still readable and easily understood.

Typically, a browser will indent <dd> elements, making it easier to view the relationship between them and the <dt> elements that precede them. Because we’ve chosen lean, simple markup, any device or browsing software should have no problems whatsoever understanding what we’re delivering here. But it doesn’t exactly look the way we want it to yet. Let’s start adding some style.

Styling the container

To begin, let’s add a declaration that will set a width and blue border around the entire list. We’ll add these styles to the outer <article> previously marked with id="sweden".

#sweden {
  width: 300px;
  border: 2px solid #C8CDD2;
  }

By setting a width of 300px and a colored border around our entire box, we end up with the results shown in Figure 4.7.

Figure 4.7

Figure 4.7 Setting a width of 300 pixels contains everything within the <article>.

Identifying the image

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:

<article 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>
</article>

With each <dd> that contains the image flagged with a class="img", we’re now prepared to move on.

Applying base styles

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 <article> and the teasers themselves. First, let’s apply 10 pixels of padding to the top and bottom of the containing <article id="sweden">. Then, we’ll apply 10-pixel margins on the top and bottom of each <dl>, as well as 20-pixel margins on both the left and right of each <dl>.

Figure 4.8

Figure 4.8 Our goal is a consistent gutter of 20 pixels (marked in gray) that flows around the inside of the box and its teasers.

#sweden {
  width: 300px;
  padding: 10px 0;
  border: 2px solid #C8CDD2;
  }
#sweden dl {
  margin: 10px 20px;
  padding: 0;
  }

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.

Figure 4.9

Figure 4.9 With margins and padding distributed among the elements, the box begins to take shape.

Next, let’s introduce color and custom text treatment to the title of each tease by styling <dt> elements within our box:

#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 shade, and increased space between letters by a fraction using the letter-spacing property, mimicking the style from the Furniture Shack example, where images were used in place of styled text.

Figure 4.10

Figure 4.10 Simple text styling can do wonders for a component’s design, and often eliminates the need for image-based type.

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 over-ridden that by zeroing out margins and padding.

Figure 4.11

Figure 4.11 To match the Furniture Shack example, we’ve decreased the size of the description and made the text gray.

Positioning the image

Our next challenge is to position the image to one side of both the title and description. For now, let’s worry about lining things up on the left only. Later, we’ll address how best to alternate the alignment as seen in the Furniture Shack example.

Because of the order in which things appear in the markup—title, image, then description—if 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.

Figure 4.12

Figure 4.12 With the image coming after the title in the markup, just floating it to one side leaves the title above everything.

In the past, I’ve swapped the order of elements to make this work, putting the image in the <dt> element and using <dd> elements for both the title and description. Because the image appeared first, floating to either side would allow us to line it up just right. But semantically, it makes far more sense to have the title be the definition term, followed by an image and text that describe that title (as we’ve done in our markup structure for this example). It takes only a little more CSS magic to have the best of both worlds: optimal markup structure and the image to one side of both the title and description.

Opposing floats

You may remember the “opposing floats” method explained in Chapter 3, “Expandable Rows.” Essentially, we used the float property to place two elements on opposite ends of a container. We use the same method here, allowing us to align the image to the left of both the title and the short description while keeping the markup in an optimal order.

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 title comes first in the markup (Figure 4.13).

Figure 4.13

Figure 4.13 Here we see opposing floats at work, aligning the tops of the image and title.

Notice that while we’ve successfully positioned the image, the description has slipped 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).

Figure 4.14

Figure 4.14 Determining the width for the <dt> elements involves a little calculation.

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.

Figure 4.15

Figure 4.15 With the width assigned for <dt> elements, the items fall into place.

Clear the way for any description length

Thus far in the example, each description has been long enough to roughly meet the bottom of each image. Because of this length, we haven’t yet had to worry about clearing the floats. To illustrate what could happen when the description is shortened, take a look at Figure 4.16. Not exactly bulletproof, is it?

Figure 4.16

Figure 4.16 With a shorter description, the floated images can lead to undesired results.

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 teaser. 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 teaser. For example, in the old days one might add <br clear="all"> to clear any previously declared floats in the markup. 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 HTML specifications. What we’d rather do is use CSS (and not markup) to clear floats, and we’ll explore a few ways to do just that next.

Figure 4.17

Figure 4.17 The red box shows where the <dl> containing the float really ends.

Self-clearing floats

There are several ways to clear floats using CSS, and to get a handle on many of them (and why problems arise), I encourage you to start off by reading CSS guru Eric Meyer’s article “Containing Floats” (www.complexspiral.com/publications/containing-floats/).

I’m going to share three popular methods for self-clearing floats—that is, the process of applying CSS to a container that has floated elements inside it. By self-clearing the floats within, it keeps the container independent, regardless of what comes before or after it in the flow of the document. This is a key element of being bulletproof: If we keep “modules” (containers of various mini-layouts) independent, they stand a better chance of staying intact if moved around, changed, or edited later by either you or your client or boss. Self-clearing is essential for that modularization when you’re using floats and requires no extra markup (such as <br clear="all">).

Let’s look at three ways to do this, applying each method to our example:

  • The “Set a Float to Fix a Float” method (described in Eric Meyer’s article and used previously in this book). This technique often depends on what comes after the container on the page, but this cross-browser method is simple to implement.
  • The “Simple Clearing of Floats” method using the overflow property. This is probably the simplest method to implement but has some possible side effects. It’s described in detail at SitePoint: www.sitepoint.com/blogs/2005/02/26/simple-clearing-of-floats/.
  • The “Easy Clearing” method using generated content (described at http://positioniseverything.net/easyclearing.html). This method requires jumping through a few hoops for Internet Explorer, but once you grasp the idea, I think it’s the most solid choice.

First, we’ll use the “Set a Float to Fix a Float” method and apply that to our example.

Setting a float to fix a float

Essentially, a container will stretch to fit around floated elements within it—if the container is also floated. So, 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 <article>, 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 teaser ending up below the other—regardless of description length (Figure 4.18).

Figure 4.18

Figure 4.18 Even with a short description, we have properly cleared floats.

The finishing touches

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 stylesheet 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;
  }
#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.19 shows the results of the new styles. 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.

Figure 4.19

Figure 4.19 We’ve achieved proper spacing between images and text.

For the border around the image, we’ve chosen to make the right and bottom edges a slightly darker shade than the top and left. This creates a subtle three-dimensional effect on the photo, as if it’s lying on top of the box (Figure 4.20).

Figure 4.20

Figure 4.20 A simple trick for creating dimension is to use darker right and bottom borders.

Toggling the float direction

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 teaser 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:

<article 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 teaser, we can now include a few rules at the end of our stylesheet 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.21 shows the results of adding these two little declarations to the stylesheet. Because the second teaser 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.

Figure 4.21

Figure 4.21 Toggling the image alignment is as simple as adding or removing the alt class.

The grid effect

If we were dealing with longer descriptions (or if the user increased the text size), we’d find that the description text would wrap down around the image. That’s the nature of a float: It will take up as much space as it needs to but will let content flow around it (Figure 4.22).

Figure 4.22

Figure 4.22 Longer descriptions will wrap around the floated image.

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 the padding, borders, and margin already specified between the image and description (Figure 4.23).

Figure 4.23

Figure 4.23 Adding the image width, margin, padding, and border together comes to 98 pixels.

So by adding a left margin of 98px to all <dd> elements and then overriding that value to 0 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 columns on either side.

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 stylesheet:

#sweden {
  float: left;
  width: 300px;
  padding: 10px 0;
  border: 2px solid #C8CDD2;
  }
#sweden dl {
  float: left;
  width: 260px;
  margin: 10px 20px;
  padding: 0;
  }
#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 0 for <dd> elements that are flagged with class="img". This will override the right margin set in the “reverse float” section farther down the stylesheet. It will also save us from repeating the override after the #sweden .alt dd declaration assigns a right margin that we again don’t want showing up on <dd> elements that contain our floated image.

Figure 4.24 shows the results of the previous additions to the stylesheet. 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.

Figure 4.24

Figure 4.24 With a margin applied to the description, it’s as if the text is held within columns.

An alternate background

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 plus a 2-pixel border on both sides).

Figure 4.25 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.26) to fade white to transparent from bottom to top.

Figure 4.25

Figure 4.25 We created a blue background by using the Gradient tool.

Figure 4.26

Figure 4.26 You’ll find the Gradient tool in the Tools palette in Photoshop.

To reference this image in our stylesheet, we just adjust the declaration for the main containing <article>:

#sweden {
  float: left;
  width: 304px;
  padding: 10px 0;
  background: url(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.27).

Figure 4.27

Figure 4.27 Here is our completed, bulletproof example.

If we zoom in on the top image, you can see that the padded frame remains white on top of the blue background (Figure 4.28). You may remember that we assigned a background: #FFF; in addition to 4px of padding on the floated images to accomplish this. If we hadn’t specified a background color here, then the blue fade would show through the image’s frame.

Figure 4.28

Figure 4.28 Combining padding and a background color creates a frame around the image.

Applying a box-shadow

As an additional detail, let’s apply a CSS3 box-shadow to each thumbnail image. The box-shadow property is a wonderfully flexible way of adding shadows to elements without the need to add extra markup or images to the design. The support for box-shadow is also decent in recent browsers—but again it’s one of those nonessential treatments that is often unmissed in browsers that don’t support it.

To add a subtle drop-shadow to each image in our example, we need to add just a few rules to the following declaration:

#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;
  -webkit-box-shadow: 1px 1px 3px rgba(0,0,0,.12);
  -moz-box-shadow: 1px 1px 3px rgba(0,0,0,.12);
  box-shadow: 1px 1px 3px rgba(0,0,0,.12);
  }

Here we’re adding a box-shadow with the appropriate vendor prefixes for WebKit and Mozilla browsers. As usual, we always end with the non-prefixed version of the property for future proofing.

The syntax for box-shadow takes a top and left coordinate for where the shadow should begin from in relation to the element (in this case 1px from the top and 1px from the left). The third value in the rule tells the browser how much blur to apply to the shadow (in this case 3px of blur). Finally, we define the color of the shadow. Here we’re using an RGBA value, which will allow us to set the color as partially transparent, letting whatever background is behind the thumbnail blend in. I almost always use RGBA values when setting box-shadows. In this particular case, we are setting 0,0,0 (the RGB value of black) at .12 (or 12%) opacity.

Figure 4.29 shows the results in Safari after adding the box-shadow rules. For browsers that don’t yet support box-shadow (e.g., IE8 and below), they’ll safely ignore those rules and not display the shadow. No harm done.

Figure 4.29

Figure 4.29 A zoomed-in view of the thumbnail image with subtle box-shadow rendering in Safari.

The nice thing about using box-shadow for drop shadows, rather than attaching images, is that the shadows don’t require space to be allotted in the layout. In other words, the shadows will bleed out into gutters or other areas of the site that aren’t explicitly accounted for in the stylesheet. Historically, you’d need to create the space where the shadow appears with padding, or extra markup with specific widths. With box-shadow, it either adds the shadow where it needs to, or doesn’t (if the browser doesn’t support the property). Worry-free bulletproofing.

More float-clearing fun

We’ve just finished the example using the “float to fix a float” method that’s been used previously in the book. We floated each <dl> in order to clear the opposing floats that were contained within.

This is a simple concept to grasp—and an easy method to implement cross-browser. But it’s somewhat reliant on a few things: We must set a width on the container (so that the floated containers stack vertically), and we must anticipate what comes before or after the container of floats (since we could run into issues with the floated container needing to be cleared as well, thus starting a vicious, never-ending cycle).

So while floating a container to clear floats within it can work in certain circumstances, there are other methods that are consistent regardless of the scenario. Let’s take a look at a few more options.

Simple clearing of floats using the overflow property

Applying the overflow property on a container will self-clear any floats within it (see Alex Walker’s article at SitePoint: www.sitepoint.com/blogs/2005/02/26/simple-clearing-of-floats/). The approach is simple and easy to implement, although it’s not obvious that it will work under most circumstances. But it does.

Using our example, if we removed the floats from each <dl> and replaced them with overflow: auto, we’d be achieving the same goal.

Here’s the original declaration:

#sweden dl {
  float: left;
  width: 260px;
  margin: 10px 20px;
  padding: 0;
  }

And here it is with the overflow trick to clear floats instead:

#sweden dl {
  overflow: auto;
  width: 260px;
  margin: 10px 20px;
  padding: 0;
  }

Now in most circumstances, the overflow trick will likely work out fine—but there are situations where it could become problematic. We’ve used the value auto, which could trigger scrollbars around the element should its contents be wider than its specified width (260px). So that’s one possible scenario. You could also specify overflow: hidden; instead of overflow: auto;. The hidden value will (you guessed it) hide its contents should they exceed the container’s width.

If you’re positive that neither of those scenarios will happen, then perhaps overflow is worth a shot. As for me, I’m more likely to want a solution that I don’t have to worry about in the future—and that’s just what we’ll get with the next method.

Easy clearing using generated content

The most robust, reliable solution for self-clearing I’ve found is documented in an article at Position Is Everything: “How to Clear Floats Without Structural Markup” (http://positioniseverything.net/easyclearing.html). The idea is rather clever: It uses the :after pseudo-element in CSS (www.w3.org/TR/CSS21/selector.html#before-and-after) to insert a period after the container of floats. The clear: both rule is also added to clear all floats, and then the period is hidden. Let’s take a look at the declaration in action:

#sweden dl {
  width: 260px;
  margin: 10px 20px;
  padding: 0;
  }
#sweden dl:after {
  content: ".";
  display: block;
  height: 0;
  clear: both;
  visibility: hidden;
  }

For the main #sweden dl declaration, we don’t need to add float or overflow as we did for the previous methods. It’s the next declaration that does the float-clearing magic, so let’s break it down and figure out exactly what is happening here.

We’re essentially saying, “Put a period after each definition list (content: "."; will do that), clear all floats that precede them (clear: both;), and then make sure the period is hidden (height: 0; and visibility: hidden;)." Pretty crafty, eh?

By using the :after pseudo-element to self-clear any floats, we’ve done so without having to float the container, and we don’t have to worry that overflow may cause issues down the road.

If only this worked in *cough* Internet Explorer. Yes, that’s right, IE6 and 7 don’t support the :after pseudo-element (ditto for :before). But not to worry—fortunately, there are additional rules we can target to those specific versions of IE that self-clear floats just as confidently. And the good news is that IE8+ supports the :after and :before pseudo-elements, so no additional trickery is required for the future.

Autoclearing in IE6

Conveniently, IE/Win will do its own “autoclearing” on containers as long as a dimension is applied to it. This isn’t correct behavior, of course, but we’ll use this spec deviation to our advantage. Historically called the “Holly Hack”(named after Holly Bergevin, the hack’s author), it involves setting a height: 1%;, targeted specifically to IE and IE only, that forces the container to expand around its contents (even floated elements). If the height of the container’s contents exceeds 1% (which it almost always will), that’s OK—it will expand as needed, thus ignoring the height rule. Again, this isn’t correct behavior in terms of the spec, but it’s an inconsistency that actually helps us solve this autoclearing problem (among others).

The hack uses the * html selector (which precedes the declaration) and is read only by IE/Win version 6 (we’ll tackle IE7 in just a moment):

* html #sweden dl { height: 1%; }

That one declaration will autoclear any floats in each definition list, and by using the * html hack, you will target IE6 only. Other modern browsers will ignore it, likely because it’s a nonsensical selector—there’s never an element before the <html> element.

So, by offering the :after declaration for modern browsers that recognize it (Mozilla, Firefox, Safari, and so on), as well as the Holly Hack (for IE6), we have a majority of the browser market share covered with solutions that self-clear in a solid, reliable way. Ideally, we’d keep the Holly Hack (and any other IE-specific CSS) quarantined in its own stylesheet (we’ll talk more about why later in Chapter 9).

Solving the IE7 problem

IE7 was released with significantly better standards support—a lot was fixed, and we thank the developers for that. But support for everything that browsers like Firefox, Safari, and Opera have provided for years didn’t materialize—which makes a few things a little tricky. This easy-clearing method is one of them.

IE7 fixed the height: 1%; bug. Where IE6 would expand a container to shrink-wrap its contents—even when that exceeded a dimension specified with CSS—IE7 will now correctly honor that dimension. This is now proper behavior, so we can’t blame the IE7 developers for fixing this. And like other, more standards-aware browsers, IE7 also now ignores declarations that begin with the * html selector, which is also proper behavior.

The problem, though, is that IE7 doesn’t support the :after pseudo-element. And so by fixing the height: 1% bug and not supporting :after, the IE7 developers ensured that we’re stuck in terms of getting the browser to auto-clear floats using one of these methods.

To address this issue, enter this bit of code:

*:first-child+html #sweden dl { min-height: 1px; }

Setting a min-height on a container in IE7 also expands a container in the same fashion that adding a height in IE6 does. That wacky-looking selector that precedes #sweden dl (*:first-child+html) is the piece that targets IE7 and IE7 only.

Hooray! Now we have the three pieces in place that will self-clear things in the most popular browsers. Let’s take a look at all of them together in one place:

#sweden dl:after { /* for browsers that support :after */

  content: " .";
  display: block;
  height: 0;
  clear: both;
  visibility: hidden;
  }
* html #sweden dl { height: 1%; } /* for IE5+6 */
*:first-child+html #sweden dl { min-height: 1px; } /* for IE7 */

Again, ideally the patches that target IE specifically would be placed in a separate stylesheet, kept separate so as to avoid tainting the clean code (more about that in Chapter 9, “Putting It All Together”). But with these three declarations, we have a solid, reliable way of self-clearing floats. The code may seem a bit verbose at first, but once you start using these rules consistently, you’ll find that they become indispensable for creating flexibility without concern that your floats will fall apart in the future.

Combining selectors to save code

You can also combine selectors that share this self-clearing code by building a single declaration instead of repeating them for each container. For instance, suppose you are also self-clearing floats found in the header of the document:

#header:after,
#sweden dl:after { /* for browsers that support :after */
  Acontent: ".";
  display: block;
  height: 0;
  clear: both;
  visibility: hidden;
  }

* html #header,
* html #sweden dl { height: 1%; } /* for IE6 */

*:first-child+html #header,
*:first-child+html #sweden dl { min-height: 1px; } /* for IE7 */

As you’re constructing your layout, you simply add elements to these three declarations as necessary, thus saving you from repeating the code for each.

Choosing what works for you

Now that we’ve looked at three methods for self-clearing, I’d like to point out that (as with almost everything in web design) there’s no one way that is correct 100% of the time. After experimenting with them all, you’ll find that one method might work better than the others for you, depending on the situation.

I like the easy-clearing method because of its robustness in just about any scenario, but I’ll often throw overflow: hidden; on a container when initially building a layout, which is quick and easy to remember while prototyping. Later, I’ll do a quick search for that rule and build the three declarations that make up the easy-clearing method.

Whatever method you choose, the important thing to remember is that self-clearing can be a powerful tool that maintains the flexibility that floats can bring to layout while keeping components of the page independent.

  • + Share This
  • 🔖 Save To Your Account