Learning SVG

Reference

Second post of the day! I couldn’t hold off on working on the project after all, and worked on removing the Font Awesome dependency in favor of using SVG icons instead.

SVGs as Icons

A while back I learned about the basics of SVG: what they are, how to make them, and how they're perfect for crisp logos and icons instead of using images or icon elements, which require external stylesheets. However, when I actually tried to bring SVGs into my project, I got a big fat mess.

I think the main reason was because the SVGs I was using to start had a lot of extraneous code in them that I didn’t really understand. Also, with little confidence of using the inline <svg> element, I was placing them as an img src which meant I couldn’t really manipulate them. Learning about the things below solved all the problems.

Inline SVGs

The only way to manipulate SVGs with CSS is to include the full SVG element inline with the page markup (as far as I know). But since SVG markup is looong, I wanted to avoid placing it inline. Since I’m using the Hexo static site generator, I can use its templates to create partials for the SVGs. For example I have a partial for the twitter logo:

<svg aria-labelledby="title" role="presentation" class="svg-twitter" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
<title id="title" lang="en">Start Over Coder on Twitter</title>
<path d="M459.37 151.716c.325 4.548.325 9.097.325 13.645 0 138.72-105.583 298.558-298.558 298.558-59.452 0-114.68-17.219-161.137-47.106 8.447.974 16.568 1.299 25.34 1.299 49.055 0 94.213-16.568 130.274-44.832-46.132-.975-84.792-31.188-98.112-72.772 6.498.974 12.995 1.624 19.818 1.624 9.421 0 18.843-1.3 27.614-3.573-48.081-9.747-84.143-51.98-84.143-102.985v-1.299c13.969 7.797 30.214 12.67 47.431 13.319-28.264-18.843-46.781-51.005-46.781-87.391 0-19.492 5.197-37.36 14.294-52.954 51.655 63.675 129.3 105.258 216.365 109.807-1.624-7.797-2.599-15.918-2.599-24.04 0-57.828 46.782-104.934 104.934-104.934 30.213 0 57.502 12.67 76.67 33.137 23.715-4.548 46.456-13.32 66.599-25.34-7.798 24.366-24.366 44.833-46.132 57.827 21.117-2.273 41.584-8.122 60.426-16.243-14.292 20.791-32.161 39.308-52.628 54.253z"/>
</svg>

Whenever I want to use this, I can use templating to place it with minimal markup:

<ul class="nav__menu">
<li>
<a href="https://twitter.com/spacex" target="_blank" rel="noopener">
<%- partial("svg/twitter") %>
</a>
</li>
</ul>

Cleaning Up SVGs

To get rid of all of that extraneous code, there is a great tool called SVGOMG which will clean the markup right out. For example, my search icon looked like this to start:

<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="512px" height="512px" viewBox="0 0 512 512" enable-background="new 0 0 512 512" xml:space="preserve">
<g>
<g>
<path d="M338.752,99.482c-65.965-65.974-173.306-65.974-239.277,0c-65.967,65.964-65.967,173.305,0,239.269
c63.708,63.712,165.99,65.879,232.342,6.544l13.413,13.413c-3.34,8.56-1.59,18.623,5.311,25.528l70.782,70.782
c9.305,9.31,24.397,9.305,33.696,0c9.31-9.299,9.31-24.387,0-33.696l-70.777-70.772c-6.905-6.899-16.988-8.65-25.533-5.311
l-13.413-13.423C404.636,265.465,402.463,163.188,338.752,99.482z M119.698,318.539c-54.819-54.819-54.819-144.015,0-198.834
c54.819-54.83,144.017-54.819,198.836,0s54.819,144.02,0,198.839S174.517,373.358,119.698,318.539z"/>
<path d="M153.1,151.877c23.944-23.95,51.774-41.331,81.037-52.169c-33.153-1.886-68.66,11.014-95.909,38.253
c-27.624,27.626-40.488,63.746-38.142,97.302C110.841,205.137,128.511,176.46,153.1,151.877z"/>
</g>
</g>
</svg>

After running it through SVGOMG it looked like this:

<svg xmlns="http://www.w3.org/2000/svg" width="512" height="512"><path d="M338.752 99.482c-65.965-65.974-173.306-65.974-239.277 0-65.967 65.964-65.967 173.305 0 239.269 63.708 63.712 165.99 65.879 232.342 6.544l13.413 13.413c-3.34 8.56-1.59 18.623 5.311 25.528l70.782 70.782c9.305 9.31 24.397 9.305 33.696 0 9.31-9.299 9.31-24.387 0-33.696l-70.777-70.772c-6.905-6.899-16.988-8.65-25.533-5.311l-13.413-13.423c59.34-66.351 57.167-168.628-6.544-232.334zM119.698 318.539c-54.819-54.819-54.819-144.015 0-198.834 54.819-54.83 144.017-54.819 198.836 0s54.819 144.02 0 198.839-144.017 54.814-198.836-.005z"/><path d="M153.1 151.877c23.944-23.95 51.774-41.331 81.037-52.169-33.153-1.886-68.66 11.014-95.909 38.253-27.624 27.626-40.488 63.746-38.142 97.302 10.755-30.126 28.425-58.803 53.014-83.386z"/></svg>

BETTER!

Accessible SVGs

One thing SVGOMG removed that I didn’t like was the accessibility markup. In Sarah Drasner’s SVG talk she very succinctly identified what’s needed to make sure SVGs can be handled correctly by screen readers and keyboard users. First, the SVG element needs to include an aria-labelledby attribute which references a title element; the title element must be the first child within the SVG, and it also needs to include an id. Adding role="img" lets screen readers know that it’s an image and most will skip over these, however since most of my SVGs will be placed within an anchor tag, they’ll still be processed.

Later I found this article which gives even more detail about making SVGs accessible. Tl;dr they should also include a description element. It’s also important to note that the role should be "presentation" in cases like SVG backgrounds, or "text" when they’re text.

One note about the title: in addition to its accessibility usefulness, unfortunately it doubles as a hover tooltip…not pretty. To get rid of this, add pointer-events: none; to the element’s CSS. Since the SVG is within an anchor tag, it will keep all the needed functionality.

Here’s the final result:

<svg aria-labelledby="title desc" role="img" class="svg-search" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><title id="title" lang="en">Search</title><desc id="desc">Magnifying glass</desc><path d="M505 442.7L405.3 343c-4.5-4.5-10.6-7-17-7H372c27.6-35.3 44-79.7 44-128C416 93.1 322.9 0 208 0S0 93.1 0 208s93.1 208 208 208c48.3 0 92.7-16.4 128-44v16.3c0 6.4 2.5 12.5 7 17l99.7 99.7c9.4 9.4 24.6 9.4 33.9 0l28.3-28.3c9.4-9.4 9.4-24.6.1-34zM208 336c-70.7 0-128-57.2-128-128 0-70.7 57.2-128 128-128 70.7 0 128 57.2 128 128 0 70.7-57.2 128-128 128z"/></svg>

Getting Them To Show Up

Ok, now all the basics are done! Last step is to make them look how they should. One great tip from this video is to add a blanket fill property to all SVG elements in the CSS; that way, by default they will inherit whatever text color is assigned to their parent elements. Combined with the title handling above, this goes near the top of the CSS file:

svg {
fill: currentColor;
pointer-events: none;
}

Last thing is to throw some size on them so that they are bigger than 0x0 px (the default, how I’ve stripped the SVG files). Since this will change depending on the use, I’ve included a class for each SVG file to access them easily. Or, if there are several SVGs under one parent (like in a nav menu), I can size them in one go:

.nav__menu svg {
width: 18px;
vertical-align: sub;
}

SVGs seem to line up slightly differently from how icons were in line with the text, so it took some fiddling around with this. In this case, aligning it as a subscript worked for my nav menu.

One article I found that I didn’t implement is about just that—getting SVGs to line up properly with text. There are some nice ideas about giving a font size to them so that the SVGs also inherit sizing, rather than needing to explicitly define it for each use. I don’t have that many icons on my site, but maybe I’ll try this one day!

Sourcing SVGs

While there are a lot out there freely available, ironically I’m still using the Font Awesome icons, because they make them available as SVG downloads! I bought a forever-license a year and a half ago as part of a Kickstarter campaign, and this is the first time I’ve had use for it…love it. The license also gives me access to the regular- and lightweight icons that aren’t available for free.

Other Stuff

In all of the reading and research I also came across this CSS Tricks article: Inline SVG vs Icon Fonts [CAGEMATCH]. It’s a good read if you’re interested in learning more about SVG icons vs. icons!

Up Next