skip to content
usubeni fantasy logo Usubeni Fantasy

Mastering CSS Flex and Grid Layouts

/ 10 min read

This Post is Available In: CN EN

Remember those dark days when CSS layouts were a nightmare? float: left paired with clear: both, countless hacks and workarounds just to make elements behave properly. Fortunately, modern CSS blessed us with two layout superpowers: Flex and Grid.

If you’re already using these layout methods but occasionally get confused by axes and alignment, this review guide is perfect for you. We’ll start from the fundamental concepts, move to practical usage techniques, explore Tailwind’s atomic class abstractions, and wrap up with some real-world insights.

Ready? Let’s dive in!

Flex

Flex is short for “flexible layout,” and as the name suggests, it’s all about flexibility. (Cue the boing sound effect!)

Flexibility

In a flex container, we only need to set widths for some items, while others can dynamically adjust their size to fill the remaining space.

Here’s the most common use case in code:

<div class="fixed-flex">
<div class="side">Sidebar</div>
<div class="main">Main Content</div>
</div>
<style>
.fixed-flex {
display: flex;
}
.side {
width: 200px;
background: #ffecb3;
}
.main {
flex-grow: 1;
flex-shrink: 1;
flex-basis: 0%;
background: #fff9c4;
}
</style>

The .side has a fixed width of 200px, while for .main:

  • No explicit width: flex-basis: 0%
  • Grows when extra space is available: flex-grow: 1
  • Shrinks when space is limited: flex-shrink: 1

These 3 values can be shortened to flex: 1. However, beginners should avoid using flex shorthand other than flex: 1, as the syntax can be quite complex.

Wrapping

Sometimes you don’t want to squeeze everything into a single line. Flex provides wrapping options for that.

<div class="wrap-layout">
<div>Akira</div>
<div>Astro Boy</div>
<div>Cowboy Bebop</div>
<div>Dragon Ball Z</div>
<div>Fullmetal Alchemist</div>
<div>Ghost in the Shell</div>
<div>Mobile Suit Gundam</div>
<div>Neon Genesis Evangelion</div>
<div>Princess Mononoke</div>
<div>Sailor Moon</div>
</div>
<style>
.wrap-layout {
display: flex;
flex-wrap: wrap;
gap: 10px;
}
.wrap-layout div {
width: auto;
background: #c8e6c9;
padding: 10px;
text-align: center;
}
</style>

By default, flex layout is single-line, and elements get squeezed when there’s insufficient space. Adding flex-wrap: wrap; allows items to maintain their width and wrap to new lines automatically.

Cross Axis

Flexbox is designed as a one-dimensional layout system—it’s either row or column. This means all child elements line up along the main axis. However, wrapping inevitably creates a two-dimensional layout, introducing the concept of the cross axis.

By default, the horizontal direction is the main axis, and wrapping creates a cross axis perpendicular to it.

CSS properties related to the main axis have the justify prefix:

  • justify-content

CSS properties related to the cross axis have the align prefix:

  • align-content
  • align-items
  • align-self

align-content controls the distribution between lines in multi-line scenarios—it won’t take effect without wrap; align-items controls the alignment of elements within a single line.

Direction

We can switch the main axis direction using flex-direction: column;.

<div class="column-layout">
<div>Top</div>
<div>Middle</div>
<div>Bottom</div>
</div>
<style>
.column-layout {
display: flex;
flex-direction: column;
gap: 10px;
}
</style>

It’s that simple! Just one line of flex-direction: column; switches the main axis from horizontal to vertical. The tricky part is the mental adjustment it requires.

All the concepts we discussed—main axis, cross axis, justify, align, wrapping—remain the same. You just need to reframe your understanding with a vertical main axis. It’s not difficult, just takes time to adapt.

Centering

Flex provides the most convenient centering method of the modern era: justify-content: center; and align-items: center;.

Veterans who’ve been doing frontend since 2015 still remember the days when we had to memorize various CSS centering hacks. Now that browsers have caught up, Flex solves most centering problems.

As mentioned above, justify-content controls distribution along the main axis, while align-items controls alignment along the cross axis. Combined, they achieve perfect centering within a flex container.

<div class="center">
<p>Centered Content</p>
</div>
<style>
.center {
display: flex;
justify-content: center;
align-items: center;
height: 200px;
background: #f0f0f0;
}
</style>

Now someone might ask: “Can’t we use align-content to center from a line perspective?” Yes, you can, but as mentioned earlier, you must set wrap for align-content to take effect, so you need an extra line:

.center {
display: flex;
justify-content: center;
flex-wrap: wrap;
align-content: center;
height: 200px;
background: #f0f0f0;
}

You can play around with Flex’s wrap, align, and justify properties and see their effects on element layout at this interactive learning site.

Bonus: What to do when flex containers overflow? When you set text to not wrap, flex containers often get stretched beyond their bounds. Remember to set the overflow property in such cases. I find this quirky—when layouts are vertical, I easily remember to set overflow, but when using Flex with horizontal layouts, I always forget! 😂

Grid

Grid layout is essentially a game of drawing grids. Let’s see how to draw these grids with an example:

.container {
display: grid;
grid-template-columns: 100px 200px auto;
grid-template-rows: 50px auto 50px;
}

In some ways, Grid is simpler than Flex because you don’t need to constantly switch between main axis and cross axis concepts—less mental overhead. With Grid, you just need to know how to set up rows and columns.

grid-template-columns defines the grid’s columns. 100px 200px auto means the first column is 100px, the second is 200px, and the third is auto-sized.

grid-template-rows defines the grid’s rows. 50px auto 50px means the first row is 50px, the second is auto-sized, and the third is 50px.

There’s also a very useful unit called fr, which represents flexible fractions (fractional units of remaining space). For example:

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

This divides the columns into 3 equal parts.

Alignment

Flexbox children are always tightly packed along the main axis with no extra space for individual alignment, so Flex doesn’t have justify-items. Alignment along the main axis is uniformly controlled by the parent container’s justify-content property, which determines how all child elements are distributed and aligned as a whole along the main axis.

In contrast, Grid is about drawing grids. Once the grid is drawn, child elements can do their own thing within their cells, naturally supporting justify-items.

Named Grid Areas

<div class="grid-container">
<header class="header">Header</header>
<nav class="nav">Navigation</nav>
<main class="content1">Content 1</main>
<main class="content2">Content 2</main>
<footer class="footer">Footer</footer>
</div>
<style>
.grid-container {
display: grid;
grid-template-areas:
"header header header"
"nav content1 content1"
"nav content2 content2"
"footer footer footer";
grid-template-columns: 150px 1fr 1fr;
grid-template-rows: 100px 1fr 1fr 60px;
gap: 10px;
height: 90vh;
}
.header {
grid-area: header;
background-color: #f0c3a2;
}
.nav {
grid-area: nav;
background-color: #a2d2ff;
}
.content1 {
grid-area: content1;
background-color: #b7efc5;
}
.content2 {
grid-area: content2;
background-color: #b7efc5;
}
.footer {
grid-area: footer;
background-color: #f2e293;
}
</style>

This is quite fun, I must say! After configuring row and column dimensions, you can “draw” the page structure with text:

"header header header"
"nav content1 content1"
"nav content2 content2"
"footer footer footer"

Grid Spanning

Besides “drawing” with grid-template-areas, you can also design page elements using grid spanning.

.grid-container {
display: grid;
grid-template-columns: 150px 1fr 1fr;
grid-template-rows: 100px 1fr 1fr 60px;
gap: 10px;
height: 90vh;
}
.header {
grid-column: 1 / 4;
grid-row: 1 / 2;
background-color: #f0c3a2;
}
.nav {
grid-column: 1 / 2;
grid-row: 2 / 4;
background-color: #a2d2ff;
}
.content1 {
grid-column: 2 / 4;
grid-row: 2 / 3;
background-color: #b7efc5;
}
.content2 {
grid-column: 2 / 4;
grid-row: 3 / 4;
background-color: #b7efc5;
}
.footer {
grid-column: 1 / 4;
grid-row: 4 / 5;
background-color: #f2e293;
}

The numbers after grid-column represent content from the Nth grid line to the Mth grid line. This might seem abstract—why use grid lines instead of saying “Nth column”?

Actually, there is a column-based syntax too, for example:

.header {
grid-column: 1 / span 3;
grid-row: 1 / span 1;
background-color: #f0c3a2;
}

If you want to control a specific span range, you still need to start with a number, then add span number. 1 / span 3 means starting from the 1st grid line, spanning 3 columns.

Writing grid-column: span 3; directly only represents 3 columns but doesn’t control the starting position.

Alignment

Grid also has the align- and justify- alignment system, with effects similar to those mentioned in Flex. You can play around with Grid’s align and justify properties and see their effects on element layout at this interactive learning site.

place-content is a CSS shorthand property that sets both align-content and justify-content properties simultaneously. It’s mainly used for Grid layout, since Flex layout rarely sets these two properties together. Here’s an example:

place-content: center;
place-content: end space-between;

With one value, it applies to both horizontal and vertical directions. With two values, the order is place-content: <align-content> <justify-content>;.

If there’s content, is there also items? Yes, my friend, as you might guess, there’s place-items, and its usage follows the same logic—no need to elaborate further.

Grid has slightly less browser support than Flex, but the future looks promising. Users are updating their browsers more easily now, and the need to support legacy browsers is greatly reduced compared to before.

Tailwind

Tailwind wraps common Flex and Grid APIs into atomic classes that can be combined directly in class attributes. In some ways, learning Flex layout directly through Tailwind might be easier, but if you’re a Tailwind opponent, feel free to skip this section.

Let’s recreate the key examples above using class names:

Flex Basics

  • Container and direction:
flex
flex flex-col
flex-row-reverse
flex-col-reverse
  • Spacing and wrapping:
gap-4
gap-x-6 gap-y-2
flex-wrap
flex-nowrap

Flex Alignment

  • Main axis/cross axis (container):
flex justify-between items-center
flex justify-center items-stretch
  • Multi-line content distribution (container, only noticeable when flex-wrap is active):
flex flex-wrap content-between
flex flex-wrap content-center
  • Individual item alignment (child items):
self-start
self-center
self-end
self-stretch

Flex Item Sizing and Order (child items)

  • Ratio/grow/shrink/basis:
flex-1
grow
shrink-0
basis-40

Grid Basics

  • Container and grid tracks:
grid
grid-cols-3
grid-rows-4
  • Using custom column/row sizes (corresponding to 150px / 1fr / 1fr and 100px / 1fr / 1fr / 60px from above):
grid grid-cols-[150px_1fr_1fr] grid-rows-[100px_1fr_1fr_60px] gap-2 h-[90vh]

Recreating the Layout Above with Spanning

Tailwind doesn’t natively provide atomic classes for grid-template-areas. The example above can be implemented using col-start/col-end and row-start/row-end combinations:

  • Header (spans 3 columns, 1 row):
col-start-1 col-end-4 row-start-1 row-end-2
  • Nav (1st column, spans from 2nd to 4th row):
col-start-1 col-end-2 row-start-2 row-end-4
  • Content1 (columns 2-3, row 2):
col-start-2 col-end-4 row-start-2 row-end-3
  • Content2 (columns 2-3, row 3):
col-start-2 col-end-4 row-start-3 row-end-4
  • Footer (spans 3 columns, 1 row):
col-start-1 col-end-4 row-start-4 row-end-5

You can also use shorthand:

col-span-3 row-span-1

(Use start/end when determining starting lines; use col-span-/row-span- when only controlling span.)

Grid Alignment

  • Set both align-content and justify-content (container):
place-content-center
place-content-between
  • Set both align-items and justify-items (container):
place-items-center
  • Horizontal only/vertical only (container):
justify-items-start
align-items-end
  • Auto-placement direction and dense packing:
grid-flow-col
grid-flow-row-dense

Takeaways

  • Flex is better suited for one-dimensional distribution and alignment, while Grid excels at two-dimensional grids with row and column spanning. In real projects, a common strategy is “outer Grid for layout zones, inner Flex for content arrangement.”
  • Remember the axes: justify-* works on the main axis, align-* works on the cross axis. When switching to column direction, both “rotate” along with the main axis.
  • Impact of wrapping: align-content only takes effect when flex-wrap is set. Focus on align-items/align-self for single lines, consider align-content for multiple lines.
  • Flex item sizing principle: Fixed + adaptive = fixed width + flex: 1 (equivalent to grow-1 shrink-1 basis-0%). Except for flex: 1, beginners should use more complex flex shorthand cautiously.
  • Grid’s core is “drawing grids”: grid-template-columns/rows with fr units define tracks; use grid-column/grid-row for spanning (like 1 / 4 or 1 / span 3); template-areas provides intuitive named layouts.
  • Alignment overview: Grid also supports justify-items/align-items and shorthand combinations like place-content/place-items, controlling both “content as a whole” and “within cells.”
  • Compatibility and practice: Grid support is slightly less than Flex, but modern browsers are generally compatible. Choose Flex conservatively for legacy environments; prioritize Grid + Flex combinations for new projects.
Loading comments...