A CSS grid is defined by declaring explicit tracks on its container. \(grid-template-columns: 200px 1fr 200px\) sets up two fixed sides and a flexible middle; \(grid-template-rows: 100px 1fr auto\) does the same vertically. Tracks may use keyword \(auto\) (sized by largest content), fixed lengths, the flexible \(fr\) unit, or be calculated with \(minmax(100px, 1fr)\) and \(fit-content(200px)\). The \(repeat()\) function reduces repetition: \(repeat(3, 1fr)\) produces three equal columns. Named lines inside \(repeat()\) work too — \(repeat(3, [col-start] 1fr [col-end])\) — letting items be placed by name.
Beyond raw track sizes, Grid offers three higher-level placement tools. \(grid-template-areas\) lets you paint the layout as ASCII art using names; \(grid-area\) then assigns a child to a named region (\(grid-area: header\)) or by numeric lines (\(grid-area: 1 / 1 / 2 / 4\) meaning row-start / column-start / row-end / column-end). Implicit named areas automatically generate four line names per region, which can be referenced with the explicit-line syntax. The full shorthand \(grid\) resets all sub-properties and combines template, auto-flow, and auto-rows/columns; \(grid-template\) is narrower and covers only rows, columns, and areas.
When items spill outside the explicit grid, an implicit grid is created and its tracks are sized by \(grid-auto-rows\) and \(grid-auto-columns\). \(grid-auto-flow\) controls whether items fill row by row (default) or column by column, and the \(dense\) keyword backfills holes when items have varying spans — at the cost of reordering visually. Spanning is performed with the keyword \(span\) or explicit lines: \(grid-column: span 2\) reaches across two columns, \(grid-column: 1 / 3\) reaches from line 1 to line 3, and \(grid-column: 1 / -1\) spans every column because negative line numbers count from the end (-1 is the last line). A modern addition, \(grid-template-columns: subgrid\), lets a nested grid inherit track sizes and named lines from its parent.