Given `grid-template-areas: "header header" "sidebar main";` on a CSS grid container, what line names does the browser create automatically, and how can an item use them?
answer
- areas quietly name their edges
- -start and -end on both axes
- grid-area: main is shorthand for four names
- the rule runs in reverse too
- full-bleed wrapper works without an areas map
basics
~20 sEvery named area generates four lines: for main, the names main-start and main-end on both the row and column axes. An item can target them directly, so grid-column: main-start / main-end works — and grid-area: main is simply shorthand for using all four.
solid answer
~40 sNaming an area in `grid-template-areas` implicitly names its bounding lines `<name>-start` and `<name>-end` on both axes. So the map above creates `header-start`/`header-end`, `sidebar-start`/`sidebar-end` and `main-start`/`main-end` as usable line names, and `grid-area: main` is just the shorthand that references all four at once. That lets an item align to part of a region — `grid-column: sidebar-start / main-end` spans both columns without repeating any numbers. The relationship runs the other way too: if you explicitly name lines `card-start` and `card-end` on both axes in your track templates, those four lines define an implicit area called `card`, and `grid-area: card` places an item in it even though no `grid-template-areas` was written. It is one naming system approached from two directions.
code
css · 15 lines.wrapper {
display: grid;
grid-template-columns:
[full-start] 1rem
[content-start] minmax(0, 60ch)
[content-end] 1rem
[full-end];
grid-template-rows: [content-start] auto [content-end];
}
/* implicit area 'content' exists purely from the line names */
.prose { grid-area: content; }
/* pierce the content column without any numbers */
.bleed { grid-column: full-start / full-end; }go deeper
Know that grid-area: name places an item in a region declared by grid-template-areas. The generated line names are beyond what is expected here.
Explain that each named area also creates <name>-start and <name>-end lines on both axes, and show an item placed with grid-column: sidebar-start / main-end rather than numbers.
Demonstrate the reverse direction: lines named with the -start/-end convention define an implicit area. Be ready to explain the full-bleed wrapper pattern in terms of the mechanism, not the snippet.
Own the naming vocabulary for a shared layout: one source of names per grid, semantic names rather than repeat-generated ones, and a rule that components place against names the container defines so redesigns stay container-local.
## Areas generate lines A named grid area is not just a label on a block of cells. Defining an area called `main` also names the four lines that bound it: `main-start` and `main-end` on the row axis, and `main-start` and `main-end` on the column axis. The same name appears on both axes, and there is no ambiguity because `grid-row` only ever resolves row lines and `grid-column` only ever resolves column lines. ```css .page { display: grid; grid-template-columns: 200px 1fr; grid-template-areas: "header header" "sidebar main"; } /* both of these place an item across the whole second row */ .a { grid-area: sidebar-start / sidebar-start / main-end / main-end; } .b { grid-column: sidebar-start / main-end; grid-row: main-start / main-end; } ``` That is why `grid-area: main` works at all: a bare `<custom-ident>` in a placement property first looks for a line named `<ident>-start` for a start edge, or `<ident>-end` for an end edge, and the area's generated lines are exactly those. `grid-area: main` sets all four longhands to `main`, and each resolves to its corresponding generated line. ## Why targeting the lines is useful Once the lines exist, an item is no longer limited to whole areas. A decorative background can run from `sidebar-start` to `main-end` while the content sits inside `main`. A modal overlay can stretch from `header-start` to `main-end` on the row axis. None of these placements involve a number, so a change to the number of tracks in the template does not invalidate them. This is the practical payoff: the container names its structure once, and items reference the structure by meaning rather than by index. It also composes with `span`. `grid-column: main-start / span 1` is legal, as is pairing a generated name with an explicit end line. ## The relationship reverses The rule works in both directions. If you explicitly name lines with the `-start` and `-end` convention when declaring tracks, those lines define an **implicit named area**: ```css .wrapper { display: grid; grid-template-columns: [full-start] 1rem [content-start] minmax(0, 60ch) [content-end] 1rem [full-end]; grid-template-rows: [content-start] auto [content-end]; } .prose { grid-area: content; } /* works: no grid-template-areas needed */ .bleed { grid-column: full-start / full-end; } ``` Here no `grid-template-areas` was written at all, yet `grid-area: content` places the item, because lines named `content-start` and `content-end` exist on both axes and together define the area. This is the mechanism behind the popular "full-bleed content column" wrapper pattern, and knowing *why* it works separates someone who copied the snippet from someone who can adapt it. ## Naming lines explicitly Line names are declared in square brackets inside the track templates, before, between or after track sizes. A line may carry several names: ```css grid-template-columns: [full-start main-start] 1fr [main-end full-end]; ``` And `repeat()` produces repeated names, which are then addressed with a name plus an index — `grid-column: col 3 / span 2` means "the third line named `col`". That indexed form is the only way to disambiguate repeated names, and it is why a name from `repeat()` is not a substitute for a semantic name. ## Precedence and collisions If a line named `main-start` is declared explicitly *and* an area called `main` exists, the explicitly named line participates in the same set of lines with that name, and a bare `main` in a start position resolves to the first such line in the grid. Deliberately mixing an explicit `-start`/`-end` naming scheme with an areas map that uses the same base name is therefore a maintenance hazard: it parses, it places something, and reasoning about which line won requires reading both declarations. Pick one source of names per grid. ## When this matters in practice Most layouts never need generated line names — `grid-area: main` is enough. They earn their keep in two situations: layout wrappers where a single content column must be pierced by full-width elements, and design-system grids where components are placed against named structural lines they did not define. In both, the container owns the vocabulary and the items speak it, which is precisely the property that makes a grid survive redesigns.
- Does `grid-column: main` work, with a single identifier and no slash?Yes. The start resolves to the first line named `main-start`, and because the omitted end value copies a custom identifier start, the end resolves to `main-end`. So `grid-column: main` spans the columns of the `main` area. The same rule is what makes `grid-area: main` set all four edges from one name.
- How do you reference a line name that `repeat()` produced several times?Pair the name with an index: `grid-column: col 3 / span 2` means the third line named `col`. A bare name always resolves to the first line carrying it, so repeated names are only usable with the index form — which is why generated names from `repeat()` do not replace semantic, one-off line names.
- What are the risks of using the same base name for both an explicit line and a grid area?They land in the same pool of names, so a bare identifier resolves to the first matching line and the winner depends on declaration order in the track template. It parses and places something, but reasoning about the result means reading two declarations at once. Keep one naming source per grid.
saying these in an interview costs you the question
- Thinks grid-area: main only works with grid-template-areas
- Says generated line names exist on one axis only
- Believes you must name lines manually to target an area's edges
- Assumes a bare name resolves to the last matching line
- Thinks repeated repeat() names can be used without an index