Inline FontAwesome SVGs in Hugo

2021-03-08

I have recently started using icons from FontAwesome, and I found an excellent post that shows how you can inline FontAwesome SVGs. This pulls the SVG data into the HTML of each page, so that a single GET request receives the page and any icons.

So far, all I’m using this for is FontAwesome like the original post does, but this technique will work for any SVG.

I made a couple of improvements over the linked post, however:

  1. I reference the partial from the short code, avoiding duplicated code
  2. I strip the comments from the SVGs

Here’s how I did it:

Download FontAwesome and drop SVGs into themes/<THEME>/fontawesome

I just added all of FontAwesome to my site. This only increases the size of my Git repository, not any delivered page, and it means I can reference any FontAwesome glyph in the future.

I downloaded the latest release from GitHub, then moved them into the right place:

unzip fontawesome-free-5.15.2-web.zip
mv fontawesome-free-5.15.2-web/svg themes/<THEME>/fontawesome
rm -rf fontawesome-free-5.15.2-web*

Add themes/<THEME>/layouts/partials/fontawesome.html

There is an unfortunate hack here – I have to hard-code the path to the fontawesome directory, which is inside my theme, which means I’ve hardcoded the “themes” directory (which is configurable) and the name of my theme into the partial.

Note that I’m modifying the SVG to include a fill='currentColor', and also using a regex to strip XML comments. (Of course, regular expressions cannot parse all of HTML/XML, but they can handle this task within the limited domain of SVG files I inspected by hand first.)

A partial is usable within other theme data.

<span class="fontawesome-inline-svg" >
  {{- $fname:=print "themes/<THEME>/fontawesome/" . ".svg" -}}
  {{- $svg := readFile $fname -}}
  {{- $commentStrippedSvg := replaceRE "<!--[^>]*-->" "" $svg -}}
  {{- $filledPathSvg := replace $commentStrippedSvg "<path" "<path fill='currentColor'" -}}
  {{ $filledPathSvg | safeHTML }}
</span>

Add layouts/shortcodes/fontawesome.html

A shortcode is usable within your Markdown content. It just references the partial.

{{ partial "fontawesome.html" ( .Get 0 ) }}

Add styling

Put this wherever you’re keeping your site’s CSS. This scales the SVG to be approximately the size of whatever text element it’s in, so that it feels like an “icon font”, but is not using web fonts.

span.fontawesome-inline-svg {
  display: inline-block;
  height: 0.9em;
  width: 0.9em;
  top: 0.1em;
  position: relative;
}

UPDATE 2021-03-09: Actually, use inline styling

Since publishing this, I found that while styling based on the fontawesome-inline-svg class works great in the browser, it does not work reliably in RSS feed readers. Here’s a Twitter thread with screenshots.

What seems to work better – although I don’t know if it works reliably everywhere – is using an inline style="..." attribute on the <span> element containing the SVG. I added that to my fontawesome.html partial, so now it looks like this:

<span
  class="fontawesome-inline-svg"
  style="display:inline-block; height:0.9em; width:0.9em; top:0.1em; position:relative;"
>
  {{- $fname:=print "themes/<THEME>/fontawesome/" . ".svg" -}}
  {{- $svg := readFile $fname -}}
  {{- $commentStrippedSvg := replaceRE "<!--[^>]*-->" "" $svg -}}
  {{- $filledPathSvg := replace $commentStrippedSvg "<path" "<path fill='currentColor'" -}}
  {{ $filledPathSvg | safeHTML }}
</span>

I also removed the style from my CSS so that I wouldn’t get confused trying to edit it in the future.

This may not be a concern for you at all, depending on whether you expect to need to use SVGs in your actual content, and on whether you have an RSS feed in the first place. For me personally, RSS is very important – it’s how I interact with much of the Web, and I want to support it as best I can wherever I can, so I have moved over to the inline approach.

Use it

In my Markdown content, I can do this:

Hard at {{% fontawesome "solid/wrench" %}} work

In my theme templates, I can do this:

<p>Hard at {{< partial "fontawesome.html" "solid/wrench" >}} work </p>

And it’ll come out looking like this:

Hard at fontawesome/solid/wrench work