Drawings and lists
A coworker sent me a card component to look at on Friday and I got a few lines into a review comment before deleting the whole thing.
The card’s footer is a price at one end and a button at the other, and they’d built it as a grid with two named columns. My comment said it should be flexbox. Then it started explaining why, and the explanation was “because flexbox is for one-dimensional layout,” and I sat looking at that sentence for a while, because their footer is one-dimensional. It works, and the CSS is three lines long. So what was I actually asking them to change, and on what authority.
One-dimensional against two-dimensional is the answer everybody gives. I’ve given it twice this week. Grid arrived a month ago, Safari picked it up at the end of March. So it’s in Firefox and Chrome and Safari now with Edge as the holdout, and everyone I work with is suddenly holding a decision they didn’t have to make in February. The trouble with that answer is that the moment you say it to someone who’s actually holding one, they say “flexbox wraps onto more than one line though, so that’s two dimensions.” Which it does. They’re not being difficult, they have a point.
I also deleted the comment because I’d spent Wednesday afternoon doing something dumber, which I’ll get to.
One dimension, twice
Flexbox with flex-wrap does produce more than one row. It produces them by running out of room, one line at a time, and each line is settled on its own by whatever landed on it.
So it’s two dimensions the way a paragraph of prose is two dimensions. Words spill onto the next line when they run out of room, nothing on line two lines up with anything on line one. We don’t call a paragraph a table. You can watch it happen in a wrapping list of cards the moment the final line comes up short, because the leftovers either stretch to fill it or huddle over on the left depending on what you set, and either way they’ve stopped agreeing with the lines above them.
A grid’s second row is a thing you declared. Items in column two line up because column two is there, empty or not, and not because they happened to break at that point.
That’s the difference I actually use now, and it turns out not to be about dimensions at all. It’s about who knows the arrangement before the content arrives. With grid the container knows, because you draw the tracks first, in the stylesheet, and items drop into cells that already exist. With flexbox nobody knows. The items have sizes that come from their own contents, the container hands out whatever is left over, and the arrangement is the thing that falls out of that.
So the question I’ve started asking instead is whether the thing in front of me is a drawing or a list.
Show your work
A drawing is an arrangement that exists before you know what’s going in it. A page with a masthead, an article, a sidebar and a colophon is a drawing, and it’s the same drawing whether the sidebar has two things in it or nine. That one is easy, and everybody gets to it on their own inside a week.
The one that convinced me was much smaller. A client’s account settings form, a stack of rows, each row a label and a control. Built as flex rows, every row works out its own label width, so “Email” and “Marketing preferences” put their inputs in two different places down the page, and the fix for that is to give every label a width you made up. Which holds until somebody translates the site and the width you made up is wrong in German.
.settings {
display: grid;
grid-gap: 0.75rem 1.5rem;
grid-template-columns: max-content 1fr;
}
Every label goes in column one, every control in column two, and column one comes out exactly as wide as the longest label, because that’s what max-content means. Nobody had to know that width, me included. The catch, and it’s a real one, is that the labels and the controls have to be children of the same grid, so the rows can’t be wrapper divs, which means the drawing decides the markup instead of the other way around. I haven’t figured out how I feel about that yet. Last month grid left a wrapper in my markup with nothing to do and I called that the whole point of the feature, and here it is putting a constraint back in from the other direction.
It’s also where the support matrix conversation starts, because IE11 has an ancient prefixed grid in it that can’t place anything by itself. I wrote a whole post in January about getting that written down in week one, while it’s still cheap to agree to. A settings form that falls back to labels sitting above their controls is completely fine. A page skeleton that falls back to a pile is not.
Five, until Wholesale
Wednesday’s dumber thing. A client’s site header, five links, spread along the bar. It had been flexbox since last year and it was fine. I converted it to grid, because I’d spent the weekend reading about grid and everything had started to look like a cell.
/* the version I wrote */
.site-nav {
display: grid;
grid-template-columns: repeat(5, max-content);
justify-content: space-between;
}
/* the version that came back */
.site-nav {
display: flex;
justify-content: space-between;
}
The grid version has one line in it the flex version doesn’t, and the number in that line is the problem. Not because it’s wrong, there really are five links. It’s that I’d written a fact about this month’s navigation into a stylesheet, and the account team has been asking about a Wholesale link since February. The flex version has no number in it because it doesn’t need one, the links being as wide as their own words with the leftover space falling between them, and when Wholesale shows up the nav will be correct without me.
A nav is a list. So is that card footer, and a row of filter pills, and a byline with an avatar and a name and a date in it. Every one of those is however many of these there are, at whatever width their contents come out, arranged along a line, and every one of them can be done in grid, at the cost of writing down a number the content already knew.
Becoming A Grid Person
The versus framing implies you pick one and then that’s who you are, and in practice nearly everything I’ve built this month is both of them, in the same component, two or three layers deep.
The page is a grid. One of its cells holds a card. The card is a grid of image, body and footer, because that arrangement is the same whether the body runs to 12 words or 60. The card’s footer is a flex row, because it’s a price and a button and their widths are their own business. There’s no competition to settle in there, which is sort of the whole point.
Anyway. The instinct I’m trying to catch is the one where you learn something and then go looking for places to have learned it, and Wednesday established fairly clearly that I’ve got it bad. A year and a half ago I was doing the same thing to floats with display: flex, so this is at least a familiar shape of mistake.
Nobody’s fighting but us
My sense is the fight is mostly our fault, and by ours I mean the people who write about this stuff, me very much included. A comparison is easier to write than a description. Two specs, both about putting boxes next to other boxes, both new to most of us inside the same 18 months, so of course one is replacing the other and somebody ought to say which. I have published a post called Gulp because Grunt, and the one I wrote about Yarn is the same post with different nouns in it. So I’m the last person here who gets to complain about it.
The tell that they were never rivals is that align-items and justify-content mean the same thing in both. That isn’t a courtesy, it’s one shared module written by an overlapping group of people, so that what you work out on a flex row carries over to a grid track and you don’t learn alignment twice. Rivals don’t share a spec.
If you want it small enough to keep in your head, could you draw the arrangement before you knew what was going in it? Then grid. Is the arrangement however many things there happen to be, at whatever size they come out? Then flexbox. I’ll get that wrong sometimes and so will you, and both of them will work anyway, which is the part I keep having to remind myself of. My coworker’s two-column card footer renders perfectly and it always will, and deleting the comment was the right thing to do with it.