I’ve been playing around with various CSS frameworks for the past eight years. All these frameworks like Foundation, Bootstrap and Blueprint have really only served one purpose for me: to disguise the fact that until now, layout in CSS has been a hack.
Floats were the best tool we had available at the time, but they were never really meant for full-page layout, they were meant for floating an image next to a block of text. Because of this, faking a grid with floats requires careful calculations of widths, setting margins and results in pages that can easily break when the content changes or isn’t what the designer or developer intended. The frameworks a lot of us relied on hid most of this complexity.
What about Flexbox?
A few years ago it seemed like Flexbox was going to change all this, and in some ways it did. We could now put elements side by side and make them equal-height without resorting to hard-coded heights or JavaScript. That was nice. We could also easily centre items both horizontally and vertically without any trickery. Items could also wrap onto multiple rows.
However, using Flexbox to build a two-dimensional grid is also a hack. So all those frameworks just transitioned to using Flexbox. It was better than using floats, but still a hack.
Diving into CSS Grid
So how is CSS Grid different? CSS Grid has just appeared during the past year in modern browsers and has been implemented at an astonishing speed (compared to many previous CSS features). I’m not going to try to explain everything CSS Grid can do here, but I’ll cover the basics, show some examples and then discuss what that means for the future.
A 12-column Grid using Grid
We’ve got a traditional 12-column grid and three items we want to place onto it, 4 columns each. Using flexbox (example adapted from Foundation) it would look something like the following example:
HTML:
<div class="grid">
<div class="cell small-4">
Cell 1
</div>
<div class="cell small-4">
Cell 2
</div>
<div class="cell small-4">
Cell 3
</div>
</div>
CSS:
.grid-x {
display: flex;
flex-flow: row wrap;
}
.cell {
padding: 1rem;
background: yellow;
flex: 0 0 auto;
min-height: 0px;
min-width: 0px;
width: 100%;
}
.grid-margin-x > .small-4 {
width: calc(33.33333% - 1rem);
}
In CSS Grid, it would look like this:
.grid {
display: grid;
grid-template-columns: repeat(12, 1fr);
grid-gap: 1rem;
}
.cell {
padding: 1rem;
background: yellow;
}
.small-4 {
grid-column: span 4;
}
Similar to flexbox, I set the parent element to display: grid
. The big difference are the new CSS properties grid-template-columns
, grid-gap
on the parent which actually define what the grid should be, and grid-column
on the child element (.small-4
in this case because I wanted to keep the same markup from the previous example).
The value of grid-template-columns
is repeat(12, 1fr)
which the browser interprets as “divide the available space equally between 12 columns”.
The big difference here compared to our previous example is that instead of having to calculate and set the width of the small-4
element, I’m just saying “I want this to span 4 columns”.
A closer look at grid-template-columns
and grid-template-rows
These two properties allow you to define arbitrary tracks (a common term for columns and rows). Here for example we’re defining one 200px column and another 800px column.
grid-template-columns: 200px 800px;
These are obviously fixed-width. In this next example, the second column has been changed to be flexible using the new fr
unit.
grid-template-columns: 200px 1fr;
fr
stands for “fraction of the available space”, so this second column will now expand to take up as much space as it can within its parent container, after space for fixed-width columns has been reserved.
The cool thing about the fr
unit is we can easily add a second column like this:
grid-template-columns: 200px 1fr 1fr;
Notice how now both the 2nd and 3rd columns are 1fr
. First the browser will add up those units (1 1), divide up the available space by the total (2) and then allocate the space to the individual columns. So if I were to change the second column to 2fr
, its width would be twice the size of the third column.
So back to our 12-column example, we could define that grid like this: 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr
but luckily CSS Grid supports a handy repeat notation which allows us to just write repeat(12, 1fr)
. The repeat notation can also be used to repeat a pattern, such as repeat(12, 1fr 50px)
which would make every other column 50 px and the rest would be split up evenly based on the available space.
Rows work exactly the same:
grid-template-rows: 200px min-content;
In the above code, min-content
is a way of saying “I want this track to be whatever the minimum size is that my content needs”. There are loads of keywords like this, you should read up on all the ways to size tracks here.
Gutters using grid-gap
We no longer need to bother with paddings or margins to create fake gutters, because the grid spec has a new property just for that, grid-gap
. In the latest spec version this has been shortened to just gap
, hopefully meaning that we might get the same feature in Flexbox later on. You should probably still use the older syntax for now because browsers don’t support gap
yet.
Two-dimensional layouts
What we’ve done so far isn’t anything we couldn’t have done with flexbox or floats. The code is more robust for sure, but it’s still not anything radically new. But what if you want one of the items to span two rows?