CSS Layout - Grid vs Flexbox

A good layout makes users stay on a site because it makes important stuff easily accessible and intuitive to find. A lousy layout frustrates users, who leave because they can't find what they are looking for.

In web design, a layout is a term that explains how a website is displayed on the screen. HTML 5 has quite a few elements that define parts of a web page: header, nav, section, aside, article, and footer are the significant distinctions in creating a layout. They constitute the four major sections of a webpage - header/banner, navigation, content, and footer.

Programming languages make websites feel alive, but at the core of every web page stands the good old HTML. When we discuss layouts, we must consider factors that make a good layout: responsiveness, viewing ports, display devices, browsers, and users’ screen sizes. A great layout not only looks great but can preserve the original intent by fitting in every possible display ratio. This correction is produced through CSS. In this article, we will examine two powerful properties: CSS Flexbox and CSS Grid.

Generic Web Layout
Generic Web Layout

WHAT IS CSS FLEXBOX LAYOUT?

The Flexible Box Module, commonly shortened to ‘flexbox,’ is a one-dimensional layout model. This means it deals with either row or column at a time but never both together. Flexbox is efficient when in aligning, distributing, and directing elements in a page.

Two key terminologies in Flexbox are the main axis and the cross axis. A flex container's main axis is the primary axis along which these flex items are laid out, and the cross-axis is perpendicular to it.

To start, we will wrap our HTML divs in a flex-wrapper

<div class="flex-wrapper">
  <div id="one">Header</div>
  <div id="two">Nav</div>
  <div id="three">Content</div>  
  <div id="four">Footer</div>
</div>

In CSS, our parent container, "flex-wrapper" will be converted to a flexbox with a simple line of code.

.flex-wrapper { 
  display: flex; 
} 

I'll be adding a few elements and properties with bright colors and margins to make our containers and divs stand out.

.flex-wrapper{ 
  display: flex; 
  background-color: beige; 
} 
.flex-wrapper > div { 
  background-color: green; 
  height: 100px; 
  width: 100px; 
  margin: 10px; 
} 

You can see how nicely the div elements position itself horizontally. But if you notice, it doesn’t entirely take up all the space within the container. There’s a gap at the end. We can change this by adding flex-grow.

.flex-wrapper > div { 
  flex-grow: 1; 
}

The flex-grow element distributes each item in a flex container. The default is 0, and by assigning a unit number to any of the divs, you can make it grow more massive than the rest. The opposite of this is flex-shrink.

#one{ 
  flex-grow: 10;
} 
/* this gives the first div ten more units than the others */

Flex-direction

Flex-direction controls the direction in which items in a flex container should face. You can make the divs go up, down, left, and right. You can also have them in reverse order. By default, items in a flex-container are ordered from left to right, horizontally, within the main axis.

.flex-wrapper{ 
  display: flex; 
  flex-direction: row; /* default direction */ 
}
.flex-wrapper{ 
  display: flex; 
  flex-direction: row-reverse;  
}

Here, the items are displayed from left to right, but in reverse order. The fourth div now becomes the first and the first — the last.

.flex-wrapper{ 
  display: flex; 
  flex-direction: column; 
} 

The divs are ordered from in a vertical manner - from up to down.

.flex-wrapper{ 
  display: flex; 
  flex-direction: column-reverse; 
}

The divs are ordered vertically, but in reverse, where the fourth div is at the top, and the first one is at the bottom.

Flex Basis

Flex basis defines the size of an item or a div inside the flex-container. This size value can be in em, px, or percentage. Flex-basis is different from flex-grow because it doesn’t equally share the space between items in a container.

#three { 
  flex-basis: 200px; 
}

Flex

Flex is a shorthand property that combines flex-shrink, flex-grow and flex-basis. It is recommended that you use this property instead of writing each individual property and its value. The order to set the values for the property is this: flex-grow, flex-shrink, flex-basis.

.flex-wrapper { 
  display: flex; 
  flex: 0 0 200px; 
} 

Justify-content and align-self

Justify-content and align-self is the perfect solution to centralize a div or a container on a browser using flexbox.

.flex-wrapper { 
  display: flex; 
  flex: 0 0 200px; 
  justify-content: center; 
  align-items: center; 
} 

CSS Layout GRID

CSS grid is a powerful 2-dimensional layout. This means it can handle both the rows and columns of the layout. CSS grid works with a 12-grid arrangement, where the screen is (invisibly) divided into 12 parts, and items must fit into this arrangement.
CSS grid's advantage over flexbox and other layout models is its two-dimensional quality. It also makes positioning more straightforward, and the container’s elements can be set to overlap and overlap each other.

Defining a grid in CSS grid

A simple CSS line will transform an HTML structure to a CSS grid.

<div class="container"> 
  <div id="one">Header</div> 
  <div id="two">Nav</div> 
  <div id="three">Content</div>  
  <div id="four">Aside</div>   
  <div id="five">Section</div>  
  <div id="six">Footer</div> 
</div> 
.container { 
  display: grid; 
} 

Grid template-columns and grid-template-rows

The grid-template-columns and grid-template-row define the size of a column or row. It assigns a div a size depending on what is assigned. When you set the size of a template-column and template-grid size, you use px, fr, percentage, or em.

.container { 
  display: grid; 
  grid-template-columns:  40px 1fr 20%;  
  grid-template-rows: 200px; 
  background-color: beige;   
}
.container > div { 
  background-color: green; 
  margin: 10px; 
} 

grid-template-columns: 40px 1fr 20%; - this line of code tells the browser to assign the first div a width of 40px. The second takes one fraction of the assigned space and the third 20%. Automatically, divs 4 to 6 move below the first 3, and takes on the values assigned in the same order. This means div 4 is assigned 40px, div 5 one fraction and div 6, 20%.

To place all six divs on one line, we must assign six values to the grid-template-column. We do not have to give different measurements to the grid-columns. We could use only percentages, fr, or px.

grid-template-rows: 200px; - this assigns all the divs a height of 200px;

FR

.container { 
  display: grid; 
  grid-template-columns: 16.7% 16.7% 16.7% 16.7% 16.7% 16.7%;  
} 

By assigning 16.7% in 6 places, I have successfully divided the six divs in the container into six equal parts on the screen. I used 16.7 because 16.7 times 6 gives 100% of the screen width.

Using percentage and px works perfectly, but it lacks adequate flexibility and belies the most useful resource - a fraction of the CSS grid.

Fr is a fractional unit. It assigns each item one fraction of available space. The fractional space can be increased to accommodate each div according to how much space they need.

Our grid-template-columns now becomes

grid-template-columns: 1fr 1fr 1fr 1fr 1fr 1fr; 

This divides each div equally on the screen.

grid-template-columns: 1fr 2fr 1fr 2fr 1fr 1fr; 

This new value makes the second and fourth div twice the size of the rest. Most importantly, it is still distributed evenly on the browser and very much responsive.

Repeat Function

Rather than write down the values repeatedly, we can take advantage of the repeat function to assign values once.

.container { 
  display: grid; 
  grid-template-columns: repeat(6, 1fr);
}

The syntax is relatively straightforward. We need to use the word ‘repeat’ and then assign how many times we want the size repeated, which is 6, and then give the measurement value. This repeat function works with fr, em, px as well as percentage. This works for template-row as well.

Gap

Gap, also called gutter is a CSS grid property that allows you to specify the gap-space between divs in a CSS grid container. It works just like the margin property and is calculated mainly in px.

gap: 10px;

Grid-column-start/grid-column-end and grid-row-start/grid-row-end

The grid-column-start and grid-column-end place a grid item in a particular location within the column by referring to specific grid lines. The grid-row-start and grid-row-end also do the same to the row. By assigning a value to this property, grid items can be conveniently manipulated to start and end within the specified areas.

.container { 
  display: grid; 
  grid-template-columns: repeat (3, 1fr); 
  grid-template-rows: repeat(4, 200px); 
}
#one { 
  grid-column-start: 1; 
  grid-column-end: 3; 
  grid-row-start: 1; 
  grid-row-end: 4; 
}

When you assign these values to the first div, you’ll notice it pushes the second div one unit away, and it occupies the first two positions, pushing div 3 below. Row-wise, it now occupies three positions giving it a longer height.

There is a rule when indexing in programming because we generally count from 0, which applies here. The last value is usually mentioned, but not put into effect. For example, the grid-column-end is 3, but it stops at 2 just like the grid-row-end, which ends at 3 and not 4.

Grid-columns and grid-row

Gap, also called gutter is a CSS grid property that allows you to specify the gap-space between divs in a CSS grid container. It works just like the margin property and is calculated mainly in px.

#one { 
  grid-column: 1/3; 
  grid-row: 1/4; 
}

Creating galleries using CSS grid

CSS grid is the perfect model to create galleries. With little code and manipulation, you could make perfect, responsive gallery layouts.

A Mosaic Gallery Layout

A mosaic gallery layout creates even tiles of images distributed evenly over a page/container.

<div class="container"> 
  <div id="one">Image One</div> 
  <div id="two">Image Two</div> 
  <div id="three">Image Three</div>  
  <div id="four">Image Four</div>   
  <div id="five">Image Five</div>  
  <div id="six">Image Six</div> 
  <div id="seven">Image Seven</div> 
  <div id="eight">Image Eight</div> 
  <div id="nine">Image Nine</div> 
</div>
.container{ 
  display: grid; 
  grid-template-columns: repeat(3, 1fr);  
  grid-template-rows: repeat(3, 200px); 
  background-color: beige; 
  gap: 10px 
}
.container > div { 
  background-color: green; 
}

This creates a perfectly tiled mosaic image gallery layout.

Mosaic Layout
Mosaic Layout

A Masonry Gallery Layout

This layout is uneven due to the fact it does not have a fixed row height. Using the grid-columns and grid-rows, we can adjust images to fit and move across assigned fractional units as we want to.

.container { 
  display: grid; 
  grid-template-columns:  repeat(3, 1fr);  
  grid-template-rows: repeat(5, 200px); 
  background-color: beige; 
  gap: 10px; 
}
.container > div { 
  background-color: green; 
}
#one { 
  grid-column: 1/3; 
  grid-row: 1/4; 
} 
#two { 
 grid-row: 1/3; 
}  
#five { 
  grid-column: 4/2; 
}   
#seven { 
  grid-row: 6/1; 
}
Masonry Layout
Masonry Layout

Grid Template Areas

Grid-template-area assigns a name to a div/element so the grid-area property can reference it. It works just like grid-column and grid-row, allowing certain areas to be mapped and accommodated with ease within the grid structure.

<div class="container">
  <div id="one">Header</div> 
  <div id="two">Nav</div> 
  <div id="three">Aside</div>  
  <div id="four">Content</div>   
  <div id="five">Section</div>  
  <div id="six">Footer</div>
</div>
.container { 
  display: grid; 
  grid-template-columns:  repeat(3, 1fr);  
  grid-template-rows: repeat(2,100px); 
  background-color: beige; 
  gap: 10px; 
  grid-template-areas: 'header header header' 
                       'nav nav nav' 
                       'aside content content' 
                       'aside section section' 
                       'footer footer footer'; 
}
.container > div { 
  background-color: green; 
  font-size: 40px; 
}   
#one { 
  grid-area: header; 
} 
#two { 
 grid-area: nav; 
}
#three { 
  grid-area: aside; 
}     
#four { 
  grid-area: content; 
} 
#five { 
  grid-area: section; 
}    
#six { 
  grid-area: footer; 
}
Section Element Flow

Grid Areas

Referencing the named areas must be done in the order in which they were called. For example, the grid area for #one cannot be footer since this is the last-named grid area. Not keeping the order will raise an error in the design.

CSS Flexbox vs. Grid - Which should you use?

In a nutshell, Grid is a Container-Based layout, while Flexbox - Content-Based. Both CSS Grid and Flexbox are powerful in their ways, although CSS grid packs more features and makes it easier to manipulate rows and columns within the grid. Before deciding which to choose, understand the complexity, the structure and the content of the site you are to build. Here’s a little more in-depth comparison: in flexbox layout, the size of a cell (flex-item) is defined within the flex-item itself, and in the grid layout, the size of a cell (grid-item) is defined inside the grid-container.

I would advise, though, that you use CSS Grid for the overall layout of the site and then Flexbox for the container's items. CSS Grid also works perfectly for individual items, and it accommodates nuances within the actual grid structure more than Flexbox. For example, grid template areas will map out the site's structure in a few seconds, and you can focus on aligning content as you deem fit.

Author

Ivaylo Ivanov

Ivaylo loves Frontend implementations. He is eager to construct interfaces that users love; pixel-perfect. In his day-to-day job, he caters to anything HTML, CSS, SCSS, or JavaScript-based on the frontend side. Complexity is not a problem, he masters VueStorefront implementations equally well to simple web apps or PWAs.
Experimentation with CSS and its' capabilities is Ivo's passion. Be it animated elements, or SVG animations - he loves it!