The Issue

I recently read a post on SitePoint advocating the use of display:inline-block instead of float:left to create columnar layouts. Being industrious, I decided to try it out with a personal project that I needed to do. Everything was going well until I tested the layout of my columns. Here's what I saw.

The layout of the navigation elements works just fine. But the layout of my content section are wrong. My sidebar has shifted below my content column as though it was too wide. After a little layout debugging, I found that there was a "mysterious" 4px margin to the right of my columns, and that extra space was breaking my layout. A quick negative right margin fixed the issue, but I began to wonder where that extra margin was coming from.

My first clue was the global navigation. You'll notice that these links are structured within an unordered list. The LIs' display is set to "inline-block", but the margins are zeroed out. So the 4px shift was also happening here, but the effect was negligible because the unintentional spacing produced a desirable result. But desirable results should not be accidental. Something that works now, may not work in the future if the browser vendors decide to fix the rendering bug that you are taking advantage of. So it is best to figure out what is going on and implement a solution that is deliberate and (hopefully) bulletproof.

Seeing that unintended spacing prompted me to investigate the nature of the inline-block setting. Inline-block causes an element to have block properties but behave like an inline box. This causes the blocks to flow just like inline text would flow. If you insert a carriage return at the end of a line of text to create a nice legible block of text in code, you'll notice that the browser will ignore that CR and instead insert some space that is equal to a space character. This behavior is implemented as specified. The browser is only supposed to create a hard line break if it is instructed to do so by either a BR, P or other tag that causes a line break, or the text is within the PRE tag.

The Solutions

There is no one solution to address this issue. Your situation will dictate which solution best meets your needs.

CSS3 to the Rescue (or maybe not)

CSS3 has the property; white-space-collapsing that allows you to specify how white space, including carriage returns at the end lines, are treated by the browser. So something as simple as white-space-collapsing:collapse applied to a parent element (the UL of the global nav for instance) will cause the browser to collapse the space between the inline block elements. See it in action (or not).

The one caveat to this solution is that there is no support for this property in any of the latest browsers. So until this property is broadly supported, you may want to go with the next solution.

CSS to the Rescue (for real this time, maybe)

You can eliminate the extra space between inline blocks if you set a negative right margin on each inline block element. This solution works, but if the browser vendors decide to change their treatment of CR's in this particular case (unlikely, but possible), your layouts will be broken again. The other issue is how much negative margin do you need? In my examples, 4px was enough to overcome the extra space. But I wouldn't bet on that being some kind of universal number that will fix all inline-block layouts. Those with more time on their hands than I have can do that research. See it in action.

The Old School Solution

The bad old days of presentational markup, littered with nightmarish tables-based layouts, were awash with examples of layouts that were broken by the trailing white space. The solution turned out to be very simple. Eliminating the trailing white space after each opening TD tag forced the browser to collapse the space.

So instead of:

        <td>
            <div>Boo</div>
        </td>
    

We did this:

        <td><div>Boo</div>
        </td>
    

Or this:

        <td><div>
            Boo</div>
        </td>
    

Applied to our fourth example gives us something like this for the global nav:

<ul>
    <li><a href="#">Home</a></li><li>
        <a href="#">Articles</a></li><li>
        <a href="#">Ideas</a></li>
</ul>

and this line for the content columns:

</section><aside id="mainAside" class="col colNw">

Not the best option if you like your code to be clean and legible, but it works very well and eliminates any variables related to how the browsers may deal with trailing white space in the future.

Final Thoughts

In an ideal world the CSS3 solution would be the only solution. But in the real world you have to make do with what works. The negative margin solution works if you can't alter your markup. Deleting the white space works if you have the time and resources to refactor your markup and can live with code that is a little less legible.

Finally, I will pre-empt comments that point out how a reader on the post addressed the very same problem solved here. I didn't read the comments until I revisited the post after I figured out what was going on, and before writing this article. Besides, the detective in me got to have some fun solving a puzzle.

Follow any responses to this entry through the RSS 2.0 feed.

You can leave a comment, or trackback from your own site.

Leave a Reply

Copyright © 1996–2012

SerpentVenom is proudly powered by WordPress
Entries (RSS) and Comments (RSS).