float: left is a layout system
Four clearfixes, one collapsing parent, and a layout system nobody actually chose.
Float was designed so you could put an image in an article and have the text go around it. That’s it. That’s the use case, it’s in the spec, it’s what magazines do and it’s what the property is for.
And yet we have built the entire visual web on top of it.
I don’t say that as a gotcha, I say it because I spent a chunk of last week debugging a three-column layout where the third column had dropped to a new line at exactly one browser width, and somewhere around the hour mark I thought: none of us chose this. Every one of us inherited a situation where the only tool that reliably puts two things next to each other is a text-wrapping property from nearly 20 years ago, and we’ve all quietly agreed to pretend that’s normal.
Bad parenting in HTML land
The first thing float does that nobody expects is take the element out of the flow, which means its parent stops accounting for its height. You get a container with three columns in it and a computed height of 0, and the next section slides straight up underneath.
The fix is to make the parent contain the floats again, and there are roughly four ways I’ve done this, in order of how long ago I stopped doing them.
The first is an empty div with clear: both at the end. It works, it’s what I was taught, and it’s a piece of markup that exists purely to serve a stylesheet, which should feel bad and after a while does.
The second is overflow: hidden on the parent, which establishes a new block formatting context and makes it contain its floats. One property! Super tidy. And then six months later you need a dropdown to hang outside that container and it gets guillotined, and you spend a while confused until you find the overflow: hidden you wrote and don’t remember why.
The third is the clearfix, which is the one all the cool kids are using now:
.clearfix:after {
content: "";
display: table;
clear: both;
}
It’s three declarations and a generated pseudo-element whose entire job is to be an invisible thing at the end of the box that clears. It works everywhere back to IE8. There’s a longer version with *zoom: 1 if you’re still on IE7, and I’m choosing to believe you’re not.
The fourth, which I’ve come around to, is to just not have a .clearfix class in the markup at all and @include it in the component that needs it, so the HTML doesn’t have to know about the plumbing.
Column, why won’t you column?
The other classic, and the one that ate my week, is that floats have no idea that they are a row. They’re a sequence of boxes finding somewhere to sit. If a row of three 33.333% columns adds up to 100.001% because of subpixel rounding, the third one doesn’t fit.
So you round down, and now you’ve got a gap on the right. Or you use a grid framework, and the grid framework is doing the same rounding for you and has a bunch of :last-child rules to mop up the margins. Or you go percentages with negative margins on the row, which is what most of them actually do under the hood.
Floats have no idea they are a row. They're a sequence of boxes finding somewhere to sit.
And equal-height columns, famously, are not a thing. You get faux columns with a repeating background image on the parent, which is a technique with a name and tutorials and everything, and which is a background image pretending to be a layout. Or you go display table. Or, and I have done this more than once, you set a min-height and hope the content behaves.
Flexbox though
I know, I know. Flexbox exists, it does all of this properly, it has align-items and it doesn’t need clearing because the parent knows its children are children.
I’ve used it on exactly one thing, a little internal helper thing where I controlled the browser, and it was lovely. Amazing to see align-items: center after doing the position: absolute; top: 50%; transform: translateY(-50%) dance.
But the support story right now is not good enough for my freelance work, and I want to be honest about that rather than optimistic. There are three syntaxes floating around from different draft versions. Old Firefox does one, old iOS Safari does another with -webkit-box, IE10 does -ms-flexbox, and IE9 and below do nothing at all. There are known bugs in IE11 around flex-basis and min-height that I don’t fully understand yet. You can paper over a lot of it with a preprocessor mixin or Autoprefixer, and people do, and I think that’s a reasonable bet on a personal project.
On a site where the client’s own analytics show a fifth of visits on IE9 and below, it isn’t a bet I get to make. So: floats, clearfix, negative margins, and the mild indignity of it.
No conclusion, really
I’m not sure this post has one, and that’s maybe fine. The thing I keep turning over is that I spent the last year thinking clearfix was a normal part of knowing CSS, like it was a technique rather than a scar. It’s in every framework. It’s in the boilerplate. Nobody flags it as strange.
But it is strange! We are all shipping an invisible generated pseudo-element to patch the side effects of a text-wrapping property. That’s a genuinely odd thing to have converged on, and the reason we did is that there was no alternative for as long as we’ve been building websites, so it stopped registering.
I don’t think there’s a lesson here beyond noticing it. My sense is that a decent amount of what I “know” about CSS is going to turn out to be this: not knowledge, just the shape of a constraint I’ve been pressed against for long enough that I mistook it for the way things are.