Utilizing icons in user interface elements is helpful. In addition to element labeling, icons can help reinforce a user element’s intention to users. But I have to say, I notice a bit of icon misalignment while browsing the web. Even if the icon’s alignment is correct, icons often do not respond well when typographic styles for the element change.
I took note of a couple real-world examples and I’d like to share my thoughts on how I improved them. It’s my hope these techniques can help others build user interface elements that better accommodate typographic changes and while upholding the original goals of the design.
Example 1 — Site messaging
I found this messaging example on a popular media website. The icon’s position doesn’t look so bad. But when changing some of the element’s style properties like font-size
and line-height
, it begins to unravel.
Identified issues
- the icon is
absolute
ly positioned from the left edge using a relative unit (rem
) - because the icon is taken out of the flow, the parent is given a larger
padding-left
value to help with overall spacing – ideally, our padding-x is uniform, and everything looks good whether or not an icon is present - the icon (it’s an SVG) is also sized in
rem
s – this doesn’t allow for respective resizing if its parent’sfont-size
changes
Recommendations
We want our icon’s top edge to be at the blue dashed line, but we often find our icon’s top edge at the red dashed line.
Have you ever inserted an icon next to some text and it just won’t align to the top of the text? You may move the icon into place with something like position: relative; top: 0.2em
. This works well enough, but if typographic styles change in the future, your icon could look misaligned.
We can position our icon more reliably. Let’s use the element’s baseline distance (the distance from one line’s baseline to the next line’s baseline) to help solve this.
Baseline distance is font-size * line-height.
We’ll store that in a CSS custom property:
--baselineDistance: calc(var(--fontSize) * var(--lineHeight));
We can then move our icon down using the result of (baseline distance – font size) / 2.
--iconOffset: calc((var(--baselineDistance) - var(--fontSize)) / 2);
With a font-size
of 1rem
(16px
) and line-height
of 1.5
, our icon will be moved 4 pixels.
- baseline distance =
16px
* 1.5 =24px
- icon offset = (
24px
–16px
) / 2 =4px
Demo: before and after
Example 2 – unordered lists
The second example I found is an unordered list. It uses a web font (Font Awesome) for its icon via a ::before
pseudo-element. There have been plenty of great articles on styling both ordered and unordered lists, so I won’t go into details about the relatively new ::marker
pseudo-element and such. Web fonts can generally work pretty well with icon alignment depending on the icon used.
Identified issues
- no
absolute
positioning used – when using pseudo-elements, we don’t often use flexbox like our first example andabsolute
positioning shines here - the list item uses a combination of
padding
and negativetext-indent
to help with layout – I am never able to get this to work well when accounting for multi-line text and icon scalability
Recommendations
Because we’ll also use a pseudo-element in our solution, we’ll leverage absolute
positioning. This example’s icon size was a bit larger than its adjacent copy (about 2x). Because of this, we will alter how we calculate the icon’s top
position. The center of our icon should align vertically with the center of the first line.
Start with the baseline distance calculation:
--baselineDistance: calc(var(--fontSize) * var(--lineHeight));
Move the icon down using the result of (baseline distance – icon size) / 2.
--iconOffset: calc((var(--baselineDistance) - var(--iconSize)) / 2);
So with a font-size
of 1rem
(16px
), a line-height
of 1.6
, and an icon sized 2x the copy (32px
), our icon will get get a top value of -3.2 pixels.
- baseline distance =
16px
* 1.6 =25.6px
- icon offset = (
25.6px
–32px
) / 2 =-3.2px
With a larger font-size
of 2rem
(32px
), line-height
of 1.2
, and 64px
icon, our icon will get get a top value of -12.8 pixels.
- baseline distance =
32px
* 1.2 =38.4px
- icon offset = (
38.4px
–64px
) / 2 =-12.8px
Demo: before and after
Conclusion
For user interface icons, we have a lot of options and techniques. We have SVGs, web fonts, static images, ::marker
, and list-style-type
. One could even use background-color
s and clip-path
s to achieve some interesting icon results. Performing some simple calculations can help align and scale icons in a more graceful manner, resulting in implementations that are a bit more bulletproof.