Web Standards: Semantic or Pragmatic?
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

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:
<h2>Recent Updates</h2>
<ol>
<li>
<img src="placeholder.png" alt="" />
<h3>Lorem ipsum dolor</h3>
<p>Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Proin odio. Integer non ante.</p>
</li>
<li>
<img src="placeholder.png" alt="" />
<h3>Lorem ipsum dolor</h3>
<p>Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Proin odio. Integer non ante.</p>
</li>
<li>
<img src="placeholder.png" alt="" />
<h3>Lorem ipsum dolor</h3>
<p>Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Proin odio. Integer non ante.</p>
</li>
<li>
<img src="placeholder.png" alt="" />
<h3>Lorem ipsum dolor</h3>
<p>Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Proin odio. Integer non ante.</p>
</li>
<li>
<img src="placeholder.png" alt="" />
<h3>Lorem ipsum dolor</h3>
<p>Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Proin odio. Integer non ante.</p>
</li>
<li>
<img src="placeholder.png" alt="" />
<h3>Lorem ipsum dolor</h3>
<p>Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Proin odio. Integer non ante.</p>
</li>
</ol>
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.
<h2>Recent Updates</h2>
<div class="row">
<div>
<img src="placeholder.png" alt="" />
<h3>Lorem ipsum dolor</h3>
<p>Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Proin odio. Integer non ante.</p>
</div>
<div>
<img src="placeholder.png" alt="" />
<h3>Lorem ipsum dolor</h3>
<p>Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Proin odio. Integer non ante.</p>
</div>
</div>
<div class="row">
<div>
<img src="placeholder.png" alt="" />
<h3>Lorem ipsum dolor</h3>
<p>Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Proin odio. Integer non ante.</p>
</div>
<div>
<img src="placeholder.png" alt="" />
<h3>Lorem ipsum dolor</h3>
<p>Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Proin odio. Integer non ante.</p>
</div>
</div>
<div class="row">
<div>
<img src="placeholder.png" alt="" />
<h3>Lorem ipsum dolor</h3>
<p>Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Proin odio. Integer non ante.</p>
</div>
<div>
<img src="placeholder.png" alt="" />
<h3>Lorem ipsum dolor</h3>
<p>Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Proin odio. Integer non ante.</p>
</div>
</div>
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.
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!
Technorati tags: html xhtml css layout floats web standards
Bookmark this article with del.icio.us
Previously: Our Facebook application - friend finder for hotels
Next: @import considered harmful
Comments
- Sophie Dennis
- 32 days ago
Good example!
Using em-based heights is about the only way I’ve found to get this kind of layout to work and be ‘bulletproof’ against random content. Typically I’ve used a fixed (rather than minimum) height, with overflow:hidden, to tackle both too-short and too-long content. This, of course, if only acceptable if you’re happy for overly long content to get truncated.
Otherwise I agree you’re left with whatever variation on not-entirely-semantic ickyness you find least offensive. I’d consider both adding class=’left’ (as in example 2) or the ‘row’ divs from example 3 to be essentially unsemantic, on the grounds you’re using either a class name or element entirely to achieve the visual two column layout. I’d consider them more unsemantic than the usual extra wrapper div/elements you’d need to throw in as ‘hooks’, as they aren’t entirely neutral in effect. Change the visual layout to, say, three columns later and you will have to alter your HTML to support that, even though the meaning/structure of the content hasn’t changed.
Nonetheless, current CSS implementations leave little choice to dirty up your code like this, and I think your solution is a perfectly decent compromise.
- #1
- Nathan Smith
- 32 days ago
I ran into a similar problem awhile back. I ended up using jQuery to insert a clearing after ever Nth chunk. While this makes the design dependent on JS, it did the trick, and allowed the markup to stay a bit cleaner / more semantic. Really though, it’s about pragmatism. Whatever gets the job done, without obscuring accessibility, is fine by me.
- #2
- Matthew Pennell
- 32 days ago
Nathan: That would work too, and I did consider it, but—particularly when handing work off to clients—I favour the most straightforward solution.
- #3
- Karl
- 31 days ago
Whilst not known by the end user or by other developers doing a “view source”, what you’ve done here is due diligence – you’ve gone for the most semantic approach (even though it could be argued that the humble list is stretched beyond what may have been anticipated for it originally), found it wanting in the real-world and put in a maintainable solution instead.
+1 for pragmatism in this example.
- #4
- Phil Thompson
- 31 days ago
For previous projects, I’ve written JavaScript that works out which element is the tallest (in a group) and makes all other elements in that group the same height by changing the min-height setting (or height setting for IE6)
In a sitatuon like yours, I’d be looking for my HTML to look like this:
[content]
[content]
[content]
[content]You can then add your JavaScript to work out the heights of items in each row and make them equal height. A JavaScript solution isn’t quite bulletproof though but I think it’s better than truncating long content.
- #5
- Phil Thompson
- 31 days ago
Damn, my beautiful HTML example has gone west!
I was simply trying to show an unordered list with the list items having multiple class names that stated what row they were in, whether they were an odd or even item in the list and whenever they were first or last in the list.
Roll on CSS3 when this won’t be necessary
- #6
- James Oppenheim
- 28 days ago
Nice example.
I have been using this technique to achieve the same thing: http://www.brunildo.org/test/ImgThumbIBL.html
I have found it to work really well using display: inline-block and moz-inline-box to work around Mozillia’s problems with inline-block.
- #7
- Pragmatic
- 25 days ago
I may not bee the coolest kid in the Web 2.0 world, but if you are using divs in that way, what do you benefit from not using tables for that particular layout.
Tables may be a sematically bad choice for a layout, but a div is even less semantic. A div doesn’t mean anything.
- #8
- Matthew Pennell
- 25 days ago
@Pragmatic: It’s not true that a DIV doesn’t mean anything – it’s a DIVision of content. A table means tabular data, which this isn’t, so it would definitely be the wrong choice.
- #9
- Shinya
- 23 days ago
I wonder why we need to use the huge background image. Better off with background color with border-bottom?
If i am missing let me know- #10
- Matthew Pennell
- 23 days ago
Shinya – if you just use a background colour and a border, the red borders will not align correctly if there are differing amounts of text in adjoining boxes.
- #11
Comment form