CSS Grid
CSS Grid
When first learning Grid layout, following online tutorials, the process usually goes like this: first get familiar with grid-template-columns, then memorize grid-column: 1 / 3, then learn grid-area, and then start using it for layouts. Many people stop there, treating Grid as a “more powerful Flexbox.”
This understanding isn’t wrong, but it’s really just scratching the surface.
The real point is: CSS Grid is not a layout tool, but a two-dimensional spatial system.
The core of Grid is not the cell, but the line
Line-based grid model
When you write this CSS:
grid-template-columns: 200px 1fr 200px;
What the browser generates internally is not three “cells,” but a set of grid lines:
line 1 | track 1 | line 2 | track 2 | line 3 | track 3 | line 4
The number of lines = the number of tracks + 1.
grid-column: 1 / 3, means placing this element in the space between line 1 and line 3. This is not typesetting; it’s coordinate positioning.
Differences in positioning models
| Model | Essence | Characteristics |
|---|---|---|
position: absolute | Pixel coordinates | Handwritten coordinates, hard to maintain |
display: flex | Flow-based ordering | Single-axis arrangement, naturally adapts to content |
display: grid | Linear coordinate system | Structured coordinates, composable |
Grid is essentially a two-dimensional absolute positioning system, but unlike absolute, its coordinates are structured, composable, and semantic.
Semantic Grid Lines
Problems with numeric notation
grid-column: 2 / 5;
- Unreadable; seeing
2 / 5gives you no idea what it refers to - Unmaintainable; changing one number when adjusting a layout can trigger a chain reaction
- Completely disconnected from design semantics
Even more troublesome: add a column on the far left, and all number-based positioning has to be recalculated.
Named Lines
CSS Grid allows naming grid lines:
grid-template-columns:
[sidebar-start] 240px
[sidebar-end content-start] 1fr
[content-end];
Then use them like this:
.sidebar {
grid-column: sidebar-start / sidebar-end;
}
.main {
grid-column: content-start / content-end;
}
Besides achieving semantic substitution, the perspective when thinking about layout also shifts, from a numeric coordinate system to a spatial semantic system. Layout is no longer “element A sits between lines 2 and 5,” but “the sidebar occupies the sidebar area, and the main content occupies the main content area,” directly matching component semantics with positional semantics.
Mainstream layout patterns
This is a common Grid structure for web applications, with centered content:
grid-template-columns:
[full-start] minmax(24px, 1fr)
[content-start] min(1200px, 100%)
[content-end] minmax(24px, 1fr)
[full-end];
On the surface, this is “centering content.” But what it actually defines is a three-layer spatial structure:
| gutter (auto) | content (bounded) | gutter (auto) |
Three spatial regions, each with clear semantics and constraints:
- Left and right gutters:
minmax(24px, 1fr)ensure a minimum 24px safe margin while expanding automatically with the screen - Content area:
min(1200px, 100%)ensures a maximum width of 1200px, automatically filling the screen on smaller viewports
There’s a shift in thinking here, from “how to center content” to “how to place different types of things in their positions.”
Container-first
The old mental habit is to write the item first
.sidebar { width: 240px; }
.main { margin-left: 240px; }
The problem with this approach is that every component has to know the layout exists; they must know where to move and how much space to leave. This tight coupling is the source of many layout problems.
In Grid best practices, you should plan the container first
.layout {
display: grid;
grid-template-columns: 240px 1fr;
}
Components only need to declare which column they belong to, without knowing any layout details:
.sidebar { grid-column: 1; }
.main { grid-column: 2; }
The essential shift is: from “components determine layout” to “layout determines components”. The parent container defines spatial rules, and child elements only need to choose which space they belong to.
Subgrid
Flexbox has a limitation: each Flex container is an independent layout system, and within each Flex component, you need to provide additional positioning measures.
This causes nested Flex layouts to be naturally misaligned; a child element is left-aligned within its own container, while a sibling container’s child might be in a completely different position. This misalignment requires numerous hacks to resolve: extra wrappers, negative margins, calc calculations…
Subgrid allows child layouts to inherit the parent Grid’s track structure:
.card {
display: grid;
grid-template-columns: subgrid;
}
The entire application can share:
- a unified column system
- unified alignment rules
- a unified spacing system
Take Notion and Linear as examples
The core of their layout structure is not “a bunch of components,” but a globally unified spatial system. Every card, every modal, every sidebar operates within the same coordinate system. Choosing the right layout architecture achieves twice the result with half the effort; using absolute positioning or flex to implement similar layouts would require considerably more work.
CSS Grid Lanes: the first choice for masonry layouts
Safari Technology Preview 234 introduced CSS Grid Lanes.
Use display: grid-lanes to create a masonry layout:
.container {
display: grid-lanes;
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
gap: 16px;
}
Defining columns creates a “waterfall” layout; defining rows creates a “brick” layout.
The flow-tolerance property.
Grid Lanes introduces a new property flow-tolerance, which controls how eagerly elements move between tracks:
.container {
flow-tolerance: 2em;
}
Default value 1em. This property addresses the question: should an element jump to a shorter track, or stay in its current position? This trade-off directly affects the compactness of the final layout.
Suitable scenarios
Grid Lanes is especially suited for:
- Photo galleries
- Newspaper-style article grids
- E-commerce product listings
- mega menu
These layouts used to require JavaScript libraries; now pure CSS can handle them.
Layout thinking
| Level | Essence | Mental model |
|---|---|---|
| Component | Content | UI = component tree |
| Flex | Arrangement | UI = flow-based composition |
| Grid | Space | UI = spatial coordinates |
| System | Rules | UI = physical laws |
When thinking with Flex, you’re asking “how should elements be arranged.”
When thinking with Grid, you’re asking “how should space be distributed.”
When thinking with Subgrid + Grid Lanes, you’re asking “what are the spatial rules for the entire interface.”
When CSS Grid first became widespread, most tutorials introduced it as a “two-dimensional version of Flexbox.” This analogy is helpful, but it can also keep people at the surface.
When you truly grasp Grid’s line-based model, you’ll realize it solves not “how to arrange elements” but “how to define spatial rules.” Many layout problems that once required hacks become natural once you accept this shift.
Subgrid and Grid Lanes extend this thinking further: from a single-layer spatial system, to a multi-level nested unified spatial system, to a dynamic spatial system supporting masonry layouts. CSS is becoming a truly powerful layout language, and Grid is the core of this entire evolution.