SVG has all but replaced icon fonts as the de facto standard for showing icons on the web. Earlier this week, I ran into a seemingly strange alignment issue when I tried to use one alongside text.
I was attempting to create an error message with an icon that’s:
- vertically centered, and
- has a margin between it and the text
SVG icon courtesy of https://feathericons.com/
My first instinct in vertically centering situations has been to reach for flexbox and
align-items: center, which makes all things vertical-centering-related generally trivial.
However, this results in the following image:
If you take a look in the inspector, you’ll see the following two boxes surrounding the
<svg> vs. the
<div> surrounding it:
<div> is taller than its child, even though it has no other content in it! The extra height is causing the SVG to be vertically misaligned with the text.
What’s going on here?
<svg> elements are inline elements by default, which have
vertical-align: baseline as their default. The implication, according to the spec, is that the baseline of the SVG element is aligned with the baseline of its parent. In all browsers that I know of, inline elements have an extra bit of height below the baseline of the font to accommodate descenders, the little hanging features of text e.g. below lowercase “g”s and “y”s.
<svg> ‘s parent (the
<div> ) is displayed as a block-level element, the parent’s height is going to be increased as a result of the of the descender padding, which is what you can see in the above screenshots, causing the parent to appear taller than it is and misaligning it with the text.
How do we fix this?
vertical-align: top | bottom | middle on the SVG element
Pretty much anything other than
baseline will solve this problem since
bottom will align the element with one of the edges of the parent, while
middle will align the middle of the SVG with the middle of the parent. All of these achieve the outcome we’re looking for.
Note that if you decide to set this globally, like the example above, the
vertical-align value you use will have implications if you put the
<svg> alongside other text.
display: block on the SVG element
vertical-align does not apply to block elements, which will make the extra padding go away. Note that, as above, setting this globally as in the example above will affect your ability to put
<svg> elements next to other text.
3. (In the example above) Wrap the text with
margin-left instead of wrapping the SVG with
For the purposes of this component, this is basically the same as option #2. Children of
display: flex components are treated similarly as block-level elements.