Centering things: a solved problem?


In Chrome and Edge, the following code can be used on block layouts to center child elements:

.container {
  align-content: center;
  justify-items: center;
}

align-content works without the need for flexbox or grid — and it works in all browsers!

See the Pen center without grid or flex by Ollie Williams (@cssgrid) on CodePen.

justify-items on a parent element and justify-self on a child also work without flexbox or grid, but only in Chromium for now.

See the Pen Untitled by Ollie Williams (@cssgrid) on CodePen.

Here’s a handy table from the CSS Box Alignment spec:

Unfortunately, not all of this is implemented by all browsers yet. In Firefox and Safari, justify-items and justify-self can only be used in conjunction with display: grid.

How to center a position: absolute element

An absolutely positioned element can be centered using margin: auto. This approach requires setting a width and height on the element:

  position: absolute;
  inset: 0;
  margin: auto;
  width: fit-content; 
  height: fit-content;

An alternative approach that currently only works in Chrome and Firefox Nightly is to use justify-self and align-self instead of margin, but I can’t discern any huge benefit over the older method:

  position: absolute;
  inset: 0;
  justify-self: center;
  align-self: center;

See the Pen absolute position centering with justify/align-self by Ollie Williams (@cssgrid) on CodePen.

And yet…

Regardless of whether you’ve given an element equal padding on the top and bottom, used margin: auto or align-content, with or without flexbox or grid, its often not enough to vertically center text. The article Hardest Problem in Computer Science: Centering Things has plenty of example screenshots from the websites of large companies failing to visually center things. The developers of these websites aren’t stupid — so why is it so difficult?

Even without any padding, a text box will still contain excess white space above and below the actual visible text. The line-height set in your CSS will affect this. The font you use will also have an impact on just how much extra vertical space there is — with the same CSS applied, one font might look perfectly centered while another might look askew. A small handful of fonts have been designed with this problem in mind. The sales pitch for Martian Grotesk, for example, reads: “We researched and calculated vertical metrics and set them up in a way that guarantees equal space above the cap height and under the baseline.” While certain fonts might help avoid the issue somewhat, two new CSS properties offer a more generally applicable solution.

text-box-trim and text-box-edge

Used together, these properties trim the whitespace (known as leading) from above the first line of text and below the last line of text.

Using text-box-trim, you can trim from just the top (trim-start), just the bottom (trim-end) or both (trim-both).

button {
  text-box-trim: trim-both;
}

How much to trim?

text-box-edge accepts two values. The first value specifies where to trim at the above the text. The second value specifies where to trim below the text.

For trimming above the text you have an option of ex, cap or text. For trimming below the text you have a choice between alphabetic or text.

cap height refers to the height of a capital letter.

alphabetic will trim beneath the baseline (the baseline is the invisible line upon which letters sit).

This gif is borrowed from a useful (although now somewhat out-of-date) article by Ethan Wang, a designer at Microsoft.
button {
  text-box-trim: trim-both;
  text-box-edge: cap alphabetic;
}

In typographic parlance, the term x-height is the height of the lowercase “x” character in whichever font you are using.

button {
  text-box-trim: trim-both;
  text-box-edge: ex alphabetic;
}

See the Pen text-box-edge examples by Ollie Williams (@cssgrid) on CodePen.

The text-box shorthand property can set both text-box-trim and text-box-edge:

text-box: trim-both cap alphabetic;

Figma has a control for what it calls vertical trim, which is equivalent to text-box-trim: cap alphabetic.

screenshot of Figma UI vertical trim control

text-box-trim isn’t just for centering text. Here’s an example aligning the very top of some text to the top of an image:

Example title

text-box-trim: trim-start; 
text-box-edge: cap alphabetic;

text-box-trim and text-box-edge are currently supported in Safari 18.2 and looks likely to reach Chrome and Edge relatively soon.

Whether text looks vertically centered partly depends on the context. Does the button text contain ascenders but no descenders? Or vice versa? All caps or only lowercase? Depending on the characters used, the same button can look either perfectly aligned or slightly squiffy.

That text-box-edge has so many potential values speaks to the fact that there is no foolproof boilerplate solution that works for all cases. Until this reaches broader browser support, we’re stuck manually offsetting by a single pixel or two using relative positioning or applying uneven padding whenever things don’t look quite right.