CSS Grid and Flexbox

Written by Hamilton Cline
Last updated on April 19, 2019, 9:15 am

Layout Structures

It's possible that if you started making websites in the early 2000s, you made a website layout with a table. You should probably not do that anymore. It's possible that if you made a website anytime before 2015, you made it with a float layout structure. You should probably stop doing that, as well. Tables are for tabular data representation, and floats are for text wrapping, and we now have better tools for layout in HTML and CSS.

Check out CSS-TRICKS for more complete guides on Grid and Flex-Box.

Flexbox or Grid?

So which one of these tools should you use? It's important to know the difference. Grid is like the great big daddy that can technically do anything, but it's way overly complicated for some things, or at the least, it's very complicated to learn the simple things it can do. On the other hand, flex-box can solve tons of simple problems all on its own, but once a layout gets too exacting it won't quite be enough.

Flex is good for this pattern. Rows of potentially uneven data.

Item
Much Bigger Thing
Item
Much Bigger Thing
Item
Much Bigger Thing
Item
Much Bigger Thing
Much Bigger Thing

Flex is also fine for patterns like this. Rows of probably even data.

Item
Item
Item
Item
Item
Item
Item
Item

Grid can also handle even row patterns.

Item
Item
Item
Item
Item
Item
Item
Item

Grid really shines with flat, big, predefined layouts.

Header
Side
Body
Body
Body

Atomic CSS Classes

This tutorial is going to heavily favor atomic classes. What are atomic classes? They are single purpose classes, most often named for exactly what they do. Most often only changing one value, these classes can build up on an element if left unchecked. Often times, however, elements only need one or two small value changes, and having single classes for common changes can mean a lot of options. Of course, it can also means building up a library of things that need to be memorized.

Flexbox

Creating simple to use classes can simplify the bootstrapping process.

flex-parent

Making a flex parent will turn a group of block elements into a group of close inline-like elements.

.flex-parent { display:flex; }

div

Item
Item
Item

div.flex-parent

Item
Item
Item
<div class="flex-parent"> <div>Item</div> <div>Item</div> <div>Item</div> </div>

flex-child

Creating a flex child class will go on the immediate children of a flex-parent. They will now fill as much space as possible, or shrink to give room for others. Use the shorthand syntax which stands for flex-grow, flex-shrink, and flex-basis all in one.

.flex-child { flex: 1 1 auto; }
.flex-child
.flex-child
.flex-child
<div class="flex-parent"> <div class="flex-child">Item</div> <div class="flex-child">Item</div> <div class="flex-child">Item</div> </div>

flex-none

Adding in a flex none will give you the ability to mix and match children that stretch or not. The flex-child elements will grow and shrink at a similar pace, while the flex-none elements will remain whatever size they were set to.

.flex-none { flex: none; }
.flex-none
.flex-child
.flex-child
<div class="flex-parent"> <div class="flex-none">.flex-none</div> <div class="flex-child">.flex-child</div> <div class="flex-child">.flex-child</div> </div>
.flex-none
.flex-child
.flex-none
<div class="flex-parent"> <div class="flex-none">.flex-none</div> <div class="flex-child">.flex-child</div> <div class="flex-none">.flex-none</div> </div>
.flex-child
.flex-none
<div class="flex-parent"> <div class="flex-child">.flex-child</div> <div class="flex-none">.flex-none</div> </div>

flex-align-center

By default, the items are aligned along the horizontal axis to the top. It can often be useful to align all the children to the center. Most often this makes the most sense when all aligned items share a common background color.

.flex-align-center { align-items: center; }
.flex-child
.flex-child
.flex-child
<div class="flex-parent flex-align-center"> <div class="flex-child">.flex-child<br>.flex-child</div> <div class="flex-child">.flex-child</div> </div>
Header
Link
Link
Link
<div class="flex-parent flex-align-center"> <div class="flex-child"><div style="font-size:2.5em;line-height:1em; padding:1rem 0">Header</div></div> <div class="flex-none flex-parent"> <div class="flex-child" style="padding:0 0.5em;">Link</div> <div class="flex-child" style="padding:0 0.5em;">Link</div> <div class="flex-child" style="padding:0 0.5em;">Link</div> </div> </div>

flex-justify-center

You can also pull elements to the center of the horizontal plane as well.

.flex-justify-center { justify-content: center; }
.flex-none
.flex-none
.flex-none
<div class="flex-parent flex-justify-center"> <div class="flex-none">.flex-none</div> <div class="flex-none">.flex-none</div> <div class="flex-none">.flex-none</div> </div>

flex-wrap

By default, a flex row will not wrap it's content. it will just stretch out into the ether. Adding a flex wrap class is a great way of making content that will stay within borders.

.flex-wrap { flex-wrap:wrap; }
item
item
item
item
item
item
item
item
item
item
item
item
item
<div class="flex-parent flex-wrap"> <div class="flex-none">item</div> <div class="flex-none">item</div> <div class="flex-none">item</div> <!-- etc ... --> </div>

flex-vertical

When you start with flex, you'll probably focus on its ability to make normally vertical content be horizontal. But it's use for vertical content can also be important, especially for app development.

.flex-vertical { flex-direction:column; }
.flex-none
.flex-child
.flex-none
<div class="flex-parent flex-vertical" style="height:10em"> <div class="flex-none">.flex-none</div> <div class="flex-child">.flex-child</div> <div class="flex-none">.flex-none</div> </div>

Grid

Grid is a lot harder to make simple bootstrappy classes for, because each grid is more or less unique. Grid can be very complex, especially when you are first introduced to it, but once it's broken down, it does have some easy to follow uses. You can create some simple row classes, and even make a default holy grail layout for yourself.

grid-parent

Setting yourself up with a grid-parent makes it real simple to define an element as a grid, but doesn't particularly imbue the element with anything by itself.

.grid-parent { display:grid }
Item
Item
Item
<div class="grid-parent"> <div>Item</div> <div>Item</div> <div>Item</div> </div>

Grid-wrap

Grid can be used to make simple repeating rows. Make as many simple repeating designs and all the children of the grid parent will flow into lines.

.grid-wrap-2 { grid-template-columns: repeat(2, 1fr); } .grid-wrap-3 { grid-template-columns: repeat(3, 1fr); } .grid-wrap-4 { grid-template-columns: repeat(4, 1fr); } .grid-wrap-5 { grid-template-columns: repeat(5, 1fr); } /* etc ... */ .grid-wrap-12 { grid-template-columns: repeat(12, 1fr); }

.grid-wrap-2

Item
Item
Item
Item
Item
Item
Item
Item
Item
<div class="grid-parent grid-wrap-2"> <div>Item</div> <div>Item</div> <div>Item<br>Item</div> <div>Item</div> <!-- etc... --> </div>

.grid-wrap-3

Item
Item
Item
Item
Item
Item
Item
Item
Item
Item
<div class="grid-parent grid-wrap-3"> <div>Item</div> <div>Item</div> <div>Item<br>Item</div> <div>Item</div> <!-- etc... --> </div>

.grid-wrap-4

Item
Item
Item
Item
Item
Item
Item
Item
Item
<div class="grid-parent grid-wrap-4"> <div>Item</div> <div>Item</div> <div>Item<br>Item</div> <div>Item</div> <!-- etc... --> </div>

.grid-wrap-5

Item
Item
Item
Item
Item
Item
Item
Item
Item
Item
Item
<div class="grid-parent grid-wrap-5"> <div>Item</div> <div>Item</div> <div>Item<br>Item</div> <div>Item</div> <!-- etc... --> </div>

Grid Span

If we just give ourselves a few extra classes with some grid span values, we can do some really interesting things.

.grid-col-1 { grid-column: span 1; } .grid-col-2 { grid-column: span 2; } .grid-col-3 { grid-column: span 3; } .grid-col-4 { grid-column: span 4; } .grid-col-5 { grid-column: span 5; } /* etc ... */ .grid-row-1 { grid-row: span 1; } .grid-row-2 { grid-row: span 2; } .grid-row-3 { grid-row: span 3; } .grid-row-4 { grid-row: span 4; } .grid-row-5 { grid-row: span 5; } /* etc ... */
Item
Item
Item
Item
Item
Item
Item
Item
Item
<div class="grid-parent grid-wrap-5"> <div>Item</div> <div class="grid-col-3">Item</div> <div class="grid-row-2">Item<br>Item</div> <div class="grid-row-2 grid-col-2">Item</div> <div class="grid-col-2">Item</div> <div>Item</div> <div class="grid-col-2">Item</div> <div class="grid-col-5">Item</div> </div>

Grid Gap

Rounding out the basics, we can add a couple grid gap classes to give us some flexibility in designing our grids with gutters in between elements.

[class*='grid-gap'] { --gap-size:5px; } .grid-gap-sm { grid-gap:var(--gap-size); } .grid-gap-md { grid-gap:calc(2 * var(--gap-size)); } .grid-gap-lg { grid-gap:calc(4 * var(--gap-size)); }
Item
Item
Item
Item
Item
Item
Item
<div class="grid-parent grid-wrap-4 grid-gap-md"> <div>Item</div> <div>Item</div> <div class="grid-row-2 grid-col-2">Item</div> <div class="grid-col-2">Item</div> <div>Item</div> <div class="grid-col-2">Item</div> <div>Item</div> </div>

grid-holygrail

The holy grail layout was a concept that web designers struggled with for a decade. Grid is THE definitive solution to this design pattern. You can even define a relatively simple structure for it, and standardize a little bit of naming for any variations you might want to make.

.grid-holygrail { grid-template-areas: "header header header" "side-left body side-right" "footer footer footer"; grid-template-rows: 3em 1fr 3em; grid-template-columns: 100px 1fr 100px; } .grid-header { grid-area: header; } .grid-side-left { grid-area: side-left; } .grid-side-right { grid-area: side-right; } .grid-body { grid-area: body; } .grid-footer { grid-area: footer; }
Header
Side
Side
Side
Side
Side
Side
Body
<div class="grid-parent grid-holygrail"> <div class="grid-header">Header</div> <div class="grid-side-left">Side<br>Side<br>Side</div> <div class="grid-side-right">Side<br>Side<br>Side</div> <div class="grid-body">Body</div> <div class="grid-footer">Footer</div> </div>

You could of course, then make whatever variations on the theme that you want.

.grid-one-column-left { grid-template-areas: "header header header" "side-left body body" "footer footer footer"; } .grid-one-column-right { grid-template-areas: "header header header" "body body side-right" "footer footer footer"; }
Header
Side
Side
Side
Body
<div class="grid-parent grid-holygrail grid-one-column-right"> <div class="grid-header">Header</div> <div class="grid-side-right">Side<br>Side<br>Side</div> <div class="grid-body">Body</div> <div class="grid-footer">Footer</div> </div>
Header
Side
Side
Side
Body
<div class="grid-parent grid-holygrail grid-one-column-left"> <div class="grid-header">Header</div> <div class="grid-side-left">Side<br>Side<br>Side</div> <div class="grid-body">Body</div> <div class="grid-footer">Footer</div> </div>
Written by Hamilton Cline
Last updated on April 19, 2019, 9:15 am