Centering a div is one of the oldest punchlines in web development. For years it was genuinely hard — floats and table hacks and more magic numbers than anyone wants to remember. Today you have several clean, dependable methods. The trick is knowing which one to reach for, because they each have a different mental model and a different set of trade-offs.
This guide covers every technique worth knowing, from the modern defaults to the legacy approaches you will still encounter in real codebases. All examples use plain CSS. Tailwind utility equivalents are noted where they add clarity.
Flexbox — the right default for most situations
Flexbox was built for aligning items along an axis, which makes centering a natural fit. A container needs three declarations: turn on flex, center along the main axis, center along the cross axis.
.parent {
display: flex;
justify-content: center; /* horizontal */
align-items: center; /* vertical */
}
That is it. The child needs nothing special. The parent does not need a fixed height — if you give it min-height: 100vh it will center its child within the full viewport. If you give it height: 400px it centers within that box.
.hero {
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
}
In Tailwind: flex items-center justify-center.
Centering one child vs. multiple children
When there is one child, justify-content: center horizontally centers it. When there are multiple children, it distributes them all centered as a group along the main axis. If you want one item centered but others aligned differently, reach for margin: auto on the individual child instead of adjusting the parent:
.nav {
display: flex;
align-items: center;
}
.nav .logo {
margin-right: auto; /* pushes everything else to the right */
}
Auto margins in a flex container consume available space, which gives you surgical control without changing the parent's alignment strategy.
CSS Grid — the two-liner
Grid ships a shorthand, place-items, that sets both align-items and justify-items in one declaration. For centering a single child it is the most concise option in CSS:
.parent {
display: grid;
place-items: center;
}
Two properties. Done. This works because place-items: center is shorthand for align-items: center; justify-items: center. The child stays centered regardless of its size.
For centering content that also needs to span a defined column structure, grid is even more at home. But for a plain "put one thing in the middle" layout, the two lines above are hard to beat.
In Tailwind: grid place-items-center.
place-content vs. place-items
place-items aligns items within their grid areas. place-content aligns the entire grid track bundle within the container. For centering a single element, they produce the same result. When you have multiple grid children, the distinction matters — place-content: center packs all the tracks together in the middle of the container, while place-items: center centers each item within its own grid cell.
Absolute positioning with transform
This is the classic pre-flexbox technique and still the right tool when the child needs to be positioned independently of document flow — modal dialogs, floating badges, overlays.
.parent {
position: relative;
}
.child {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
How it works: top: 50% and left: 50% position the child's top-left corner at the center of the parent. transform: translate(-50%, -50%) then shifts the child back by half of its own width and height, so its own center lands on the parent's center. This works regardless of the child's dimensions, even if you do not know them at write time.
The parent must have a positioning context — position: relative, absolute, fixed, or sticky — otherwise the child positions relative to the nearest positioned ancestor (or the viewport).
The inset shorthand
Modern CSS lets you write the four directional properties as one. Combined with margin: auto, it gives you a clean alternative when you know the child's dimensions or when the child should fill a defined area:
.child {
position: absolute;
inset: 0; /* top: 0; right: 0; bottom: 0; left: 0 */
margin: auto;
width: 300px; /* child needs explicit dimensions */
height: 200px;
}
Setting all four inset values to zero creates equal pull from every edge; margin: auto resolves that tension by splitting available space evenly. This is especially readable when you want a centered overlay that also has an explicit size.
Margin auto — horizontal centering of block elements
This is still the correct answer when you want to center a block-level element horizontally within its container and you do not need vertical centering. It has been reliable since CSS 2.1.
.card {
max-width: 680px;
margin-left: auto;
margin-right: auto;
}
/* shorthand */
.card {
max-width: 680px;
margin: 0 auto;
}
The element must be a block (or have display: block) and must have an explicit or constrained width — either a fixed width or a max-width that is narrower than the container. Without a width constraint, the block stretches to fill its container and there is no space for auto margins to divide.
This technique does not center vertically. For a simple article layout — text column centered on a wide screen — it is often all you need and is semantically clear at a glance.
Centering text and inline content
Worth distinguishing from box centering: text-align: center centers inline content (text, inline images, inline-block elements) within their containing block. It does not move the box itself.
.banner {
text-align: center; /* centers the text inside .banner */
}
If you apply text-align: center to a <div>, the div stays left-aligned but its text content centers. If you want the div itself centered, use margin auto or flex/grid on the parent.
Viewport centering — putting something in the middle of the screen
A common pattern: a modal, a splash card, a full-screen hero. Two clean approaches:
Fixed positioning with transform
.modal {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
z-index: 100;
}
Fixed positioning anchors the element to the viewport rather than a parent. Combined with the transform trick, the element stays centered even as the user scrolls.
Full-viewport flex container
.overlay {
position: fixed;
inset: 0;
display: flex;
align-items: center;
justify-content: center;
z-index: 100;
background: rgb(0 0 0 / 0.5);
}
This pattern has an advantage: the backdrop and the centering live in the same element. The child (the actual modal card) requires no positioning of its own. It is also easier to dismiss on backdrop click since the whole overlay is one element.
Choosing the right method
In practice, the decision comes down to context:
- Centering one thing inside a container:
display: grid; place-items: center— two lines, no ambiguity. - Centering a row of items or distributing space: flexbox with
justify-contentandalign-items. - Centering a fixed-width content column on the page:
margin: 0 autowith amax-width. - Centering an overlay or element that sits outside document flow: absolute or fixed positioning with
transform: translate(-50%, -50%), orinset: 0; margin: autowith explicit dimensions. - Text and inline elements within a block:
text-align: center.
A complete working example
Here is a self-contained snippet combining the most common patterns — a full-viewport hero centered with grid, and a content column centered with margin auto:
/* Full-viewport hero, child centered */
.hero {
display: grid;
place-items: center;
min-height: 100vh;
padding: 2rem;
}
/* Content column, max-width centered on the page */
.prose {
max-width: 65ch;
margin: 0 auto;
padding: 0 1rem;
}
/* Centered modal overlay */
.overlay {
position: fixed;
inset: 0;
display: flex;
align-items: center;
justify-content: center;
background: rgb(0 0 0 / 0.5);
}
.modal {
background: white;
border-radius: 0.5rem;
padding: 2rem;
max-width: 480px;
width: 100%;
}
These patterns cover 95% of real-world centering needs. They work across all modern browsers without vendor prefixes or workarounds. The remaining 5% — things like centering within a CSS subgrid or aligning against an anchor element — build on the same mental model: define a container's alignment behavior, let the child respond to it.
What about the old ways?
You may still encounter display: table-cell with vertical-align: middle, negative margins, or line-height tricks in legacy codebases. They work, and knowing how to read them is useful. But for new code, there is no reason to reach for any of them. Flexbox and grid have universal support, cleaner syntax, and fewer edge cases. Start there.
The long-standing joke about centering a div being hard has an expiration date, and it has already passed. Once the mental model clicks — align the container, not the child — the right method for any situation becomes straightforward to choose.