Thursday, Dec 8, 2016
Building a simple CSS grid with flexbox
Building a new CSS grid might seem futile since there’s a lot of CSS grids out there, but sometimes you just need a straightforward and quick solution, so let’s learn how to build your own.
Rather then using “we cover all possible scenarios” solutions that bring a whole new set of rules and specifics to your workflow, you can easily build your own grid, especially if you don’t have a need for high complexity. In that case, you can create simple CSS grid with flexbox in just a few easy steps.
The major advantage of using flexbox over classic floated grid is that you have more options for display, but the best feature, in my opinion, is that the equal column height problem is solved by default. Since browser support is fair (there are a few issues with older versions of IE), we’re good to go.
Grid setup
To start building a grid, we need to determine the number of columns and gutters. Let’s take, for example, 12 column grid with 24px gutter. We will use paddings on columns to setup gutters, and negative margins on a row to resolve first and last item gutter problems.
Every column should have left and right padding half of the gutter value, so in our case 24px/2=12px.
.col {
padding-left: 12px;
padding-right: 12px;
}
In the same way, we can set negative margins on a row to neutralize left padding on the first column and right padding on the last.
.row {
margin-left: -12px;
margin-right: -12px;
}
Now we need to add flexbox rules to the row, which will define it as a flexbox container.
.row {
display: flex;
justify-content: flex-start;
flex-wrap: wrap;
margin-left: -12px;
margin-right: -12px;
}
Next, we need to setup classes for all 12 columns and set appropriate widths for different breakpoints.
Calculation of the column width can be done with this simple formula:
column/number of columns * 100%
Let’s see it in action:
/* Small grid */
.col-sml-1 {
width: calc(1/12 * 100%); // 8.333333333333333%
}
.col-sml-2 {
width: calc(2/12 * 100%); // 16.66666666666667%
}
.col-sml-3 {
width: calc(3/12 * 100%); // 25%
}
...
.col-sml-12 {
width: calc(12/12 * 100%); // 100%
}
/* Medium grid */
@media (min-width: 480px) {
.col-med-1 {
width: calc(1/12 * 100%); // 8.333333333333333%
}
.col-med-2 {
width: calc(2/12 * 100%); // 16.66666666666667%
}
.col-med-3 {
width: calc(3/12 * 100%); // 25%
}
...
.col-med-12 {
width: calc(12/12 * 100%); // 100%
}
}
/* Large grid */
@media (min-width: 768px) {
.col-lrg-1 {
width: calc(1/12 * 100%); // 8.333333333333333%
}
.col-lrg-2 {
width: calc(2/12 * 100%); // 16.66666666666667%
}
.col-lrg-3 {
width: calc(3/12 * 100%); // 25%
}
...
.col-lrg-12 {
width: calc(12/12 * 100%); // 100%
}
}
As you can see, we used -sml
, -med
, -lrg
, etc. modifiers for particular screen sizes, and -1
, -2
, -3
, etc. modifiers for the number of columns.
Column offset
We can setup offsets in a similar way we did grid widths. We will use margin-left
instead of the width
property, and the rest is the same. Here’s the setup:
/* Small grid offsets */
.col-offset-sml-1 {
margin-left: calc(1/12 * 100%); // 8.333333333333333%
}
.col-offset-sml-2 {
margin-left: calc(2/12 * 100%); // 16.66666666666667%
}
.col-offset-sml-3 {
margin-left: calc(3/12 * 100%); // 25%
}
...
.col-offset-sml-12 {
margin-left: calc(12/12 * 100%); // 100%
}
/* Medium grid offsets */
@media (min-width: 480px) {
.col-offset-med-1 {
margin-left: calc(1/12 * 100%); // 8.333333333333333%
}
.col-offset-med-2 {
margin-left: calc(2/12 * 100%); // 16.66666666666667%
}
.col-offset-med-3 {
margin-left: calc(3/12 * 100%); // 25%
}
...
.col-offset-med-12 {
margin-left: calc(12/12 * 100%); // 100%
}
}
/* Large grid offsets */
@media (min-width: 768px) {
.col-offset-lrg-1 {
margin-left: calc(1/12 * 100%); // 8.333333333333333%
}
.col-offset-lrg-2 {
margin-left: calc(2/12 * 100%); // 16.66666666666667%
}
.col-offset-lrg-3 {
margin-left: calc(3/12 * 100%); // 25%
}
...
.col-offset-lrg-12 {
margin-left: calc(12/12 * 100%); // 100%
}
}
Column source ordering
To handle source ordering, we need to include order
flexbox property. Since you have a different number of grid items all over the project, it’s hard to set predefined CSS classes to cover all cases. So, for this feature, we will have to add classes to match the count of your items in a particular grid. Here’s an example for a small grid with three items (columns).
Note: If you use this feature, you need to set order
property to all items in the grid.
/* Small grid offsets */
.col-order-sml-1 {
order: 1;
}
.col-order-sml-2 {
order: 2;
}
.col-order-sml-3 {
order: 3;
}
@media (min-width: 480px) {
.col-order-med-1 {
order: 1;
}
.col-order-med-2 {
order: 2;
}
.col-order-med-3 {
order: 3;
}
}
@media (min-width: 768px) {
.col-order-lrg-1 {
order: 1;
}
.col-order-lrg-2 {
order: 2;
}
.col-order-lrg-3 {
order: 3;
}
}
Using a grid in HTML
After you finish setting up your grid, you can use it in HTML.
Simple usage:
<div class="row">
<div class="col col-sml-12 col-med-6 col-lrg-4"></div>
</div>
Nested grid:
<div class="row">
<div class="col col-sml-12 col-med-6 col-lrg-4">
<div class="row">
<div class="col col-sml-12 col-med-6 col-lrg-4"></div>
</div>
</div>
</div>
Using offset:
<div class="row">
<div class="col col-sml-12 col-med-6 col-offset-sml-12 col-offset-med-6"></div>
</div>
Using source ordering:
<div class="row">
<div class="col col-sml-12 col-med-4 col-order-sml-1 col-order-med-3"></div>
<div class="col col-sml-12 col-med-4 col-order-sml-2 col-order-med-2"></div>
<div class="col col-sml-12 col-med-4 col-order-sml-3 col-order-med-1"></div>
</div>
And that’s it.
We have been using this grid in Mono for some time now, and we find it very practical and easy to use. The credit for this simple tool goes to Mono’s (the past and the current) design/frontend team, and we will surely show more tools like this in the future.