Float: center;

I recently put up a codepen demonstrating something which seems pretty basic. I think it deserves a little write-up.

I was building a site which had a design which had a three-column layout on desktop:

… but a two-column layout on mobile:

… in addition to which, needed to do this, if there were an uneven number of elements:

Some other considerations:

  • The site needed to work in IE8
  • The site needed to work without JavaScript (but didn’t need to look exactly the same)

Frameworks are not the answer

Most CSS frameworks have a row > column structure. This means that moving columns from one row to another (without DOM manipulation) is not possible. To switch between two rows of three columns each to three rows of two columns each requires markup changes.

You could have horrible duplication of content, and switch columns off and on, depending upon the viewport size, but this is hardly an elegant solution.

This looks like floating, but these blocks behave a bit like text

If it was floating, it would be float: center; (which doesn’t exist)

display: inline-block; gets us some of the way. Each element (in my example, they’re label tags) behaves like a word in a sentence, with a declared width and any text inside the label wrapping if it’s too long. However, there’s some issues with this approach:

  • There has to be white-space between the elements, so that the browser knows to wrap them
  • The height of each element needs to be established with JavaScript (I used matchHeight)

Is word-spacing the answer?

My initial approach was to use word-spacing to establish the gutter between the label tags. This worked, but was a bit of a fudge.

For the most part, I wasn’t using responsive rules: I set the max-width of the containing element to 960 pixels, then set each label tag inside it to pixel widths too, with the word-spacing making up the gutter.

Once the screen with was less than 960 pixels, I could assume a slightly more sophisticated browser was parsing the code, so I switched to calc(). This sort of thing:

.choice label {
width: calc(50% - 10px);
}

The codepen uses an all-liquid layout, rather than a desktop fixed-width layout, switching to liquid for responsive. This means the codepen won’t work on browsers who don’t understand calc().

Why are you using calc()? Won’t box-sizing fix that?

Unfortunately, box-sizing: border-box will calculate the width of an element including padding and borders, but not margins. The design I was working with had coloured backgrounds on each label tag, so the gutters had to be created with margins.

Safari woes

This pretty much worked as expected, until I started testing on iOS. No matter what I did, iOS seemed to shift all of the label tags slightly to the right, even if this meant moving them outside their containing element. Even removing whitespace between the container and the first label tag made no difference.

I was stumped.

Forget about word-spacing

Much of the advice online about display: inline-block; includes font-size: 0; declarations. I wanted to avoid that, as it seemed like it might have inherited effects and could harm accessibility. However, it was only once I bit the bullet and applied the font-size, that the layout started to work:

/* .choice is the immediate ancestor for each set of <label/> tags */
.choice {
font-size: 0;
}
    .choice label {
font-size: 22px;
/* These margins will collapse, on adjacent <label/> tags */
margin: 0 10px;
width: calc(50% - 10px);
}

This left me with an extra couple of 10 pixel margins on either side, but they were easily dealt with. So:

  • We still needed whitespace between the labels, so that they’d behave like text on a line
  • Now that the font-size is zero, the gutter between the labels will also be zero, even though they’ll still wrap
  • I’d been using ems for the font-size up until now, but using ems on the label tag (which is now inside an element with a font-size of zero) might behave weirdly, so I switched to pixel sizes instead
  • By using margins on the labels, we could recreate the gutters
  • Unfortunately, these margins will be subject to the weirdness of collapsing margins