Errors and fixes

Centring an element: the four correct ways and when to use them

Grid, flex, auto margins and absolute positioning each solve a different case. The choice depends on what you centre: content, a block or an overlay.

Key points

  • For content inside a container, `display: grid; place-items: center` is the shortest form.
  • For a fixed-width block, `margin-inline: auto` needs no flexible container.
  • For an overlay, `position: absolute; inset: 0; margin: auto` avoids the transform and its rounding.

Short answer: to centre content inside a container use display: grid; place-items: center. For a block with a known width, margin-inline: auto. For an overlay, inset: 0; margin: auto. The transform is needed less often than it looks.

Centring means distributing the free space

An element centres only when space is left over. The browser measures the width available in the container, subtracts the width of the child and gets the free space; each method spends that space in a different way. Grid hands it to the tracks and then aligns the item inside the track, flex distributes it along the main axis, auto margins absorb it in equal parts, and absolute positioning splits it between the two sides once inset is resolved.

Hence the practical rule: if the child fills the whole width there is no free space and no method will move it. The same holds vertically when the container has no definite height: a percentage against a parent without a height resolves to auto, and the centring has nothing to distribute.

The diagnostic step, before touching the CSS

Open the developer tools, select the child and read the Computed panel: if width equals the container width, the problem is the free space, not the method. Then compare the two rectangles from the console.

const child = document.querySelector(".stage > *");
const box = child.getBoundingClientRect();
const parent = child.parentElement.getBoundingClientRect();
console.log({ freeX: parent.width - box.width, freeY: parent.height - box.height });

If freeX is zero the child is as wide as the container: add a max-width or drop width: 100%. If freeY is zero the container is as tall as its content: you need a min-height. Only after ruling out those two cases does switching method make sense.

The four methods

1. Grid

.stage {
  display: grid;
  place-items: center;
  min-height: 100dvh;
}

This is the shortest form, and it centres on both axes without knowing the size of the child. It also works when the content is taller than the container, as long as you handle the overflow.

2. Flex

.row {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 1rem;
}

Better than grid when several elements sit side by side: the gap and the alignment stay explicit. With a single child, grid is shorter.

3. Auto margins

.prose {
  max-width: 68ch;
  margin-inline: auto;
}

This needs no flexible container and suits the body of an article. Vertically, auto margins resolve to zero unless the parent is flex or grid.

4. Absolute positioning

.overlay {
  position: absolute;
  inset: 0;
  margin: auto;
  width: min(90vw, 32rem);
  height: fit-content;
}

The gain here is skipping transform: translate(-50%, -50%), which at fractional zoom can leave text less sharp. With inset: 0 and margin: auto the browser does the centring.

Which one to choose

CaseMethodWhy
content in a sectiongridone declaration, both axes
several items in a rowflexexplicit gap and alignment
body text of an articleauto marginsno flexible context needed
overlay or dialogabsolute + insetno transform, free size

When the fix does not work

If the centring seems to work but the content is clipped, the container has a fixed height and the child is taller: you need min-height and overflow: auto. If the child stays on the left with margin: auto, it is 100% wide: with no free space there is nothing to distribute.

When the common fix makes things worse

Adding display: grid; place-items: center to the wrapper is the fix that circulates most, and on a text child it does damage: justify-items: center removes the stretch, so the paragraph shrinks to its content and the lines break in the middle. The centring succeeds, the reading does not.

The same applies to text-align: center placed on a container that has to stay readable: it centres inline text, not blocks, and on a list it produces items with a centred first line and the rest on the left. If the child must keep its width, centre the block and leave the text on the left.

One limitation to budget for

Centring with place-items: center is unreachable when the child is larger than the container: the overflow spills on both sides and the left part ends up outside the scroll area. That is not a browser defect, it is the definition of center. With place-content: center and a min-height the content stays centred but scrolls; with justify-items: safe center the browser falls back to start when space runs out. Support for safe is the part to check, not to assume.

How to prevent it

  • Choose one method per content type and use it across the project.
  • Never centre with line-height or padding: it breaks as soon as the text wraps.
  • Test at 320px, 768px and 1440px: centring that works on desktop often clips on mobile.

Where to continue

In the catalogue: hero block, components and icons. The guides: Flexbox and Grid for designers and UI kit, library or design system; the comparison: dark mode without a second design system.

Frequently asked questions

Does place-items: center also centre vertically?

Yes, on a grid container. With one row and one column it centres both axes.

Why does margin: auto not centre vertically?

On a block in normal flow the vertical auto margins resolve to zero. It only works vertically in a flex or grid context.

Does a transform blur the text?

It can round to subpixels at fractional zoom. For small text, prefer grid or auto margins.

How do I centre an element without knowing its height?

Grid and flex do not need the height. With absolute positioning, inset: 0 plus margin: auto lets the browser compute it.

And if the container has overflow: auto?

Centring can clip the content when it is taller than the container. Use place-content: center with a min-height and padding.