How to make 2 opposite boxes wrap nicely

This article was first published on CSS-101 (04-01-2013).

This is based on a clever technique that justify-aligns boxes in their container. A fellow named Jason came up with the original trick; I’m only hacking it to achieve a different goal.

The challenge

Imagine this: 2 boxes “floated” in opposite direction:

Nav 1 | Nav 2 | Nav 3 | Nav 4
Option 1 | Option 2

This common construct will make the “options” drop below the nav in case the parent container cannot accommodate the width of both boxes, either because their content grows or because their container shrinks.

Even though relying on float for this type of layout prevents breakage, the “fallback” does not look great. There is no overlap as boxes end up on different rows, but their alignment looks odd, with the “options” still aligned to the right, like this:

Nav 1 | Nav 2 | Nav 3 | Nav 4 | Nav 5 | Nav 6 | Nav 7 | Nav 8 | Nav 9 | Nav 10
Option 1 | Option 2

What we want is to see both boxes aligned to the left side of their container.

The Solution

To solve this problem, we can rely on the trick I mentioned earlier; the one that can spread boxes across their container, like this:

box A
box B
box C
box D

Like most great solutions, this one is pretty simple:

Markup:

<div class="container">
    <div class="box">box A</div>
    <div class="box">box B</div>
    <div class="box">box C</div>
    <div class="box">box D</div>
    <div class="box shim"><!-- I am part of this hack --></div>
</div>

CSS:

.container {
    text-align: justify;
}
.box,
.shim {
    display: inline-block;
    vertical-align: baseline;
    *display: inline;
    zoom: 1;
}
.shim {
    width: 100%;
}

You do need the stretched shim, but if you do not care about IE 6/7, then you can replace it with a pseudo-element - it will work the same.

You may also want to change the vertical-align value depending on what you’re dealing with (i.e. plain text versus boxes).

The result

Spreading 2 boxes apart via this technique instead of using a basic float layout does all the magic:

Nav 1 | Nav 2 | Nav 3 | Nav 4 | Nav 5 | Nav 6 | Nav 7 | Nav 8 | Nav 9 | Nav 10
Option 1 | Option 2

Things you should know about

This approach creates some unwanted “white-space” below the boxes, as shown in the last example and below:

Nav 1 | Nav 2 | Nav 3 | Nav 4 | Nav 5 | Nav 6 | Nav 7 | Nav 8 | Nav 9 | Nav 10
Option 1 | Option 2

Things I’ve tried

You can play with font-size or line-height to reduce the gap, but it’s not pretty. The best solution I found so far is either to use a negative bottom margin on the second box, to compensate with a negative top margin on the next element in flow, or to use that gap as if it were an intended margin below the container.

I haven’t yet found a nice/clean way to kill that gap, which becomes more apparent when the boundaries of the box show (via background, border, or other styling). So if you find the magic bullet, please let me know!