The fastest way to center one box inside another, both horizontally and vertically, is two lines of grid:
.parent {
display: grid;
place-items: center;
}That centers any direct child on both axes, with no fixed widths, no negative margins, no math. It is Baseline (supported in every current browser since 2020), so you can ship it today without prefixes or fallbacks. The rest of this page is the full menu: the flexbox version everyone reaches for, when margin: auto is the right tool, the absolute-position method for overlays, and the difference between centering text and centering a box. Pick the one that matches your situation, because "center a div" has about five correct answers depending on what you are centering and into what.
The grid one-liner: place-items: center
place-items is shorthand for align-items (the block/cross axis) plus justify-items (the inline axis). Setting it to center on a grid container centers every direct child in both directions:
.hero {
display: grid;
place-items: center;
min-height: 100vh;
}<div class="hero">
<div class="card">Perfectly centered</div>
</div>This is my default for "one thing in the middle of a region" because it does not care about the child's size, it works when the child wraps to multiple lines, and there is nothing to keep in sync. The one thing to know: place-items aligns items inside their grid area, so if you have multiple children they all stack into the same cell and center individually. For one centered element it is the cleanest option there is.
Flexbox: justify-content + align-items
The flexbox version is the one most people already know. On a row-direction flex container, justify-content aligns along the main (horizontal) axis and align-items aligns along the cross (vertical) axis:
.parent {
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
}That is the workhorse. It does the same job as the grid one-liner and is worth reaching for when the surrounding layout is already flex, or when you want the centered items laid out in a row or column with gap between them:
.toolbar {
display: flex;
justify-content: center;
align-items: center;
gap: 1rem;
}gap in flexbox is Baseline now, so you no longer need margins between flex children. The axis mapping is the part that trips people up: if you switch to flex-direction: column, the axes swap, justify-content now controls vertical and align-items controls horizontal. The full breakdown of axes, flex-grow, and wrapping lives in my practical guide to flexbox; this page is just the centering slice.
Centering a single item with margin: auto
Inside a flex (or grid) container, margin: auto on a child absorbs all the free space around it on both axes, which centers that one item without touching the parent's alignment properties:
.parent {
display: flex;
}
.child {
margin: auto;
}This is genuinely useful when you want to center one item while siblings stay put, or push one item to an edge. margin-left: auto on a single flex child shoves it to the right and pulls everything else left, which is the idiomatic "logo on the left, menu on the right" navbar pattern, no spacer div required.
For block-level boxes outside flex or grid, the classic margin: 0 auto still centers horizontally, but only if the element has a width less than its container:
.container {
max-width: 60rem;
margin: 0 auto;
}margin: 0 auto does nothing vertically on a normal block element (auto top/bottom margins resolve to zero in normal flow). That is the reason "center vertically" needs flexbox, grid, or the transform method below, not just margins.
Absolute positioning with transform
When the centered element is taken out of flow, an overlay, a modal, a tooltip, a badge pinned to a card, the classic technique is to offset by 50% then pull back by half the element's own size with transform:
.overlay {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}The top/left of 50% positions the element's top-left corner at the center of the positioned ancestor; the translate(-50%, -50%) then shifts it back by half its own width and height, landing the element's center on the center. It works without knowing the element's dimensions, which is why it survived as the go-to for so long.
Two caveats. The parent needs position: relative (or any non-static position) or the element will center against the viewport instead. And translating by a non-integer pixel can land the box on a half-pixel and render text slightly blurry; if you see fuzzy edges, nudge with transform: translate(-50%, -50%) translateZ(0) or prefer the grid/flex method, which snaps to the pixel grid. For an overlay that genuinely needs to escape flow this is still the right tool; for in-flow content, grid or flex is cleaner.
Centering text vs centering a box
These are different problems and need different properties. To center the text inside an element, use text-align:
.headline {
text-align: center;
}text-align: center centers inline content (text, inline images, inline-block buttons) inside the box. It does nothing to the box itself. For a single line of text that also needs vertical centering inside a fixed-height element, line-height equal to the height is the old trick:
.badge {
height: 3rem;
line-height: 3rem;
text-align: center;
}That only works for a single line; the moment text wraps, line-height breaks. For multi-line text centered vertically, go back to flexbox or grid on the container. The rule of thumb: text-align and line-height center content within a box, while flex, grid, margin, and transform center the box within its parent.
Which method to reach for
/* One item centered both ways, you control the parent: grid */
.parent { display: grid; place-items: center; }
/* Same, but the layout is already flex or you want gap between items */
.parent { display: flex; justify-content: center; align-items: center; }
/* Center one child, leave siblings alone, or push one to an edge */
.child { margin: auto; } /* or margin-left: auto to push right */
/* Horizontal-only, a fixed-width block in normal flow */
.container { max-width: 60rem; margin: 0 auto; }
/* The element is out of flow (overlay, modal, pinned badge) */
.overlay { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); }
/* Center the text inside an element, not the element */
.text { text-align: center; }If you are sizing the centered region with mixed units (a header offset, viewport math), CSS calc() with min(), max(), and clamp() pairs naturally with any of these for fluid layout. And once you are comfortable centering, the :has() parent selector opens up conditional centering, for example styling a container differently when it contains a centered media element.
FAQ
See also
- A practical guide to flexbox: the axes model, justify-content vs align-items, flex-grow, gap, and wrapping in full.
- CSS calc() with min(), max(), and clamp(): mixing units for fluid sizing of the regions you center into.
- The CSS :has() parent selector: style a container based on what it contains, including conditional centering.
Sources
Authoritative references this article was fact-checked against.
- place-items (MDN Web Docs)developer.mozilla.org
- justify-content (MDN Web Docs)developer.mozilla.org
- align-items (MDN Web Docs)developer.mozilla.org
- Aligning items in a flex container (MDN Web Docs)developer.mozilla.org





