Skip to content

Grid Layout: The Two-Dimensional Revolution in CSS Layout โ€‹

Imagine you are designing a newspaper layout. The newspaper has clear rows and columns, headlines might span multiple columns, images might occupy multiple rows, and articles are arranged in columns. You need to precisely control the position and size of each element in both horizontal and vertical directions simultaneously. This is a typical scenario for two-dimensional layout.

Before Grid Layout appeared, creating such complex layouts required a lot of nested divs, complicated calculations, and a combination of various layout tricks. Grid Layout is like a professional design grid paper prepared for web designers, allowing you to freely place elements at the intersections of rows and columns, easily achieving complex two-dimensional layouts.

Why We Need Grid โ€‹

Limitations of Traditional Layouts โ€‹

We already have Flexbox, so why do we need Grid? Because they solve different problems.

Flexbox is a one-dimensional layout model; it can only handle one direction at a timeโ€”either a row or a column. When you try to create complex two-dimensional layouts with Flexbox, you'll find yourself trapped in a dilemma of multiple layers of nesting.

Let's look at a practical example. Suppose you want to create a typical website layout:

+------------------+------------------+
|      Header                         |
+------------------+------------------+
|  Sidebar  |   Main Content         |
|           |                         |
|           +------------------------+
|           |   Aside                |
+------------------+------------------+
|      Footer                         |
+------------------+------------------+

Using Flexbox, you would need to do this:

html
<div class="page">
  <header>Header</header>
  <div class="content-wrapper">
    <!-- Extra wrapper element needed -->
    <aside class="sidebar">Sidebar</aside>
    <div class="main-and-aside">
      <!-- Another wrapper element -->
      <main>Main Content</main>
      <aside class="aside">Aside</aside>
    </div>
  </div>
  <footer>Footer</footer>
</div>
css
.page {
  display: flex;
  flex-direction: column;
}

.content-wrapper {
  display: flex;
  flex: 1;
}

.sidebar {
  flex: 0 0 200px;
}

.main-and-aside {
  display: flex; /* Third layer of flex nesting */
  flex-direction: column;
  flex: 1;
}

.main-and-aside main {
  flex: 1;
}

See that? You need to add extra wrapper elements, use multi-layered nested Flexbox, and the HTML structure becomes less semantic.

Grid's Elegant Solution โ€‹

Now let's implement the same layout using Grid:

html
<div class="page">
  <header>Header</header>
  <aside class="sidebar">Sidebar</aside>
  <main>Main Content</main>
  <aside class="aside">Aside</aside>
  <footer>Footer</footer>
</div>
css
.page {
  display: grid;
  grid-template-columns: 200px 1fr; /* Two columns: fixed width sidebar, flexible content area */
  grid-template-rows: auto 1fr 1fr auto; /* Four rows: header, main, aside, footer */
  min-height: 100vh;
}

header {
  grid-column: 1 / 3; /* Spans two columns */
  grid-row: 1;
}

.sidebar {
  grid-column: 1;
  grid-row: 2 / 4; /* Spans from row 2 to row 4 (occupying the height of main and aside) */
}

main {
  grid-column: 2;
  grid-row: 2; /* Second row */
}

.aside {
  grid-column: 2;
  grid-row: 3; /* Third row */
}

footer {
  grid-column: 1 / 3; /* Spans two columns */
  grid-row: 4;
}

See the difference? The HTML structure is cleaner and more semantic, requiring no extra wrapper elements. Although the CSS code might look a bit unfamiliar, the logic is clear: we defined a 2ร—4 grid (2 columns, 4 rows) and then told each element which cells it should occupy.

Core Concepts of Grid โ€‹

To master Grid Layout, you need to understand several core concepts. These concepts are like the "vocabulary" of Grid; once understood, you can use Grid for layout fluently.

Grid Container and Grid Items โ€‹

Similar to Flexbox, Grid Layout is also based on the relationship between container and items:

html
<div class="grid-container">
  <!-- This is the grid container -->
  <div class="grid-item">Item 1</div>
  <!-- These are grid items -->
  <div class="grid-item">Item 2</div>
  <div class="grid-item">Item 3</div>
</div>
css
.grid-container {
  display: grid; /* Creates a grid container */
}

Once you set display: grid on an element, it becomes a grid container, and its direct children automatically become grid items.

Grid Lines โ€‹

Grid lines are the foundation of the grid structure. Imagine drawing a 3ร—3 grid on paper; you need 4 vertical lines and 4 horizontal lines.

1   2   3   4  โ† Vertical grid line numbers
โ”Œโ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ” 1 โ† Horizontal grid line numbers
โ”‚   โ”‚   โ”‚   โ”‚
โ”œโ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”ค 2
โ”‚   โ”‚   โ”‚   โ”‚
โ”œโ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”ค 3
โ”‚   โ”‚   โ”‚   โ”‚
โ””โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”˜ 4

In CSS Grid, grid lines are numbered starting from 1. A 3-column grid has 4 vertical lines (1, 2, 3, 4), and a 3-row grid has 4 horizontal lines (1, 2, 3, 4).

You can use these numbers to precisely position elements:

css
.item {
  grid-column-start: 1; /* Starts from vertical line 1 */
  grid-column-end: 3; /* Ends at vertical line 3 */
  /* Equivalent to spanning column 1 and column 2 */
}

A more concise way is to use the shorthand property:

css
.item {
  grid-column: 1 / 3; /* From 1 to 3 */
}

Grid Tracks โ€‹

A grid track is the space between two adjacent grid lines, which can be a row track (horizontal) or a column track (vertical).

    Col Track 1  Col Track 2  Col Track 3
    โ”Œโ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”
    โ”‚     โ”‚     โ”‚     โ”‚ Row Track 1
    โ”œโ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”ค
    โ”‚     โ”‚     โ”‚     โ”‚ Row Track 2
    โ”œโ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”ค
    โ”‚     โ”‚     โ”‚     โ”‚ Row Track 3
    โ””โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”˜

When you define grid-template-columns: 200px 300px 400px, you create three column tracks with widths of 200px, 300px, and 400px respectively.

Grid Cells โ€‹

A grid cell is the smallest space enclosed by four grid lines, just like a cell in a table.

โ”Œโ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”
โ”‚Cell โ”‚Cell โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚Cell โ”‚Cell โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”˜

A grid item can occupy one or multiple grid cells.

Grid Areas โ€‹

A grid area is a rectangular area composed of any number of grid cells. A grid item can occupy a grid area.

โ”Œโ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”
โ”‚     A     โ”‚  B  โ”‚
โ”‚           โ”œโ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚           โ”‚  C  โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”˜

In this example, A occupies a 2ร—2 area, while B and C each occupy a 1ร—1 area.

Creating Your First Grid Layout โ€‹

Let's start with a simple example to gradually understand how Grid Layout works.

Basic Grid โ€‹

First, create a simple 3ร—3 grid:

html
<div class="grid">
  <div class="item">1</div>
  <div class="item">2</div>
  <div class="item">3</div>
  <div class="item">4</div>
  <div class="item">5</div>
  <div class="item">6</div>
  <div class="item">7</div>
  <div class="item">8</div>
  <div class="item">9</div>
</div>
css
.grid {
  display: grid;
  grid-template-columns: 100px 100px 100px; /* Three columns, 100px each */
  grid-template-rows: 100px 100px 100px; /* Three rows, 100px each */
  gap: 10px; /* Gap between grid items */
  background-color: #f5f5f5;
  padding: 10px;
}

.item {
  background-color: #2196f3;
  color: white;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 24px;
  font-weight: bold;
  border-radius: 4px;
}

This code creates a 3ร—3 grid where each cell is 100px ร— 100px. The 9 items will automatically fill these cells in order from left to right, top to bottom.

Using the fr Unit โ€‹

fr (short for fraction) is a new unit introduced by Grid Layout, representing a fraction of the available space. It makes the grid truly flexible.

css
.grid {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr; /* Three columns sharing space equally */
  gap: 10px;
}

This code creates three equal-width columns that divide the container's width. If the container width is 900px, after deducting two gaps (2 ร— 10px), the remaining 880px is divided into three parts, with each fr approximately equal to 293.3px.

You can use different fr values to create columns with different proportions:

css
.grid {
  display: grid;
  grid-template-columns: 2fr 1fr 1fr; /* First column is twice as wide as the others */
  gap: 10px;
}

If the container width is 900px, after deducting gaps, the remaining is 880px. There are a total of 4 parts (2 + 1 + 1), so each part is 220px. Thus, the first column is 440px, and the second and third columns are 220px each.

Mixing Different Units โ€‹

The power of Grid lies in the ability to mix different units:

css
.grid {
  display: grid;
  grid-template-columns: 200px 1fr 2fr; /* Fixed + Flexible + Flexible */
  gap: 10px;
}

In this example, the first column is always 200px. The remaining space is divided into 3 parts (1 + 2), with the second column taking 1 part and the third column taking 2 parts.

Assuming the container width is 900px:

  • First column: 200px (fixed)
  • Remaining space: 900px - 200px - 20px (gap) = 680px
  • Second column: 680px ร— (1/3) โ‰ˆ 226.7px
  • Third column: 680px ร— (2/3) โ‰ˆ 453.3px

The repeat() Function โ€‹

When you have many identical tracks, the repeat() function makes the code more concise:

css
/* Traditional way */
.grid {
  grid-template-columns: 1fr 1fr 1fr 1fr 1fr;
}

/* Using repeat() */
.grid {
  grid-template-columns: repeat(5, 1fr); /* Repeat 1fr 5 times */
}

repeat() can also repeat a pattern:

css
.grid {
  grid-template-columns: repeat(3, 100px 200px);
  /* Equivalent to: 100px 200px 100px 200px 100px 200px */
}

This creates 6 columns, repeating the 100px, 200px pattern 3 times.

Practical Application Scenarios โ€‹

Let's look at a few practical application scenarios to feel the real power of Grid Layout.

Grid is perfect for creating image galleries:

html
<div class="gallery">
  <div class="photo photo-1">Photo 1</div>
  <div class="photo photo-2">Photo 2</div>
  <div class="photo photo-3">Photo 3</div>
  <div class="photo photo-4">Photo 4</div>
  <div class="photo photo-5">Photo 5</div>
  <div class="photo photo-6">Photo 6</div>
</div>
css
.gallery {
  display: grid;
  grid-template-columns: repeat(3, 1fr); /* 3 columns */
  grid-auto-rows: 200px; /* 200px per row */
  gap: 15px;
  padding: 20px;
}

.photo {
  background-color: #ddd;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 8px;
  overflow: hidden;
}

/* Make the first photo occupy 2ร—2 space */
.photo-1 {
  grid-column: 1 / 3; /* Spans two columns */
  grid-row: 1 / 3; /* Spans two rows */
  background-color: #2196f3;
  color: white;
  font-size: 24px;
}

In this example, the first photo occupies a 2ร—2 space, becoming the focal point, while other photos occupy 1ร—1 spaces. Grid automatically adjusts the positions of other photos without manual calculation.

Card Layout โ€‹

Grid is also very suitable for creating responsive card layouts:

html
<div class="cards">
  <div class="card">
    <h3>Basic Plan</h3>
    <p class="price">$9/month</p>
    <ul>
      <li>10 Projects</li>
      <li>5GB Storage</li>
      <li>Email Support</li>
    </ul>
    <button>Choose Plan</button>
  </div>
  <div class="card">
    <h3>Pro Plan</h3>
    <p class="price">$29/month</p>
    <ul>
      <li>Unlimited Projects</li>
      <li>50GB Storage</li>
      <li>Priority Support</li>
      <li>Advanced Analytics</li>
    </ul>
    <button>Choose Plan</button>
  </div>
  <div class="card">
    <h3>Enterprise</h3>
    <p class="price">$99/month</p>
    <ul>
      <li>Unlimited Everything</li>
      <li>500GB Storage</li>
      <li>24/7 Phone Support</li>
      <li>Custom Integration</li>
    </ul>
    <button>Choose Plan</button>
  </div>
</div>
css
.cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
  /* auto-fit: automatically fit
     minmax(250px, 1fr): minimum 250px, maximum 1fr */
  gap: 20px;
  padding: 20px;
}

.card {
  background-color: white;
  border: 1px solid #ddd;
  border-radius: 8px;
  padding: 30px;
  display: flex;
  flex-direction: column;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}

.card h3 {
  margin: 0 0 10px 0;
  color: #333;
  font-size: 24px;
}

.card .price {
  font-size: 32px;
  font-weight: bold;
  color: #2196f3;
  margin: 10px 0;
}

.card ul {
  flex-grow: 1;
  padding-left: 20px;
  margin: 20px 0;
}

.card li {
  margin: 10px 0;
}

.card button {
  padding: 12px 24px;
  background-color: #2196f3;
  color: white;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  font-size: 16px;
}

The magic of this layout lies in grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)):

  • auto-fit: Automatically calculates how many columns can fit based on the container width.
  • minmax(250px, 1fr): Minimum 250px per column, maximum 1fr.

This means:

  • On wide screens, cards will arrange in multiple columns.
  • When the screen gets narrower and can't fit three columns, it automatically changes to two columns.
  • Narrower still, it becomes one column.
  • No media queries needed at all!

Magazine Style Layout โ€‹

Grid is perfect for creating complex magazine-like layouts:

html
<div class="magazine">
  <header class="header">Magazine Header</header>
  <article class="featured">Featured Article</article>
  <article class="article-1">Article 1</article>
  <article class="article-2">Article 2</article>
  <article class="article-3">Article 3</article>
  <aside class="sidebar">Sidebar</aside>
  <footer class="footer">Footer</footer>
</div>
css
.magazine {
  display: grid;
  grid-template-columns: repeat(12, 1fr); /* 12-column grid system */
  grid-auto-rows: minmax(100px, auto);
  gap: 20px;
  padding: 20px;
}

.header {
  grid-column: 1 / 13; /* Spans all 12 columns */
  background-color: #333;
  color: white;
  padding: 30px;
  text-align: center;
  font-size: 32px;
}

.featured {
  grid-column: 1 / 9; /* Occupies left 8 columns */
  grid-row: 2 / 4; /* Occupies 2 rows */
  background-color: #2196f3;
  color: white;
  padding: 30px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 24px;
}

.article-1 {
  grid-column: 9 / 13; /* Occupies right 4 columns */
  background-color: #e3f2fd;
  padding: 20px;
}

.article-2 {
  grid-column: 9 / 13;
  background-color: #e3f2fd;
  padding: 20px;
}

.article-3 {
  grid-column: 1 / 7; /* Occupies left 6 columns */
  background-color: #f5f5f5;
  padding: 20px;
}

.sidebar {
  grid-column: 7 / 13; /* Occupies right 6 columns */
  background-color: #fff3e0;
  padding: 20px;
}

.footer {
  grid-column: 1 / 13;
  background-color: #333;
  color: white;
  padding: 20px;
  text-align: center;
}

This layout uses a 12-column grid system (like Bootstrap) but is more flexible than Bootstrap. Each element can precisely specify which columns it occupies, creating complex and elegant layouts.

Grid vs Flexbox: Which One to Use? โ€‹

Many developers are confused: should I use Grid or Flexbox? The answer is to use both, as they solve different problems.

Scenarios for Flexbox โ€‹

  1. One-dimensional layout: Navigation bars, toolbars, etc., where elements only need to be arranged in one direction.
  2. Content-driven: When you want elements to arrange naturally based on content size.
  3. Small-scale layout: Small layouts inside components.
  4. Alignment control: When the main purpose is alignment and space distribution.
css
/* Scenario suitable for Flexbox */
.navbar {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

Scenarios for Grid โ€‹

  1. Two-dimensional layout: Need to control both rows and columns simultaneously.
  2. Layout-driven: When you have a clear layout structure and want elements to fill this structure.
  3. Overall page structure: Complex page layouts.
  4. Precise control: When you need precise control over element position and size.
css
/* Scenario suitable for Grid */
.page-layout {
  display: grid;
  grid-template-columns: 200px 1fr 300px;
  grid-template-rows: auto 1fr auto;
}

Combined Use โ€‹

In actual projects, the best practice is to combine both:

css
/* Use Grid for overall page */
.page {
  display: grid;
  grid-template-columns: 250px 1fr;
  grid-template-rows: auto 1fr auto;
}

/* Use Flexbox for navbar */
.navbar {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

/* Use Grid for card container */
.card-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  gap: 20px;
}

/* Use Flexbox inside each card */
.card {
  display: flex;
  flex-direction: column;
}

Browser Support โ€‹

Browser support for Grid Layout is excellent. Modern browsers all support it fully:

  • Chrome 57+ (March 2017)
  • Firefox 52+ (March 2017)
  • Safari 10.1+ (March 2017)
  • Edge 16+ (October 2017)
  • iOS Safari 10.3+ (March 2017)
  • Android Browser 67+ (June 2018)

Interestingly, all modern browsers started supporting Grid Layout almost at the same time (March 2017). This is because browser vendors reached a consensus to release support for Grid simultaneously.

For projects that need to support IE 11, IE 11 supports an older version of Grid syntax (using the -ms- prefix), but functionality is limited. For most modern projects, you can use Grid with confidence without any polyfills.

Summary โ€‹

Grid Layout is a revolutionary step forward in CSS layout, providing a native, powerful solution for two-dimensional layouts.

Core Advantages of Grid:

  1. Two-dimensional layout: Control rows and columns simultaneously to create complex layout structures.
  2. Intuitive and clear: Layout intent is clear at a glance, making code easy to understand and maintain.
  3. Precise control: Can precisely specify the position and size of each element.
  4. Flexible response: Easily achieve responsive layouts with fr units and auto-fit.
  5. Reduced nesting: No need for extra wrapper elements, making HTML structure cleaner.

Core Concepts Review:

  • Grid Container and Items: display: grid creates a container, direct children become items.
  • Grid Lines: Foundation of the grid, numbered starting from 1.
  • Grid Tracks: Space between two adjacent grid lines.
  • Grid Cells: Smallest grid space.
  • Grid Areas: Rectangular area composed of multiple grid cells.
  • fr Unit: Grid-specific flexible unit representing a fraction of available space.

Usage Recommendations:

  • Use Flexbox for simple one-dimensional layouts.
  • Use Grid for complex two-dimensional layouts.
  • Combine both in actual projects to leverage their respective strengths.
  • Use Grid to build the overall layout and Flexbox to handle component internals.

In the following chapters, we will dive deeper into various Grid container properties, Grid item properties, and how to use template areas to create semantic layouts. Mastering Grid will give you the ability to create any complex layout.