Technology

How to Center a Div in CSS

To centre a div horizontally and vertically, make its parent a grid container and use place-items: center:

.parent { display: grid; place-items: center; }

That is two lines and works in every current browser. The older reliable answer is display: flex; align-items: center; justify-content: center; — three lines, identical result.

For horizontal centring alone, margin-inline: auto on a block element with a width is still the right tool, and it does not need flex or grid at all.

"How do I centre a div" has an unhelpful reputation, because the honest answer is that it depends on what you are centring, inside what, and in which direction. This guide gives you the modern default, then the four specific situations where something else is correct — and why the old tricks people still copy are no longer needed.

The modern default: grid with place-items

.parent {
  display: grid;
  place-items: center;
  min-height: 300px;   /* it needs height to centre within */
}

place-items is shorthand for align-items (block axis) and justify-items (inline axis). One value sets both, so this centres in both directions.

The comment matters more than the code. Vertical centring needs the parent to have a height. A block-level parent is only as tall as its content, so "centre it vertically" inside a box with no height means centring inside exactly the space the child already fills — nothing appears to happen. This is the single most common reason centring "does not work".

The flexbox version

.parent {
  display: flex;
  align-items: center;      /* cross axis — vertical by default */
  justify-content: center;  /* main axis — horizontal by default */
  min-height: 300px;
}

Functionally identical for a single child. Prefer flex when you have several children and care about how they distribute, wrap, or grow — gap, flex-wrap and flex: 1 all live here.

MDN's basic concepts of flexbox is the reference worth reading once properly. One trap: align-items and justify-content refer to the cross and main axes, not to vertical and horizontal. Add flex-direction: column and they swap. If your centring inverts when you change direction, that is why.

Horizontal only: margin auto

For a block element with a known width, this predates flexbox and is still correct:

.child {
  width: 600px;
  margin-inline: auto;   /* or: margin: 0 auto */
}

The width is required. Without one, a block element already fills its parent, so there is no leftover space for auto margins to divide.

margin-inline is the logical-property version of margin-left and margin-right. It follows the writing direction, so it does the right thing in right-to-left layouts without a separate rule. Prefer it in new code.

Use this rather than flex when you are centring a page container. It needs no changes to the parent, which means no risk of disturbing how the rest of the children lay out.

Centring text and inline content

text-align: center centres inline content inside a box. It does not centre the box.

.parent { text-align: center; }   /* the text moves */
.child  { text-align: center; }   /* the div does not move */

This distinction causes a lot of confusion. If you want the box centred, you need one of the techniques above; text-align only affects what is inside.

Absolute positioning, when you have no choice

For overlays, modals and tooltips positioned relative to an ancestor rather than in normal flow:

.parent { position: relative; }
.child {
  position: absolute;
  inset: 0;
  margin: auto;
  width: 300px;
  height: 200px;
}

With inset: 0 (all four offsets zero) and a fixed size, margin: auto distributes the remaining space equally in both directions. This is cleaner than the transform version and does not blur text.

The transform approach is still widely copied:

.child {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
}

It works with unknown dimensions, which is its advantage. Its drawback is that a half-pixel translation can land the element on a fractional pixel and soften text rendering. Prefer the inset: 0; margin: auto form when you know the size.

Which to use

SituationUse
One child, both directionsdisplay: grid; place-items: center
Several children, need gap or wrapdisplay: flex with align-items / justify-content
Page container, horizontal onlymargin-inline: auto with a width
Text inside a boxtext-align: center
Modal or overlayposition: absolute; inset: 0; margin: auto
Unknown size, must overlaytop/left 50% + translate(-50%, -50%)

Why it "doesn't work"

Almost every failed centring attempt is one of these five.

  • The parent has no height. Vertical centring inside an auto-height box does nothing visible. Give the parent a height, min-height, or let it stretch inside a taller grid or flex ancestor.
  • You styled the child instead of the parent. align-items and justify-content go on the container. Putting them on the child has no effect (the child-side equivalents are align-self and justify-self).
  • margin: auto with no width. A full-width block has no spare space to share.
  • You expected text-align to move the box. It moves the contents.
  • The axes flipped. flex-direction: column swaps what align-items and justify-content control.

What you no longer need

Several once-standard techniques are now obsolete, and copying them into new code adds complexity for no benefit:

  • display: table-cell with vertical-align: middle — a workaround from before flexbox.
  • Negative margins equal to half the height — required knowing the exact dimensions, and broke whenever content changed.
  • Clearfix hacks around floats — floats are not a layout system, and have not been needed for one since grid shipped.
  • Vendor prefixes on flex — unnecessary for current browsers.

Both flexbox and grid have been supported across all major browsers for years, so the modern two-line answer is safe in production. If you support a specific old browser, check the exact feature on Can I Use rather than adding prefixes speculatively.

Centring in a full viewport

A common case — a login box centred in the window:

body {
  min-height: 100dvh;
  display: grid;
  place-items: center;
  margin: 0;
}

Use 100dvh rather than 100vh. On mobile browsers, vh is calculated against the viewport with the address bar hidden, so a 100vh element is taller than the visible area and the "centred" box sits slightly low with the page able to scroll. The dynamic unit dvh tracks the visible viewport as the browser chrome shows and hides.

margin: 0 on the body matters too — the default body margin makes min-height: 100dvh overflow by 16px and introduces a scrollbar.

If the markup underneath is what is actually confusing, start with HTML for beginners, which covers which tags carry meaning and the boilerplate lines that break mobile when omitted.

Frequently asked questions

What is the easiest way to center a div in CSS?

Put display: grid; place-items: center; on the parent, and give it a height. That centres a single child both horizontally and vertically in two lines, and works in all current browsers.

Why is my div not centering vertically?

Almost always because the parent has no height. A block-level element is only as tall as its contents, so there is no extra vertical space to centre within. Add min-height to the parent, or make it stretch inside a taller ancestor.

What is the difference between align-items and justify-content?

align-items positions items along the cross axis and justify-content along the main axis. In the default flex-direction: row the main axis is horizontal, so justify-content centres left-to-right. Setting flex-direction: column swaps them.

Does margin: 0 auto still work?

Yes, for horizontal centring of a block element that has a width. It has not been superseded — it is still the cleanest way to centre a page container, because it requires no change to the parent. Prefer margin-inline: auto in new code for right-to-left support.

Should I use flexbox or grid to center?

For a single child, grid with place-items: center is shorter. For several children where you need gaps, wrapping or flexible sizing, use flexbox. Both are equally well supported, so the choice is about the rest of the layout rather than centring.

Why does my centred element look blurry?

The transform: translate(-50%, -50%) technique can place an element on a half-pixel boundary, which softens text. If you know the element's dimensions, use inset: 0; margin: auto instead, which lands on whole pixels.

Conclusion

The modern answer really is two lines. What makes centring feel hard is that the failure modes are silent — a parent with no height, or a property on the child instead of the container, produces no error and no visible change.

When it does not work, check the parent's height first. That is the cause more often than everything else combined. If you are building layouts and want them to load quickly too, our notes on making a site load faster cover the CSS side, and building a unit converter in JavaScript puts a small interface together end to end. For the numbers inside those interfaces, see formatting numbers in JavaScript.

Comments