Icons

Scaling an SVG without scaling the stroke

Image

A few days ago, I ran into a little problem when using SVGs. I’d created a reusable set of SVG symbols for a project I was working on, and started sprucing it up with all the pretty icons my designer gave to me. As we all know, one of the biggest benefits to using SVG is the “scalable” part of it, meaning that graphics render perfectly at and size, no matter the original size of the graphic. I’m a huge fan in general of SVG, and implementing them into this project was a no brainer for me.

However, a few of the icons in the design consisted of strokes, and those strokes were always 1px in width, no matter the size. When you scale an SVG, it scales everything about it, so an icon that’s scaled up two times would have stroke widths that are double the size of the original. One such example was a “+” icon that indicated there was more content. I had to reuse that icon at small and large sizes, but:

  1. I wanted the stroke width at all sizes to be 2px
  2. I wanted to create one graphic that I could reuse at any size without scaling the stroke width

Enter The Vector Effect Attribute

One of my favourite things about programming is being faced with a problem. It challenges you to research and find solutions. In this case, I stumbled upon the vector-effect attribute, which conveniently has an available value called non-scaling-stroke. It does exactly what it says, i.e. prevents strokes from scaling as an SVG scales.

[…]

I’d see a scaled up icon including scaled up effects. This one’s dimensions are 4 times the size of the original view box. As such, the stroke would render at 8px. In order to circumvent this, I added the vector-effect attribute to the paths on the original graphic, and set the value to non-scaling-stroke, like this:

Code language: HTML

<circle vector-effect="non-scaling-stroke"/>
<path vector-effect="non-scaling-stroke"/>
<path vector-effect="non-scaling-stroke"/>
Tags

Align SVG Icons to Text and Say Goodbye to Font Icons

In building my own SVG-based icon system, I’ve run into (and mostly solved) these same issues.

Why should I care about how SVGs are styled?

If you’ve ever used font icon systems like Font Awesome you know how easy it is to add to a project and get going. The icons align to your text easily and can be modified by changing the font-size of the element. There is no clearly defined way for styling an SVG icon system. I’ve seen some systems custom style and place each icon in their library. This route sounds painfully unsustainable if you utilize more than 15 icons in your UI.

Can it scale like an icon font?

To emulate the font-size scaling I use a class to set the SVG size to 1em by 1em. This means that if your title text is a 48px font size the SVG will be 48px by 48px. This works nicely for components like buttons and inputs when you want to add an icon. This also empowers you to pass a font size to the element via modifier class or inlined CSS. Using font-size to determine the size of your icon makes your life a little easier.

Image

Code language: CSS

.svg-icon svg {
  height: 1em;
  width: 1em;
}

My SVG won’t align to with my text. How do I fix this?

The downside is that a DOM element on it’s own doesn’t align nicely with text. To counter this I wrote the .svg-icon handler class to hold the size and be relative positioned so that I can absolute position the SVG inside of it. Moving the icon down by “-0.125em” allows me to pull down the icon by 12.5% at any scale.

Image

The first example shows that DOM elements align to the baseline of text by default. However, since our icon is already properly scaled to consider the baseline, we need to pull it down for the baseline to truly align. At this size the distance is 6px away, 6px/48px = ⅛ or 12.5%. In the second example, pulling the icon down by -0.125em places the icon onto the proper baseline of the text.

Code language: CSS

.svg-icon {
  display: inline-flex;
  align-self: center;
  position: relative;
  height: 1em;
  width: 1em;
}
 
.svg-icon svg {
  height:1em;
  width:1em;
}
 
.svg-icon.svg-baseline svg {
  bottom: -0.125em;
  position: absolute;
}

In the detail: close button (or how to style a close button using a font for the icon)

There’s a × character in most common fonts which you should use instead of an x for close, but getting it to look right across devices requires an eye for the detail.

Here’s a screenshot of the simulator vs. the real device, with exactly the same CSS applied to create the effect. Notice that the vertical align is off?

Image

It took me a while to work out what was different, but it’s the font. The font I’m using (if you’re on a Mac - as I was), is Helvetia Neue, but my Android doesn’t have that font, so it was falling back to the next default (possibly set as sans-serif, which could be Open Sans, or it could be something else). In this case, the different font had a slightly different letter height, so it caused (obviously) as slightly different result.

The pro tip: make sure to use a common font, probably Arial (IHMO ideally a font that doesn’t need to be downloaded) for button icons.

Yes, I know this is obvious if you’re using an icon font…but maybe not immediately obvious if you’re re-using system fonts.