How to reliably center (block) icons vertically with 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 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 with display: inline have their baseline aligned (to the baseline of their container)
    • Elements with display: inline-block, inline-grid etc. have their bottom edge aligned (to the baseline of their container)
  • vertical-align: middle aligns an element to the middle of a lowercase x. We cannot use it, since we want to align to uppercase letters.

The 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!

  1. Find the Capital Height of the font you're using, e.g. with fontforge Show archive.org snapshot : open a font file > Menu "Element" > Font Info > OS/2 > Metrics > Capital Height. Store it as a decimal, i.e. for a capital height of 675 and an em-square of 1000:
    :root {
      --font-capital-height: 0.675;
    }
    
  2. Now you simply calculate the vertical middle of the icon, and the vertical middle of surrounding capital letters. Note that this relies on inheriting the em, so the icon must not have a font size set.
    .icon {
      /* Do not set a font-size here! */
      height: var(--icon-height);
      --icon-v-middle: calc(var(--icon-height)/2);
      --capital-v-middle: calc(var(--font-capital-height)/2 * 1em);
      vertical-align: calc(var(--capital-v-middle) - var(--icon-v-middle));
    }
    

Try in this jsfiddle! Show archive.org snapshot

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)