Using CSS Flexbox, how do you center a single child both horizontally and vertically inside its parent, and what does the parent need for the vertical centering to be visible?
answer
- everything goes on the parent
- two axes, two properties
- the container needs real height
- margin: auto splits free space
- place-content only half works
basics
~20 sSet display: flex, justify-content: center and align-items: center on the parent, and give that parent a height, such as min-height: 100vh. Without a height the parent shrink-wraps its child, so there is no vertical free space to center in.
solid answer
~40 sThree declarations on the **parent** do it: `display: flex`, `justify-content: center` (main axis) and `align-items: center` (cross axis). In the default `flex-direction: row` that centers horizontally and vertically respectively; if I switch to `column` the two properties swap roles, so I think of it as "center on both axes" rather than "one for left-right, one for up-down". The part people forget is that the parent is only as tall as its content by default, so `align-items: center` appears to do nothing — I give the parent real height, typically `min-height: 100vh` for a full-page splash or a fixed height for a card. A one-declaration alternative is `margin: auto` on the child, because auto margins in flex absorb free space on both axes.
code
css · 10 lines.hero {
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
}
.hero__card {
max-width: 32rem;
}go deeper
Be able to write the three declarations from memory on the parent and say which axis each one controls. Mention that the parent needs a height, for example min-height: 100vh, for the vertical centering to show.
Explain centering in terms of main and cross axis so the answer survives flex-direction: column, and describe where the free space comes from. Knowing the margin: auto alternative and why it behaves the same for a single child is expected.
Show judgment about which container actually owns the height in a real page, and be ready to say why place-content and place-items only half-work in flex. Interviewers listen for whether you debug centering by asking where the free space is.
Own the convention: whether centering lives in a reusable utility, a layout primitive component, or ad-hoc rules, and what that costs in stylesheet size and consistency. Be able to argue when grid's place-items is the better default for the codebase.
## What "centering" means to a flex container A flex container lays its children out along a **main axis**, chosen by `flex-direction`. The default is `row`, so in a left-to-right writing mode the main axis runs horizontally. The perpendicular axis is the **cross axis**. Two properties do the positioning: `justify-content` distributes items along the main axis, and `align-items` positions them on the cross axis. That is why the recipe is worth memorising as *axes*, not as *directions*. In a row container `justify-content: center` is horizontal and `align-items: center` is vertical; add `flex-direction: column` and the two silently trade places. Candidates who memorised "justify is horizontal" get caught the moment the container becomes a column. ## The canonical recipe ```css .parent { display: flex; justify-content: center; align-items: center; min-height: 100vh; } ``` All four declarations sit on the parent. Nothing at all goes on the child — a frequent mistake is putting `justify-content` on the element you want centered, where it does nothing unless that element is itself a flex container. ## Why the height is the real answer A block-level box is as tall as its content unless you say otherwise. If `.parent` is a plain `div` wrapping one paragraph, its height *is* the paragraph's height, so after `align-items: center` there is zero leftover cross-axis space and the paragraph looks unchanged. Centering only becomes visible when the container is taller than the item. So the vertical half of the recipe is really "give the container a height": `min-height: 100vh` for a viewport-filling section, a fixed `height` for a fixed-size card, or an inherited height when the parent is itself a stretched flex or grid item. Interviewers ask this precisely because it separates people who copied a snippet from people who understand where the free space comes from. ## The auto-margin alternative ```css .parent { display: flex; min-height: 100vh; } .child { margin: auto; } ``` In a flex container an `auto` margin absorbs free space in the direction it points. With all four margins `auto`, the leftover space is split equally above/below and left/right, centering the child on both axes with a single declaration on the child. For a lone child this is equivalent to the three-property version. The behaviours differ once there are several items: auto margins take their share of the free space *before* `justify-content` gets to distribute what remains, which is exactly the property exploited by nav-bar layouts. ## Two shorthands that only half-work here Both `place-content` and `place-items` look like one-line centering, and in a grid container `place-items: center` genuinely is. In a flex container each of them only does half the job: - `place-content` is shorthand for `align-content` + `justify-content`. `align-content` applies only to **multi-line** flex containers, and the default is `flex-wrap: nowrap`, so with one line it is ignored — `place-content: center` centers horizontally only. - `place-items` is shorthand for `align-items` + `justify-items`, and flex containers ignore `justify-items` entirely, so `place-items: center` centers vertically only (in a row). Knowing why each falls short is a much stronger answer than reciting the three-property recipe. ## Things that are not box centering `text-align: center` centers *inline content* inside a block; it does not move the block itself. `line-height` equal to the container height only ever centers a single line of text and breaks on wrap. `vertical-align` applies to inline-level and table-cell boxes, not to flex items. These are the pre-flexbox workarounds, and reaching for them today reads as out-of-date. ## Practical variations If the child should also be centered but capped in width, keep the flex recipe and give the child `max-width` — the container centers whatever width the child settles at. If several children should be centered as a group, the same recipe works, and `gap` spaces them. If you want the child centered horizontally but pinned to the top, use `align-items: flex-start` and keep `justify-content: center`; the two axes are always controlled independently, which is the whole point of the model.
- If I change the container to flex-direction: column, do I have to change anything?No — the same two declarations still center on both axes, but their roles swap: `justify-content: center` now controls vertical placement and `align-items: center` horizontal. That is why it is safer to say "main axis and cross axis" than "horizontal and vertical" when describing the recipe.
- Why does align-items: center sometimes make a child visibly shrink?Because the default is `align-items: stretch`, which makes the child fill the container's cross size. Switching to `center` removes that stretch, so the child falls back to its content-based size. If you want it centered but still full-width in a column container, keep `align-self: stretch` on the child or set an explicit width.
- How would you center an element both ways without Flexbox?Grid is the shortest: `display: grid; place-items: center` on the parent — in grid, unlike flex, `justify-items` is honoured so the shorthand really does both axes. The older technique is `position: absolute; inset-block-start: 50%; inset-inline-start: 50%; transform: translate(-50%, -50%)`, which still works but takes the element out of flow.
saying these in an interview costs you the question
- Putting justify-content on the child instead of the container
- Claiming place-content: center centers a nowrap flex row vertically
- Forgetting the container needs a height for vertical centering
- Using text-align: center to move a block-level box
- Saying justify-content is always the horizontal one