ποΈ Grid Container Properties
The grid container is your control panel. From it you define the tracks, name your layout regions, distribute leftover space, and steer how items flow. This lesson works through every container-level property β including grid-template-areas, the alignment family, and the shorthands that pack it all into one declaration.
π― Learning Objectives
By the end of this lesson, you will be able to:
- Name grid lines and build readable layouts with
grid-template-areas - Control the implicit grid using
grid-auto-rows,grid-auto-columns, andgrid-auto-flow(includingdense) - Distinguish content alignment (
justify-content/align-content) from item alignment (justify-items/align-items) - Use the
place-*shorthands and the all-in-onegridshorthand safely - Assemble a responsive dashboard whose layout is redefined at each breakpoint by name
Estimated Time: 40β50 minutes β’ Difficulty: Intermediate
Hands-on: Build a named-area dashboard that restructures itself for tablet and mobile.
In This Lesson
The Container's Job
In the last lesson you defined tracks and sized them. Everything you set there lived on the grid container β the element carrying display: grid. The container is where the layout decisions live; the items simply obey. Container properties fall into four families:
Master these and you can express almost any two-dimensional layout, then re-express it entirely for a different screen size without touching your HTML.
Named Grid Lines
Counting lines by number works, but it gets brittle. Instead, you can name lines inside square brackets right in the template. A single line can carry several names.
.container {
display: grid;
grid-template-columns:
[sidebar-start] 250px
[sidebar-end content-start] 1fr
[content-end];
grid-template-rows:
[header-start] 100px
[header-end main-start] 1fr
[main-end footer-start] 80px
[footer-end];
}
Named lines are like street names instead of "third block from the edge" β an item placed at grid-column: content-start / content-end reads like intent, not arithmetic. You'll use these names for item placement in the next lesson.
grid-template-areas: layout you can read
The most loved Grid feature is grid-template-areas. You draw an ASCII map of your layout in CSS, then attach items to regions by name. The CSS looks like the page.
.page {
display: grid;
grid-template-columns: 250px 1fr 1fr;
grid-template-rows: auto 1fr auto;
grid-template-areas:
"header header header"
"sidebar content content"
"footer footer footer";
gap: 16px;
min-height: 100vh;
}
.header { grid-area: header; }
.sidebar { grid-area: sidebar; }
.content { grid-area: content; }
.footer { grid-area: footer; }
Two rules govern the map:
- Every named area must form a rectangle β no L-shapes or disjointed pieces.
- Every row string must have the same number of cells, or the whole declaration is invalid.
Use a period (.) to leave a cell deliberately empty:
grid-template-areas:
"header header header"
"sidebar content ."
"footer footer footer";
π Free named lines
Defining an area named content automatically creates the lines content-start and content-end (on both axes). So you can position other items relative to a named area without ever declaring those line names yourself.
Gap Properties
Gaps put breathing room between tracks without touching the outer edges. The modern properties are simply gap, row-gap, and column-gap:
.container {
row-gap: 20px; /* between rows */
column-gap: 30px; /* between columns */
gap: 20px 30px; /* shorthand: row-gap column-gap */
gap: 20px; /* one value applies to both */
}
β οΈ Deprecated names
The old grid-gap, grid-row-gap, and grid-column-gap were renamed to gap, row-gap, and column-gap once these properties also began working in Flexbox. Use the short names; the grid--prefixed versions only linger for legacy support.
Gaps accept any length, including responsive units, so spacing can scale with the viewport:
.container { gap: clamp(12px, 2vw, 32px); }
The Auto Properties & Dense Packing
When items land outside your explicit grid, the browser builds implicit tracks. Three properties tell it how.
grid-auto-rows / grid-auto-columns
.container {
display: grid;
grid-template-columns: repeat(3, 1fr); /* explicit */
grid-auto-rows: minmax(100px, auto); /* implicit rows grow with content */
}
With three explicit columns, a seventh item spills onto a new implicit row sized by grid-auto-rows. Using minmax(100px, auto) keeps a comfortable minimum while letting tall content expand.
grid-auto-flow and the dense keyword
grid-auto-flow sets the direction auto-placed items fill β like the reading direction of a page:
row(default) β fill left-to-right, then wrap down, like English text.columnβ fill top-to-bottom, then move right.denseβ backfill earlier gaps with later, smaller items.
.gallery {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-auto-flow: row dense; /* backfill holes */
gap: 10px;
}
.tall { grid-row: span 2; }
.wide { grid-column: span 2; }
dense, a later small item (4) jumps back to fill the hole the wide item left. This maximizes packing but can reorder items visually.β οΈ Dense reorders visually, not in the DOM
dense can move an item earlier on screen while leaving it in place for keyboard and screen-reader order. Use it for decorative galleries, not for content where reading order matters.
Alignment Properties
Grid has two pairs of alignment properties, and mixing them up is the single most common Grid confusion. The trick: content aligns the whole grid of tracks; items aligns each item inside its cell.
| Property | Axis | Moves⦠|
|---|---|---|
justify-content | inline (β) | the track grid horizontally, when it's narrower than the container |
align-content | block (β) | the track grid vertically, when it's shorter than the container |
justify-items | inline (β) | every item within its own cell horizontally |
align-items | block (β) | every item within its own cell vertically |
/* Distribute the track grid within a larger container */
.container {
justify-content: space-between; /* start | end | center | space-around | space-evenly | stretch */
align-content: center;
place-content: center space-between; /* align-content justify-content */
}
/* Align each item inside its cell (default is stretch) */
.container {
justify-items: center;
align-items: center;
place-items: center; /* align-items justify-items */
}
π‘ Why justify-content sometimes does nothing
Content alignment only has a visible effect when the tracks don't already fill the container. If your columns are all 1fr they consume every pixel, leaving nothing to distribute β so justify-content appears inert. Give the tracks fixed sizes (or fewer of them) and it springs to life.
Individual items can override the container defaults with justify-self and align-self β covered in the next lesson on grid items.
The grid Shorthand
Two shorthands roll several properties into one. grid-template sets rows, columns, and areas together:
.page {
display: grid;
grid-template:
"header header header" auto
"sidebar content content" 1fr
"footer footer footer" auto
/ 250px 1fr 1fr; /* column sizes after the slash */
}
The full grid shorthand goes further, also folding in the auto properties. It has an auto-flow form too:
/* Auto-flow form: rows are 100px, two columns 1fr 2fr, flowing densely */
.container { grid: auto-flow dense 100px / 1fr 2fr; }
β οΈ The shorthand resets everything
Any grid sub-property you don't mention in the grid shorthand is reset to its initial value. That makes it dangerous to use for partial tweaks. For most real code, prefer explicit properties or the narrower grid-template β they're clearer and won't silently wipe a grid-auto-rows you set elsewhere.
Hands-on Exercise
ποΈ A Dashboard That Restructures by Breakpoint
Objective: Use named areas to build a dashboard, then redefine the same names at two breakpoints so the whole layout reorganizes with no HTML changes.
Requirements
- Desktop: a 250px sidebar on the left; header and footer span the full width; main content beside the sidebar.
- Tablet (β€900px): sidebar drops below the main content.
- Mobile (β€600px): every region stacks in a single column.
- Only
grid-template-areas/grid-template-columnschange between breakpoints.
π‘ Hint
Assign each element to a name once (grid-area: header etc.). Then, inside each media query, restate only grid-template-columns and grid-template-areas on the container. The items follow their names automatically.
β Solution
.dashboard {
display: grid;
gap: 16px;
min-height: 100vh;
grid-template-columns: 250px 1fr;
grid-template-areas:
"header header"
"sidebar main"
"footer footer";
}
.header { grid-area: header; }
.sidebar { grid-area: sidebar; }
.main { grid-area: main; }
.footer { grid-area: footer; }
@media (max-width: 900px) {
.dashboard {
grid-template-columns: 1fr;
grid-template-areas:
"header"
"main"
"sidebar"
"footer";
}
}
@media (max-width: 600px) {
.dashboard { gap: 10px; } /* already single column; just tighten spacing */
}
Resize the window and watch the sidebar jump from beside the content (desktop) to beneath it (tablet/mobile) β driven entirely by redefining the area map.
Best Practices & Pitfalls
β Do
- Start complex layouts with
grid-template-areasβ the CSS documents itself. - Store repeated sizes in custom properties:
grid-template-columns: var(--sidebar) 1fr; - Use
frandminmax()for flexible tracks; save fixedpxfor true rails. - Redefine areas per breakpoint instead of rewriting markup.
β οΈ Don't
- Don't write ragged area maps β every row string needs the same cell count.
- Don't confuse
*-content(moves the track grid) with*-items(moves items in cells). - Don't reach for the
gridshorthand for partial edits β it resets unmentioned properties.
Summary & Quiz
π Key Takeaways
- Named lines and
grid-template-areasmake placement read like intent instead of arithmetic. - Areas must be rectangles, and every area row must have the same cell count.
- The auto properties (
grid-auto-rows/columns/flow) govern the implicit grid;densebackfills gaps but can reorder visually. - Content alignment moves the whole track grid; item alignment moves items inside cells.
- The
gridshorthand is powerful but resets unmentioned sub-properties β prefer explicit properties.
π― Quick Quiz
Question 1: Which pair of properties centers each item inside its own cell (rather than moving the whole track grid)?
Question 2: Why might a valid grid-template-areas declaration be rejected by the browser?
Question 3: What is the main risk of using the all-in-one grid shorthand?
π Further Reading
- MDN β Basic Concepts of Grid Layout
- CSS-Tricks β Complete Guide to Grid (container properties)
- Grid by Example β worked examples
- 1-Line Layouts (Una Kravets)
π What's Next?
You can now shape a container completely. Next we switch sides and focus on the grid items β placing them by line, name, and span, and aligning each one individually with justify-self, align-self, order, and z-index.
π Container mastered!
With areas and alignment in hand, you can already build most real page shells. Let's give the items a voice of their own.