skip to content

Grid items fill their cell by default. What is the initial value of align-items on a grid container, and what stops an individual item from stretching?

level: middleimportance: should knowfreq 55%

answer

  1. the computed value is not stretch
  2. auto size is a precondition
  3. auto margins outrank alignment
  4. aspect-ratio boxes get start instead
  5. equal-height cards come from this

basics

~20 s

The initial value is normal, which for grid items behaves as stretch. Stretching only happens when the item's size in that axis is auto and neither margin in that axis is auto, so a set height, an auto margin, or any align-self value other than stretch cancels it.

solid answer

~40 s

The initial value of `align-items` (and `justify-items`) is `normal`, not `stretch` — but for a grid item `normal` *behaves* as stretch, which is why an empty `<div>` fills its cell in both directions without any sizing. Stretch has preconditions: the item's used size in that axis must be `auto`, and neither margin in that axis may be `auto`. So giving the item a `height`, a `width`, an `auto` margin, or any positional `align-self`/`justify-self` value such as `center` or `start` cancels stretching, and the item falls back to its content size and is positioned in the area. One spec carve-out matters in practice: for boxes with an intrinsic aspect ratio, such as an `<img>`, `normal` behaves as `start` rather than stretch, so images do not get distorted by their grid cell.

code

css · 10 lines
css
.grid {
  display: grid;
  grid-template-columns: 200px;
  grid-auto-rows: 300px;
  /* align-items is 'normal', which behaves as stretch here */
}

.grid .fills { background: #ccc; }          /* 200x300: stretches */
.grid .short { height: 120px; }             /* 120px tall, at the top */
.grid .pushed { margin-block-start: auto; } /* auto margin cancels stretch */

go deeper

for a junior

Know that grid items fill their cell by default and that giving an item a width or height stops that. Be able to say the default keyword is normal, behaving as stretch.

for a middle

Explain the two preconditions — auto size and no auto margin — and where a non-stretching item lands. Mention the intrinsic-aspect-ratio carve-out for images.

for a senior

Use it diagnostically: when equal-height cards break in one grid, walk the list of things that cancel stretch and name the likely culprit in a component stylesheet.

for a principal

Decide the house rule — components should not hard-code heights that fight their layout container, and the design system's card primitives should stretch by default and opt out explicitly.

## normal is not literally stretch The initial value of `align-items`, `justify-items`, `align-self`, and `justify-self` is the keyword `normal`. `normal` is context-sensitive: its meaning depends on the layout mode of the box it applies to. Inside a **grid** container, `normal` behaves as `stretch` for a typical grid item — the item's margin box grows to fill its grid area in that axis. That is why the following renders as a visible 200×100 block even though the item has no dimensions of its own: ```css .grid { display: grid; grid-template-columns: 200px; grid-auto-rows: 100px; } .grid > div { background: rebeccapurple; } /* fills the whole cell */ ``` Interviewers like the distinction because `getComputedStyle` will report `normal`, not `stretch`, and candidates who memorised "the default is stretch" cannot explain that. ## The preconditions for stretching Stretch is not unconditional. In a given axis, a grid item only stretches when **both** of these hold: 1. Its used size in that axis is `auto` — you have not set a `width`/`height` (or a logical `inline-size`/`block-size`) that resolves to something definite. 2. Neither margin in that axis is `auto` — auto margins absorb the free space first, leaving nothing for stretching. Break either precondition and the item is sized to its content (its fit-content size) and then aligned in the area using the effective alignment value. ```css .card { height: 120px; /* precondition 1 broken: no block-axis stretch */ } ``` A row 300px tall now holds a 120px card sitting at the **block-start** edge — not centered, not bottom. This surprises people who expect "stretch didn't apply, so it must center"; the fallback position for a non-stretched item under `normal` is the start edge. ## Replaced elements and aspect-ratio boxes The Box Alignment specification carves out boxes with an intrinsic aspect ratio or intrinsic size: for them, `normal` behaves as `start`, not `stretch`. This is what stops an `<img>` from being smeared to the shape of its grid cell. If you actually want the image to fill the cell, you opt in explicitly and control the ratio yourself: ```css .grid img { align-self: stretch; justify-self: stretch; width: 100%; height: 100%; object-fit: cover; /* crop rather than distort */ } ``` ## Why this matters for equal-height cards Stretch is the mechanism behind grid's most-used property: sibling cards in a row are the same height for free, because each one stretches to the row's height, and the row is as tall as its tallest content. The moment a designer asks for "cards aligned to the top, not stretched", the fix is `align-items: start` on the container — and the moment someone adds `height: auto` plus a fixed `height` on the card component, the equal-height behaviour silently disappears. When a card in a grid stops matching its neighbours, checking for a stray `height` or an `align-self` in the component's own stylesheet is the first move. ## Interaction with align-self `align-items` on the container sets the initial value of `align-self` for every item; `align-self` on an item wins. So `align-self: center` opts one card out of stretching, and `align-self: stretch` opts one back in when the container said `start`. There is no way to "partially" stretch — stretch either applies fully in that axis or does not apply at all. ## Stretch on the content properties is a different thing Do not confuse item stretching with `align-content: stretch` (also the behaviour of `normal` for content alignment). That one distributes the container's leftover space into **auto-sized tracks**, making the tracks themselves taller. Tracks with a fixed length or an `fr` size do not participate, because they already have a definite size or already consumed the free space. So in a tall container with `grid-template-rows: auto auto`, the rows grow; with `grid-template-rows: 100px 100px`, they do not, and the free space stays at the end. ## Debug checklist When an item is not stretching and you expected it to: look for a `width`/`height` on the item, an `auto` margin, an `align-self`/`justify-self` override, an `align-items`/`justify-items` value on the container other than `normal`/`stretch`, or an intrinsic-aspect-ratio element such as `<img>`, `<video>`, or `<canvas>` hitting the spec's `start` carve-out.

  • If an item cannot stretch because it has a fixed height, where does it sit in the row?
    At the block-start edge of its grid area. When `normal` cannot resolve to stretch, the fallback position is `start`, not `center` — so a 120px item in a 300px row sits flush with the top, with the leftover 180px below it. Use `align-self: center` or `end` if you want it elsewhere.
  • Why doesn't an <img> stretch to fill its grid cell like a <div> does?
    Because the Box Alignment spec says `normal` behaves as `start`, not `stretch`, for boxes with an intrinsic aspect ratio or intrinsic size. That protects images from being distorted by their cell. To make one fill the cell, set `align-self: stretch` and `justify-self: stretch` (or `width: 100%; height: 100%`) plus `object-fit: cover` so it crops instead of squashing.
  • How do you turn off stretching for the whole grid but keep it for one item?
    Set `align-items: start` on the container — that becomes the initial `align-self` for every item — then set `align-self: stretch` on the one item that should still fill its row. Item-level self alignment always wins over the container's items-level default.

saying these in an interview costs you the question

  • Says the computed initial value of align-items is stretch
  • Expects a non-stretching item to center in its area
  • Thinks stretch still applies when the item has a fixed height
  • Confuses item stretch with align-content: stretch on tracks
  • Assumes images stretch to fill their grid cell

context