CSS Grid VS Flexbox: A Practical Comparison
Not so long ago, all HTML pages were laid out using tables, floats, and other CSS properties, but these properties weren’t really suitable for designing complex web pages.
Then came Flexbox, a layout pattern specifically designed to create powerful, responsive pages. Making it easy to align elements and content correctly is now the CSS system of choice for most web developers.
Now we have a new contender for the “best system for Building HTML Layouts” trophy — the powerful CSS Grid, which will be released in Firefox 52 and Chrome 57 by the end of this month, and (hopefully) other browsers soon to follow.
Basic layout testing
To see what it’s like to build a layout with each system, we built the same HTML page twice — once using Flexbox and once using CSS Grid. You can download both projects from the download button near the top of the original article, or view them in this online demo:
The design is very simple — it consists of a central container containing a header, main section, sidebar, and footer. Here are the main “challenges” we had to solve while keeping CSS and HTML as clean as possible:
- The layout has four main parts
- Responsive layout (sidebar below main content when the screen is small)
- Align the contents of the title navigation to the left and the buttons to the right
As you can see, we’ve kept everything as simple as possible for comparison purposes. Let’s start with the first question.
Challenge 1: Locate the page section
Flexbox scheme
Let’s start with flexbox. We add display: flex to the container and Orient its children vertically. This will make all the modules go down one after the other.
.container {
display: flex;
flex-direction: column;
}
Copy the code
Now we need to put the main section next to the sidebar. Since Flex containers are usually one-way, we need to add a Wrapper element.
<div class="main-and-sidebar-wrapper">
<section class="main"></section>
<aside class="sidebar"></aside>
</div>
<footer></footer>
Copy the code
We then set the wrapper display to :flex and flex-direction to the opposite direction.
.main-and-sidebar-wrapper {
display: flex;
flex-direction: row;
}
Copy the code
The last step is to set the size of the main section and sidebar. We want the main content to be three times the size of the sidebar, which is not difficult for Flex or percentages.
.main {
flex: 3;
margin-right: 60px;
}
.sidebar {
flex: 1;
}
Copy the code
You can see that Flexbox has done a good job, but we still need quite a few CSS properties + an extra HTML element. Let’s take a look at how CSS grids work.
CSS Grid plan
There are several different ways to use CSS grids, and we’ll use grid-template-areas, which seems to be the best fit for what we’re trying to accomplish right now.
First, we will define four grid-Areas, one for each grid area:
<! -- Notice there isn't a wrapper this time -->
<section class="main"></section>
<aside class="sidebar"></aside>
<footer></footer>
Copy the code
header {
grid-area: header;
}
.main {
grid-area: main;
}
.sidebar {
grid-area: sidebar;
}
footer {
grid-area: footer;
}
Copy the code
Then we can set up our grid and assign the location of each region.
The following code may seem fairly complex at first, but it’s easy to understand once you understand the grid system.
.container {
display: grid;
/* Define the size and number of columns in our grid.
The fr unit works similar to flex:
fr columns will share the free space in the row in proportion to their value.
We will have 2 columns - the first will be 3x the size of the second. */
grid-template-columns: 3fr 1fr;
/* Assign the grid areas we did earlier to specific places on the grid.
First row is all header.
Second row is shared between main and sidebar.
Last row is all footer. */
grid-template-areas:
"header header"
"main sidebar"
"footer footer";
/* The gutters between each grid cell will be 60 pixels. */
grid-gap: 60px;
}
Copy the code
That’s it! The layout now follows the structure described at the beginning and now doesn’t even need to deal with any edges or padding.
Challenge 2: Make your pages responsive
Flexbox scheme
The execution of this step is closely related to the previous step. For the Flexbox solution, we would have to change the Flex-direction of the Wrapper and adjust some margins.
@media (max-width: 600px) { .main-and-sidebar-wrapper { flex-direction: column; } .main { margin-right: 0; margin-bottom: 60px; }}Copy the code
The page is really simple, so there isn’t much to change in the media query, but in a more complex layout there will be many, many things that need to be redefined.
CSS Grid plan
Now that we’ve defined grid-Areas, we just need to reorder them in our media query. We can use the same column Settings.
@media (max-width: 600px) {
.container {
/* Realign the grid areas for a mobile layout. */
grid-template-areas:
"header header"
"main main"
"sidebar sidebar"
"footer footer"; }}Copy the code
Or, if we feel we need to, we can redefine the entire layout from scratch
@media (max-width: 600px) {
.container {
/* Redefine the grid into a single column layout. */
grid-template-columns: 1fr;
grid-template-areas:
"header"
"main"
"sidebar"
"footer"; }}Copy the code
Challenge 3: Align component headers
Flexbox scheme
The header includes some navigation links and a button. We want navigation on the left and buttons on the right. Links in navigation must be properly aligned with each other.
<header>
<nav>
<li><a href="#"><h1>Logo</h1></a></li>
<li><a href="#">Link</a></li>
<li><a href="#">Link</a></li>
</nav>
<button>Button</button>
</header>
Copy the code
In an old article The Easiest Way To Make Responsive Headers, we’ve done a similar layout using Flexbox. The technique is very simple:
header {
display: flex;
justify-content: space-between;
}
Copy the code
Navigation lists and buttons are now properly aligned. All that is left is to center the items in
header nav {
display: flex;
align-items: baseline;
}
Copy the code
Only two lines! Not bad at all. Let’s take a look at how CSS Grid handles it.
CSS Grid plan
To separate the navigation from the button, we have to set the header to display: grid and set up a 2-column grid. Two additional lines of CSS are required to position them on their respective boundaries.
header{
display: grid;
grid-template-columns: 1fr 1fr;
}
header nav {
justify-self: start;
}
header button {
justify-self: end;
}
Copy the code
As for inline links in navigation — we can’t do that very accurately with CSS Grid. Here’s our best try:
These links are inline, but they don’t align properly because there is no baseline option like flexbox’s align-items. We also have to define another subgrid.
header nav {
display: grid;
grid-template-columns: auto 1fr 1fr;
align-items: end;
}
Copy the code
Clearly, CSS Grid is having trouble with this part of the layout, but that’s not surprising — the focus is on tweaking the container, not the contents of the container.
conclusion
If you’ve read the entire article, this conclusion will come as no surprise to you. The truth is, there is no single optimal solution — Flexbox and CSS Grid are good at different things that dictate different usage scenarios, and they should be used together, not as competitors.
For those of you who jump straight to the conclusion of the article (don’t worry, I do this all the time), here’s a summary of the full comparison:
CSS grids
Useful for building larger images. They make it very easy to manage page layouts and even handle more unconventional and asymmetric designsFlexbox
Very good at aligning element content, it can be used to locate smaller details in a design- use
CSS grids
Layout in 2D (rows and columns) Flexbox
It works better with only one dimension (row or column)- There’s no reason to just use
CSS grids
Or only useflexbox
. We should learn them at the same time and use them