How to center a div in CSS, every method that works
Flexbox centers a div in two lines. Here is that method, the five others worth knowing, and the two reasons centering silently does nothing.

To center a div in CSS, make its parent a flex container and center on both axes:
.parent {
display: flex;
justify-content: center; /* horizontal */
align-items: center; /* vertical */
}
That is three lines on the parent, nothing on the child, and it works whether the child has a fixed size or not. If you only came for the answer, you can stop here.
Everyone else is still reading because that snippet did not work, and it did not work for a reason nobody's tutorial mentions. So this post covers all six methods worth knowing, when each one is the right call, and the two silent failures that make centering feel cursed.
Every position below was measured in a real browser with getBoundingClientRect(), not eyeballed. Where a method leaves an element off-centre, the number quoted is the actual pixel offset.
Pick a method in 10 seconds
Read down the left column until a row describes what you have.
| What you have | Use | Axes |
|---|---|---|
| A parent you can style, anything inside it | display: flex + justify-content + align-items |
Both |
| A parent you can style, and you like grid | display: grid + place-items: center |
Both |
| A child inside a flex parent, and only the child is yours | margin: auto on the child |
Both |
| A block element with a width, horizontal only | margin: 0 auto on the child |
Horizontal |
| An absolutely positioned element | inset: 0 + margin: auto on the child |
Both |
| An absolutely positioned element of unknown size | top: 50% + left: 50% + transform: translate(-50%, -50%) |
Both |
| Text, or anything inline | text-align: center on the parent |
Horizontal |
Six of those seven put the element dead centre, measured at x=0.0 y=0.0. The two horizontal-only rows are the exceptions, and they are exceptions on purpose.
Method 1: flexbox, the default answer
.parent {
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh; /* only if you want the whole screen */
}
justify-content works along the main axis and align-items across it. With the default flex-direction: row, that means horizontal and vertical in that order. Flip to flex-direction: column and the two swap jobs, which catches everyone once.
This is the right default because it does not care about the child. No width needed, no height needed, no wrapper. Multiple children get centered as a group.
Method 2: grid, in one property
.parent {
display: grid;
place-items: center;
}
place-items is shorthand for align-items and justify-items at once. One line, same result, and it is the shortest correct answer in CSS.
Use it when the parent is already a grid. Do not switch a working flex layout to grid just to save two lines.
Method 3: margin auto, the one people forget
Here is the trick worth stealing. Inside a flex container, margin: auto on the child centers it on both axes:
.parent {
display: flex;
}
.child {
margin: auto;
}
Measured offset: x=0.0 y=0.0. Auto margins in flexbox absorb all the leftover space, and an auto margin on all four sides splits that space evenly in both directions.
This matters when you do not control the parent's centering properties, only the child's. It is also how you push one item to the far right of a navbar while the rest stay left: margin-left: auto on that single item.
Outside a flex container, the same declaration behaves completely differently, which brings us to the next one.
Method 4: margin 0 auto, horizontal only
.child {
width: 600px;
margin: 0 auto;
}
This is the oldest trick in the list and it still runs most article layouts, including this page. It centers a block element horizontally inside its parent.
It does not center vertically. Measured on a 200px-tall container with a 60px box, the box sat at y=-70, which is the top. That is not a bug. Vertical auto margins on a normal block element resolve to zero, by specification.
Two requirements it will fail silently without:
- The element needs a width (or
max-width). A block element already fills its parent, so there is no leftover space to split. - The element must be block level. An inline element ignores it.
Method 5 and 6: centering something absolutely positioned
Absolute positioning ignores flexbox and grid centering on the parent, so it needs its own approach. There are two, and the choice is about whether you know the element's size.
If the size can be anything:
.child {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
top: 50% puts the element's top edge at the middle, which is half an element too low. The transform pulls it back by half its own height and width. Percentages in transform are relative to the element itself, which is what makes this work without knowing any dimensions.
If you would rather avoid transform:
.child {
position: absolute;
inset: 0;
margin: auto;
width: 100px;
height: 60px;
}
inset: 0 is shorthand for all four offsets set to zero, which pins the element to every edge at once. margin: auto then splits the impossible leftover space evenly. Measured at x=0.0 y=0.0. This one needs an explicit width and height, and in exchange it leaves transform free for animations.
Both need a positioned ancestor. Put position: relative on the parent or the element will centre itself against the whole page.
Method 7: text-align, which centers less than you think
.parent {
text-align: center;
}
This centers inline content: text, links, <span>, <img>, buttons. It does not center block elements.
Measured in the same 400px container, an inline <span> landed at x=-0.0, dead centre. A <div> in the same parent landed at x=-150.0, still hard against the left edge.
That single measurement explains a large share of "why is my div not centering". text-align: center is doing its job perfectly. Its job is just not the one you wanted.
Centering more than one thing
Everything above centered a single box. With two or more children, flexbox centers them as a group, which is almost always what you want:
.parent {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
gap: 1rem;
}
Measured with two 60px boxes in a 200px-tall container, the first box sat 30px above centre and the second 30px below. The pair straddles the middle. Add gap and the boxes separate without either one leaving the group.
The one thing to watch is that flex-direction: column swaps the jobs of the two centering properties. justify-content follows the main axis, and in a column the main axis runs top to bottom. So:
| Direction | justify-content |
align-items |
|---|---|---|
row (default) |
Horizontal | Vertical |
column |
Vertical | Horizontal |
Both still say center, which is why the mistake is invisible. Change the direction on a working centered layout and nothing moves, because centre is centre either way. Change it on a layout using flex-start or space-between and everything rearranges.
The first silent failure: percentage height with nowhere to measure from
This is the number one reason the flexbox snippet at the top of this post appears to do nothing.
.parent {
display: flex;
align-items: center;
height: 100%; /* ← this is the problem */
}
A percentage height means "a percentage of the parent's height". If that parent's height is auto, which is the default, there is no number to take a percentage of, so the declaration is ignored and the element just wraps its content.
Measured: a div with height: 100% inside an auto-height parent came out 19.6px tall, exactly one line of text. Not the screen. Not zero. Just its content.
So your flexbox is centering correctly. It is centering inside a box that is 19.6px tall, and vertically centering inside 19.6px looks identical to not centering at all.
Fixes, in order of how often they are right:
.parent {
min-height: 100vh;
} /* full viewport */
.parent {
min-height: 400px;
} /* a definite number */
.parent {
height: 100dvh;
} /* viewport, minus mobile browser chrome */
min-height beats height because content taller than the box can still grow instead of overflowing.
The second silent failure: place-items is not place-content
These two look interchangeable. With one child they are. With two, they produce measurably different layouts.
.a {
display: grid;
place-items: center;
}
.b {
display: grid;
place-content: center;
}
With two 60px boxes in a 200px-tall grid:
| Gap between the boxes | What it did | |
|---|---|---|
place-items: center |
40px | Split the container into two rows, centered each box in its own row |
place-content: center |
0px | Kept the boxes together and centered the pair as a group |
place-items centers each item inside its own grid track. place-content centers the whole grid inside the container. With one item there is one track and no difference, which is why the distinction stays hidden until the day it bites.
If you want a tight group in the middle of a page, you want place-content. If you want each row's contents centered, you want place-items. Both is legal and does what you would hope.
What to actually use
- Reach for flexbox first. Three lines, no assumptions about the child, works everywhere. It is the boring right answer.
- Use
margin: 0 autofor page and article layouts. Nobody wants an entire page vertically centered. - Use
place-items: centerwhen the parent is already a grid. Do not convert a layout for it. - Use absolute positioning only for overlays, like a modal or a badge on a card. If the element is part of normal page flow, it should not be absolutely positioned.
- Never use
text-align: centerto center a box. It cannot, and it will not tell you so.
And when centering fails, check the parent's height before you touch anything else. It is the answer far more often than the centering method is.
Practice it, do not just read it
Centering is one of those skills that only sticks once you have watched a box move. CSS Layout is built entirely around that: you write the CSS, the preview updates, and the checks tell you whether the element actually landed where you meant it to rather than roughly near it.
For the wider picture, the CSS guide lays out the order to learn things in, and How Websites Work covers the layout stage this all happens in, in case the phrase "the browser applies the CSS, then lays out, then paints" is doing more work than it should.
More from the blog

Vibe coding, what it is and exactly where it breaks
Vibe coding means describing what you want and shipping what the AI writes without reading it. It works for four things and fails badly at five others.
Read more
SQL joins explained, which rows survive and why
INNER, LEFT, RIGHT, FULL and CROSS joins on the same two tables, with the real result rows. Plus why the Venn diagram everyone shows you is misleading.
Read moreReady to write some code?
Put this into practice - start your first free lesson. No setup, no credit card.