CSS Grid vs. Flexbox: A Practical Guide
With CSS Grid and Flexbox, CSS finally provides two powerful layout systems that massively improve the way you define your layouts. After decades of hacking together complex layouts for web pages using tables, absolute positioning, floats, and other mediocre layout systems, Flexbox and Grid significantly clean up your layout code and make it easier to understand. Ultimately, it allows you to focus on building a great user experience instead of making the basic layout work.
However, why are there two layout systems, and what’s their purpose? When should you use Flexbox vs. Grid? Let’s briefly recap both layout systems and then discuss their use cases and when to use them.
Last Updated September 2021
This tutorial teaches you how to use the new CSS3 Flexbox box model to create responsive web layouts more effectively! | By Peter Sommerhoff
Explore CourseFlexbox quick guide
The Flexbox specification has evolved since 2009 and is currently a Candidate Recommendation by the W3C (World Wide Web Consortium). All modern browsers already support it according to caniuse.com:
So, unless you have requirements to support specific older browser versions, Flexbox is definitely ready to be used in production.
Flexbox allows you to easily create linear layouts where the content is in focus. To explain what this means, it’s useful to differentiate between the flex container that applies the flexible layout system and the flex items contained within it. In other words, a parent flex container contains a number of child flex items:
Once you have this, Flexbox gives you a powerful set of properties to control the layout inside this flex container.
For this and the following examples, assume we have this super simple HTML markup:
<div class="flex">
<div>Item #1</div>
<div>Item #2</div>
<div>Item #3</div>
<div>Item #4</div>
</div>
To activate Flexbox on the container, you simply add:
.flex {
display: flex;
}
That’s it. With this, you’re ready to apply all the powerful features of the flex layout system.
Changing the main axis direction
Let’s look at a few practical examples of how easily you can achieve different layouts with Flexbox.
For instance, you can change the layout’s main axis using flex-direction:
flex-direction: row (default)
This is the default value and, therefore, the same layout as above. It’s similar to a container with float: left but, of course, much more versatile with Flexbox.
flex-direction: column
In the column layout, it aligns elements from top to bottom in a row. Each flex item will automatically take up the whole width.
Aligning Items
Apart from the basic layout direction, Flexbox allows you to finely control the alignment of all flex items inside a flex container. Among others, there’s the justify-content property that lets you control the spacing of elements along the main axis:
justify-content: flex-start (default)
By default, all flex items align toward the beginning of the main axis, so in this case, to the left. If you had set flex-direction: row-reverse, the beginning of the main axis would be on the right instead.
justify-content: flex-end
Here, all flex items align toward the end of the main axis. For flex-direction: row-reverse, this would be the left, and for flex-direction: column, it would be the bottom. It’s important to understand these interactions between the flex properties. Fortunately, they’re very logical and intuitive.
justify-content: center
As you’d expect, by setting this property to center, all items align to the center of the main axis.
justify-content: space-around
With space-around, you can evenly distribute available space along the main axis between all flex items. It also includes whitespace at the start and end.
justify-content: space-between
Almost like space-around, but does not include space at the start and end of the main axis.
Wrapping items
The last example I want to cover is wrapping items because this will lead us to CSS Grids.
In short, you can tell your flex container to wrap its elements to break flex items into additional rows (or columns) if they would otherwise overflow. This is not the default behavior though:
flex-wrap: nowrap (default)
Here, the white border signifies the parent flex container div.flex. As you can see, the default behavior is to let the flex items overflow their container. In these cases, you’ll likely want to either reduce the number of items or use flex wrap:
flex-wrap: wrap
Using this one line of code, the container wraps items that would overflow into additional rows (or columns).
As you can see, this looks like a nice grid. However, Flexbox doesn’t give you fine-grained control over the layout of the grid. It really represents a linear, one-dimensional design. All it’s doing is breaking overflowing elements into additional lines.
Another way to think of it is this: if more space were available, the flex container would return to its desired single-line layout. This is its fundamental difference from CSS Grid.
This was just a selection of a few essential features of Flexbox. All examples shown here use properties that work on the flex container, but many control the flex items as well.
For a step-by-step guide through all Flexbox terminology, features, and use cases, please check out my complete course:
To get a taste of the course and Flexbox, watch this course preview video series:
CSS Grid quick guide
The CSS Grid layout system is a more recent Candidate Recommendation of the W3C but already has great browser support with about 95% by now as well:
You can think of CSS Grid as the big sister of CSS Flexbox. As the first proper grid-based layout mechanism for CSS, it allows you to easily and cleanly implement even complex page layouts.
The term grid already hints at the fact that it enables two-dimensional layouts. In other words, you can finely control both the rows and columns of your layout (whereas Flexbox works great to style a single row or column):
Before we dive deeper into the differentiation between Grid and Flexbox, their different use cases, and how you can combine them in practice, let’s first look at the essential features of the grid layout system.
For this and the following examples, assume again we have this simple HTML markup:
<div class="grid">
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</div>
Now let’s take a look at some common grid layouts.
Defining rows and columns
To create a simple grid layout such as in the example above, you need to define the desired dimensions of its rows and columns:
.grid {
display: grid;
grid-template-rows: 50px 80px;
grid-template-columns: 50px 100px 50px;
grid-gap: 5px;
}
This will set up a grid with two rows, sized at 50px and 80px; and three columns 50px, 100px, and 50px in size:
The grid-gap clearly shows each grid cell. As the name implies, it simply adds a gap of 5px between each grid row and column.
You can also abbreviate the grid-template-rows and grid-template-columns to one property:
.grid {
display: grid;
grid-template: 50px 80px / 50px 100px 50px;
grid-gap: 5px;
}
Here, we define the rows first, followed by a slash, followed by the column definitions.
Positioning items on the grid
Oftentimes, you want certain grid items to span multiple rows or columns. This can be tricky with classical approaches like float layouts.
With CSS Grid, it’s a charm:
/* Same as before */
.grid {
display: grid;
grid-template: 50px 80px / 50px 100px 50px;
grid-gap: 5px;
}
/* Second item should span row 2, and columns 2 to 3 */
.grid div:nth-child(2) {
grid-row-start: 2;
grid-row-end: 3;
grid-column-start: 2;
grid-column-end: 4;
}
This produces the following layout:
Instead of being in row 1 and column 2, the second child <div> is now in the second row and spans two columns. Note that the grid-row-end and grid-column-end are exclusive. So grid-column-end: 4 means that the grid item will end before column 4 (at the end of column 3).
Again, we can summarize these properties:
.grid div:nth-child(2) {
grid-row: 2 / 3;
grid-column: 2 / 4;
}
As you can see, you can use slashes in several CSS Grid properties.
Grid areas
One more extremely useful feature I want to mention here is grid areas. A grid area is an arbitrary rectangle of cells in your grid:
You can essentially give names to the areas in your grid and then place assign elements in those areas. For instance, you can define an entire layout with header, content, sidebar, and footer in just a few lines of code as follows:
#site {
display: grid;
grid-template:
"h h h h" 80px
"c c c s" 300px
"f f f f" 50px
/ 1fr 1fr 1fr 1fr;
grid-gap: 5px;
}
#header {
grid-area: h;
}
#content {
grid-area: c;
}
#sidebar {
grid-area: s;
}
#footer {
grid-area: f;
}
We’re making a big step here so let’s go through it step by step. The most interesting part is grid-template. It uses abbreviated syntax to define all of the following:
- There are three rows. We defined each row by one line of code before the slash.
- The first row has a height of 80px.
- The second row has a height of 300px.
- The third row has a height of 50px.
- There are four columns. We defined these by the grid area names such as “h h h h”. If you wanted six columns, you’d have to use “h h h h h h” and adapt the other two rows accordingly.
- Each column should take up equal space. We defined the column dimensions after the slash. Here, we used the special fr unit to specify that each column should take up “1 fraction” of the available space.
- There are four grid areas by the names of h, c, s, and f.
- Look at the positioning of the letters in the code. They represent your grid. For instance, grid area h will take up the entire first row. On the other hand, s will only take up one grid cell, namely column 4 in row 2.
- The names refer to “header,” “content,” “sidebar,” and “footer.” You can also use longer names; they don’t have to be single letters.
- Lastly, you simply assign the named grid areas to elements.
- For instance, #header should be placed in grid area h.
The result is this layout:
Note how easy it is to control the behavior for different screen sizes. If you want a fixed-size sidebar, simply give that column a fixed px value. Of course, you can still use media queries as usual to implement thorough responsive behavior.
This post only scratched the surface of what CSS Grid offers. If you want a practical overview of all features along with tons of practice activities, check out my full CSS Grid course:
Again, you can watch my free video series to get a taste of the course and of CSS Grid:
CSS Grid vs. Flexbox
Now that you have a solid overview of both Flexbox and CSS Grid, the question remains: When should you use which? Does Grid make Flexbox redundant? What are their use cases?
You already know their most fundamental difference:
- Flexbox is used for linear, 1D layouts
- Grid is used for grid-based, 2D layouts
Tab Atkins, one of the contributors of the W3C specifications, said it very well in this www-style email thread back in 2013 (highlights my own):
Flexbox is for one-dimensional layouts — anything that needs to be laid out in a straight line (or in a broken line, which would be a single straight line if they were joined back together).
Grid is for two-dimensional layouts. It can be used as a low-powered flexbox substitute (we’re trying to make sure that a single-column/row grid acts very similar to a flexbox), but that’s not using its full power.
Flexbox is appropriate for many layouts, and a lot of “page component” elements, as most of them are fundamentally linear. Grid is appropriate for the overall page layout and for complicated page components that aren’t linear in their design.
The two can be composed arbitrarily, so once they’re both widely supported, I believe most pages will be composed of an outer grid for the overall layout, a mix of nested flexboxes and grid for the components of the page, and finally block/inline/table layout at the “leaves” of the page, where the text and content live.
In short, there’s a place for both Grid and Flexbox.
In fact, you should combine both appropriately to build your entire page layout, from the overall grid layout down to linear or non-linear composite components, and further down to simple block or inline elements.
Use cases
Let’s sum it up by looking at a few concrete use cases, roughly top-down in the layout process:
- “I want to implement my entire site’s wireframe layout.”
- Use CSS Grid for this 2D layout.
- Consider using grid areas for readable code that assigns your main site components to grid areas.
- “I want to finely control the alignment of items.”
- Use CSS Flexbox for this typically 1D layout. It lets you finely control the flex item alignment, justification, size, order, overall direction, and the strategy for taking up the remaining space.
- “I want to implement the layout for one of my page components.”
- Use Flexbox if the component is linear.
- Use CSS Grid if the component has a grid-like layout. You may use Flexbox (or more grid-based layouts) for its child components.
- “I want to have overlapping items.”
- Use CSS Grid for this as it allows you to overlap the rows and columns an item spans.
Summary
Both Flexbox and CSS Grid massively improve the way you define layouts compared to previous approaches. Both enjoy wide browser support of about 95%.
Grid is best for 2-dimensional layouts where you need proper control over both the rows and columns. Flexbox is perfect for 1-dimensional linear layouts.
Recommended Articles
Top courses in CSS
CSS students also learn
Empower your team. Lead the industry.
Get a subscription to a library of online courses and digital learning tools for your organization with Udemy Business.