A flex container fills its available height when its own height is set (for example to 100vh, 100% of a sized ancestor, or a fixed value) and when its children are told to stretch along the cross axis. In a row-oriented flex container, the cross axis is vertical, so the default value align-items: stretch makes every flex item grow to the tallest item's height, which itself matches the container's content box when no item has a fixed height. The piece most often missed is the container height: stretch has nothing to stretch into when the container itself only takes the height of its content. Treating "fill height" as two separate decisions (container height plus child stretch) is the cleanest way to reason about every layout you build with flexbox.

how to make flexbox fill height
how to make flexbox fill height

Why "Fill Height" Has Two Separate Decisions

The phrase "make flexbox fill height" hides two distinct steps that developers tend to fuse together. First, the container needs an actual height to fill. Second, the items inside need permission to stretch along the cross axis. Setting display: flex alone produces a flex layout but no automatic full-height behavior; the container is still only as tall as its content unless you (or a sized ancestor) define a height. Browsers do not propagate height through percentage units by default, so height: 100% on the container only works when every ancestor up to a sized root has a height of its own.

To make the container fill the viewport, give it an explicit height such as height: 100vh or height: 100% (the latter only works if every ancestor up to the root has a height). For a sidebar that should match a main column's height, give the parent a height and let flexbox distribute the children; with align-items: stretch left at its default in a row container, each child stretches to the line height. For the items themselves, the cross-axis property align-items is the switch. Its default stretch causes items to fill the cross axis. flex-start, flex-end, and center collapse the items to their content height and pin them to one end or the middle. baseline aligns items by text baseline rather than height. Choose stretch when you want children to share the line height, and choose one of the others only when collapsed sizing is intentional.

The Five Controls That Decide Cross-Axis Sizing

Cross-axis sizing only behaves the way you expect when the other four core Flexbox properties are coherent with it. The Flexbox Generator exposes exactly those five controls, validated against a closed list, so the preview and the copied CSS cannot disagree silently.

Property Supported values Effect on cross-axis fill
flex-direction row, row-reverse, column, column-reverse Row keeps the cross axis vertical; column rotates it horizontal, so stretch then fills width
flex-wrap nowrap, wrap, wrap-reverse Wrapped lines form independent cross-axis bands, each stretched to the container's cross size
justify-content flex-start, flex-end, center, space-between, space-around, space-evenly Operates on the main axis; for a row it controls horizontal distribution, not height
align-items stretch (default), flex-start, flex-end, center, baseline The single switch that turns cross-axis fill on or off for items inside one line
gap 0 to 100, whole pixels only Adds spacing between items and between wrap lines; does not change stretch behavior

Two patterns matter most for fill-height work. First, in a row container the default align-items: stretch plus a defined container height gives every child a full-height line. Second, switching to flex-direction: column keeps stretch active but moves it onto the horizontal axis, so children fill width instead of height. This rotation is the most common reason a layout that "worked yesterday" suddenly stops filling the expected dimension after a direction change.

Configure a Fill-Height Flex Container

  1. Pick the flex direction that matches your layout. For a horizontal row of full-height columns, leave it on row. For a vertical stack that fills width, switch to column and remember align-items: stretch then affects width, not height.
  2. Choose the wrapping mode. nowrap keeps every item on one cross-axis band and is the safest pick when you want a fixed-height sidebar or hero. wrap forms new lines that each stretch to the container's cross size; wrap-reverse does the same but stacks the bands from the cross-axis end.
  3. Select the main-axis distribution (justify-content). For a row this controls horizontal spacing; for a column it controls vertical spacing. None of the six options change cross-axis stretch behavior, so this step is independent of fill height.
  4. Pick the cross-axis item alignment (align-items). To make items fill the container height in a row, leave stretch selected. Pick center, flex-start, flex-end, or baseline only when you intentionally want collapsed items.
  5. Type a whole-pixel gap from 0 to 100 in the gap field. The parser accepts only base-10 whole numbers, so 8 works and 8.5, 8px, 08, and any value above 100 are rejected before they can affect the preview or the output.
  6. Inspect the five fixed preview items. The preview only updates when every field is valid, and the styles applied to those items come from the same validated settings that the output block will use.
  7. Generate the .container rule. The generator emits exactly six declarations in a fixed order: display: flex, then flex-direction, flex-wrap, justify-content, align-items, and gap. There are no vendor prefixes, child rules, or media queries.
  8. Copy the generated CSS with the copy button, or select the visible code manually if the clipboard step fails. A failed copy still leaves the complete CSS on screen for manual selection, so you never lose the output.

If you change any select or the gap after generating, the previous output, any validation message, and the copy confirmation are cleared immediately. Generating again revalidates the full state before the new block appears, so invalid values never reach the inline style or the copied text.

Apply the Generated CSS to Common Fill-Height Layouts

Drop the generated .container rule into your stylesheet, then add your container height and your child rules next to it. A full-viewport hero pairs height: 100vh on the container with the default align-items: stretch active. Every preview child then matches the viewport height. A two-column layout uses a parent with a fixed or 100vh height, a row-direction container, and the generator's default align-items: stretch. The taller column sets the line height and the shorter column matches it automatically without any explicit height on the children. A vertical navigation uses flex-direction: column, align-items: stretch, and justify-content: flex-start. In that case stretch fills the items' width, not their height, so item height comes from each item's own content or a child rule you write yourself.

Because the generator emits only the container block, you supply container height, child widths, breakpoints, and accessibility concerns in your own reviewed stylesheet. The copied CSS is a safe starting point, not a finished responsive layout, which is why the same generated block lands cleanly in all three of those layouts with only the container height changing between them.

Why a Closed, Validated Generator Beats Ad-Hoc Editing

The generator refuses arbitrary property names, selectors, unit text, and CSS punctuation, so the output block cannot contain stray fragments or injected declarations. Every keyword list (direction, wrap, distribution, alignment) is a closed subset of the W3C Flexbox and Box Alignment specifications, and each value is validated against that list a second time before it is serialized. The gap parser is a strict base-10 whole-number grammar; negative values, decimals, leading-zero forms like 08, scientific notation, and unit suffixes are rejected rather than silently coerced. Raw gap text beyond 32 UTF-16 code units fails without truncation, and values above 100 are reported rather than reduced to the maximum. The preview and the copied block draw from the same validated settings, so the two representations cannot diverge.

All of this runs locally in the active browser tab. No setting, generated CSS, or copied confirmation is uploaded. The tool creates no file, no Blob URL, no remote stylesheet, no embedded frame, and no dynamically executed CSS string, which means you can paste the output into a stylesheet without auditing it for hidden behavior. A generation identity is attached to each clipboard job, so older asynchronous completions are invalidated when you edit, regenerate, copy again, or unmount the component.

Test the Result With Real Content and Viewports

The preview uses five fixed local items and cannot know your container's actual dimensions, your content's natural size, the user's writing mode, or the zoom level. Before you ship, paste the generated .container rule into your own stylesheet, add the container's height (for example min-height: 100vh on the body and height: 100% on the wrapper), and test with realistic child content at the viewport sizes you actually target. The same rule that fills the hero on a desktop may wrap unexpectedly on a narrow phone because items have a natural minimum width; pair the container block with a media query or with a deliberate flex-wrap choice in the generator before you call it done. A short loop of generate, paste, resize, repeat is faster than guessing values blind, and it surfaces fill issues that a static preview cannot reproduce.