← All writing
Craft · · 7 min

Grid shipped today

It landed in two browsers in one week. Here's the one thing floats could never do, and how to ship it without pretending IE11 isn't there.

CSS Cross-Browser Compatibility

Firefox 52 came out last Tuesday with CSS Grid in it. Chrome 57 came out two days later with CSS Grid in it. Safari has it in the preview builds and it’s expected within weeks. Edge has an older version of the spec and will presumably catch up.

So that happened in about 72 hours, after years of it being the thing people demoed at conferences and nobody could use, and I have spent the weekend doing very little else.

I want to write this down now, while I’m still surprised by it, because in 18 months this will be ordinary and I’ll have forgotten what it replaced.

Goodbye, clearfix

Three years ago I wrote a post about float: left being a layout system, which was mostly me being tired. Floats are a text-wrapping feature. We built the entire visual web on them because they were the only property that would put two things next to each other, and everything downstream of that, the clearfix, the collapsing parent, the grid framework with 12 columns and a .col-md-4 on every div, was scaffolding around a tool being used for something it wasn’t for.

Then flexbox arrived and took an enormous amount of pain out of a row. I’ve been happily using it for two years for exactly that. But flexbox is one-dimensional by design, and a page is two-dimensional, and every time I built a page layout out of nested flex containers I was doing the float thing again in a nicer suit.

Grid is the first CSS I’ve used that was designed by people who had actually seen a page.

layout.css
.page {
  display: grid;
  grid-template-columns: 1fr 20rem;
  grid-gap: 2rem;
}
CSS

That’s a main column and a sidebar with a gutter between them. No wrapper, no percentage arithmetic to leave room for the gutter, no :last-child rule to strip a margin off the end, and no clearfix. The fr unit means “a share of what’s left,” so the gutter is subtracted first and the fraction is taken from the remainder, which is the calculation I have done by hand in every layout I’ve ever built and got slightly wrong in about a third of them.

Layout leaves the markup

Everything above is a nicer syntax for something I could already do badly. The genuinely new thing is that the layout is described in the stylesheet rather than in the markup.

With floats, the source order is the layout. If the designer puts the sidebar on the left at desktop and above the content on mobile, you’re either duplicating markup, or you’re pushing and pulling with negative margins, or you’re quietly telling the client it has to go the other way round. The document structure was being bent to serve a visual arrangement, and then a screen reader would read the site in the order that the visual arrangement wanted.

With floats, the source order is the layout. Which means the document was being bent to serve the visual arrangement, and someone reading it linearly paid for that.

Grid separates those. You write the HTML in the order the content actually goes in, and then you place it. And the placement syntax is the daft-looking one that turns out to be the good one:

areas.css
.page {
  display: grid;
  grid-template-columns: 1fr 20rem;
  grid-template-areas:
    "header  header"
    "content aside"
    "footer  footer";
}

.page__header  { grid-area: header; }
.page__aside   { grid-area: aside; }

@media (max-width: 45em) {
  .page {
    grid-template-columns: 1fr;
    grid-template-areas: "header" "aside" "content" "footer";
  }
}
CSS

I showed that to a designer on Friday and they read it correctly without being told what it was, which I don’t think has ever happened with any CSS I’ve written. The mobile arrangement is four words in a different order. That’s the whole responsive change.

The other one worth knowing about on day one is the grid that reflows without any media queries at all:

cards.css
.cards {
  display: grid;
  grid-gap: 1.5rem;
  grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
}
CSS

Fit as many 16rem columns as you can, then share out the remainder. Three declarations, no breakpoints, and it responds to the space the component is in rather than to the width of the window. Which is very close to the thing everyone actually wanted when they asked for element queries, and it isn’t that, but it’s a lot of the way there for the specific case that comes up most.

Not everything is a grid

Flexbox, mostly. I’ll write about that properly because I can already see the framing going wrong, but briefly: grid is for the layout you drew, flexbox is for a row of things whose sizes come from their contents. A nav bar is flexbox. A page is grid. They’re neighbors, not rivals.

It also doesn’t do the thing where a nested grid lines up with its parent’s tracks. That was in the spec and got deferred to a second level, and it’s the one omission I expect to be annoyed by, because “the card’s internals line up with the page grid” is a thing designers ask for constantly and I’ll still be faking it.

And it doesn’t fix your markup on its own. You can absolutely write div soup and place every div individually with line numbers, and it’ll look right and read like nothing. The temptation is real because the placement syntax is so direct.

Shipping it this year

IE11 has an old, prefixed version of a much earlier draft. It has -ms-grid, no auto-placement, no grid-gap, no auto-fit, and it wants every item explicitly positioned. I’ve had a look and I’m not going to maintain two layouts.

So this goes in as an enhancement, and the good news is the feature query does the work for you:

progressive.css
.cards__item { float: left; width: 32%; margin-right: 2%; }

@supports (display: grid) {
  .cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr)); grid-gap: 1.5rem; }
  .cards__item { float: none; width: auto; margin-right: 0; }
}
CSS

The float layout underneath doesn’t have to be good. It has to be fine. That’s the Grade B row of the support matrix I was going on about in January, and this is the first time in a while that the two tiers have been cheap to write.

In the honeymoon

I’ve built one client page with it, on a project that hadn’t started yet, and I took about 200 lines of layout CSS down to about 40. I don’t expect that ratio to hold. I’m in the honeymoon and I know it.

But the reason I wanted to write this in the same week rather than after I’d been sensible about it is that a thing arrived that we’d been asking for since before I started doing this, and it arrived finished, designed properly rather than retrofitted, and that isn’t the usual way this goes. Enjoy it. Next week it’ll just be how layout works and nobody will mention it again 🥲

Read similar posts
6 min

display: flex, finally

Flexbox has crossed the line where I can use it on real work, and the surprise isn't the layouts it enables. It's how much of my CSS turns out to have been compensation for not having it.

6 min

float: left is a layout system

We are building every grid on the web out of a property invented to wrap text around a picture, and the pile of workarounds we've grown on top of it has stopped looking like workarounds.