Updated: How to reliably center icons vertically with text

Posted . Visible to the public. Auto-destruct in 60 days
  • Simplified to the "new" cap unit (baseline since 2023)
  • Removed the 1lh shortcut that apparently was wrong

Changes

  • [`vertical-align` is hard](https://makandracards.com/makandra/44200-css-font-metrics-in-detail). 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](/makandra/522938), 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.
  • + - 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.
  • -## Perfect solution ("100%")
  • +## 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](https://fontforge.org/en-US/): 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:
  • - ```css
  • - :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.
  • - ```css
  • - .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));
  • - }
  • - ```
  • +```css
  • +.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](https://caniuse.com/wf-cap).
  • +- 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!](https://jsfiddle.net/4nzkxg9f/)
  • -
  • -
  • -## Pragmatic shortcut ("90%")
  • -
  • -If you do not want to measure your font (or can't), you can use `--capital-v-middle: calc(1lh/2)`. This will align the icon vertically to the [line-box](https://iamvdo.me/en/blog/css-font-metrics-line-height-and-vertical-align#line-height-problems-and-beyond) instead of the true capital letter middle. It will not be perfect, but "good enough" for most fonts. Plus, it's font-independent.
Profile picture of Dominik Schöler
Dominik Schöler
License
Source code in this card is licensed under the MIT License.
Posted by Dominik Schöler to makandra dev (2026-11-09 14:30)