Web Standards: Semantic or Pragmatic?

posted 10th April 2008 15:01

For anyone involved in front-end web development, it’s a scenario that crops up several times a day. The designer has delivered an attractive layout for a section of the page for you to markup and style. Semantically, you know there is a ‘correct’ way to markup the code—but you also know that once the content gets in there, things can start to go wrong.

Here’s a recent example I’ve worked on, and the choices I made to deliver a bulletproof, albeit not as semantic as I might have liked, solution.

The Design

Screenshot of recent updates list of six items arranged two per row

The design calls for a list of recent updates to the site, and the designer had chosen a two-column grid with some nice colours and borders. As it’s a list, my first instinct was of course to mark it up as such—either with a ul or, as the list of updates is in chronological order, an ol:


Recent Updates

  1. Lorem ipsum dolor

    Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Proin odio. Integer non ante.

  2. Lorem ipsum dolor

    Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Proin odio. Integer non ante.

  3. Lorem ipsum dolor

    Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Proin odio. Integer non ante.

  4. Lorem ipsum dolor

    Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Proin odio. Integer non ante.

  5. Lorem ipsum dolor

    Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Proin odio. Integer non ante.

  6. Lorem ipsum dolor

    Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Proin odio. Integer non ante.

And then to style our list items, some simple CSS to float them left. Constrain the width of the parent list and we can line them up, two-by-two:


ol {
  width: 624px;
}
	

ol li { background: #effcfc; border-bottom: 6px solid #d11; float: left; width: 300px; margin-right: 12px; margin-bottom: 18px;
}
ol li img { float: left; margin-right: 12px;
}

All fine and dandy—view the example—our work is done. Or is it?

Known unknowns

While our list items may all line up neatly with identical dummy content, real content is not likely to be quite so uniform. Titles and paragraphs might be longer or shorter than their neighbour, and images may be different sizes or be omitted entirely. Anyone with any experience of CSS floats will know what happens when you try floating blocks of variable height—all it takes is one errant li and the whole grid falls apart. See what happens with just one misplaced sentence.

One solution that you might consider is to set a minimum height for the list-items (so that they line up correctly); you might also apply a class to even-numbered items to force them to always start a new ‘row’:


ol li {
  min-height: 15em;
}
	

ol li.left { clear: left;
}

It’s a sensible approach, but is still not entirely bulletproof—all it takes is for the end user to enter just too much text in one item and row alignment is once more shot to pieces.

Abandon semantics, all ye who enter here

There is only one way to ensure that updates on the same row always align—the styles must be applied to a single element. And that means abandoning our list for something else.


Recent Updates

Lorem ipsum dolor

Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Proin odio. Integer non ante.

Lorem ipsum dolor

Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Proin odio. Integer non ante.

Lorem ipsum dolor

Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Proin odio. Integer non ante.

Lorem ipsum dolor

Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Proin odio. Integer non ante.

Lorem ipsum dolor

Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Proin odio. Integer non ante.

Lorem ipsum dolor

Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Proin odio. Integer non ante.

What we’ve done is replace the li with a simple div to hold each update, and then wrapped every two elements (i.e. each row) in another div with class="row". Now we have the hooks to apply the background colour and border to a single element, ensuring perfect alignment whatever the content.

But, now that it’s only one element, how do we apply that border-bottom across two blocks of content? The answer is that we don’t—instead we’re going to use a background-image which has both the background colour and the border. By aligning the image to the bottom of the div.row and making sure that it is tall enough to cope with any content thrown at it (1000px should do it in this case, but the solid colours mean the graphic still only weighs 2.8KB), we can achieve the effect shown in the original design.


.row {
  width: 624px;
  background: #effcfc url(updates.png) no-repeat 0 100%;
  margin-bottom: 18px;
  padding-bottom: 6px;
  overflow: hidden;
}
	

.row div { background: #effcfc; float: left; width: 300px; margin-right: 12px;
}

(The padding-bottom on the containing div makes space for the red stripe, so that the background-color on the individual blocks of content doesn’t obscure it.)

And that’s it—a reliable and simple way to achieve multiple rows of items when their height and contents is outside your control, and have each row be just as tall as it needs to be.

View the final example

On semantics and pragmatism

There is of course still that niggling doubt. Could I have arrived at the same result with more semantic code choices?

Personally, I think that the solution I have ended up with is semantic enough. The h2 has a series of h3 children, and each sub-heading relates to the content directly following it. The use of a list—aside from adding a “List with 6 items” announcement in screenreaders—confers no additional benefit, and as we have seen has drawbacks when trying to achieve certain visual effects.

Of course, I could be wrong; there could be a perfectly semantic and yet still effective solution—and if you know what it is, I’d love to hear it!

« The Watchmaker Project