How to reliably center icons vertically with inline text

Updated . Posted . Visible to the public. Repeats.

vertical-align is hard. Have you ever wanted to vertically center an icon with text? This usually means "vertically align with capital letters", as visually, a text line goes from baseline up to the capital top. That's because text usually starts with a capital letter, plus descenders are far less frequent than ascenders.

In this card we'll vertically center an icon (or any "blockish" inline element, really) with the capital letters of surrounding text. This works well with our modern approach to SVG icons, or e.g. for custom list icons. Note that it won't work with "text" icons that scale with font-size.

Technical background

  • All text has a "baseline". It is the bottom edge of most letters, like A or a.
  • The browser aligns all inline elements to the baseline of their container (i.e. the baseline of the text of their container).
    • Elements containing text have their text baseline aligned (to the baseline of their container)
    • Replaced elements (<svg>, <img>) and empty inline-block elements have their bottom edge aligned (to the baseline of their container)
  • vertical-align: middle aligns an element's baseline to the middle of a lowercase x. We cannot use it, since we want to align to uppercase letters.

Solution

We'll move the bottom edge of the icon up to the middle of a capital letter, then push it down by half its own height. This will center the icon vertically to uppercase letters – no matter the icon height or the surrounding font size!

.icon {
  display: inline-block;
  height: var(--icon-height);
  vertical-align: calc(0.5cap - var(--icon-height)/2);
}

Notes:

  • Icon and any wrappers must not set font-family, font-size, vertical-align, since 1cap is measured in the icon's own font.
  • The cap unit is Baseline since 2024 Show archive.org snapshot .
  • Any wrapper elements must be display: inline. An inline-block wrapper creates its own line, so the icon would be centered within the wrapper instead of the text.
  • If the icon is a replaced element (svg, img), it may also be display: inline.

Try in this jsfiddle! Show archive.org snapshot

Profile picture of Dominik Schöler
Dominik Schöler
Last edit
Dominik Schöler
License
Source code in this card is licensed under the MIT License.
Posted by Dominik Schöler to makandra dev (2023-01-31 07:47)