SVG Golf

July 8, 2024
We believe that our greatest asset is our people. Our employee spotlight series aims to showcase the talent, careers, and culture of our team members and Kilterset. Join us in celebrating their personalities, stories and contributions that make our company culture vibrant and our success possible.

“Code Golf” is a common game among programmers, where the challenge is to reduce a given piece of code to a minimum number of characters while still achieving the same end result.

For example, here’s a JavaScript function for summing all the numbers between 1 and n:

A golfed version might look like:

The Challenge

Recently a team member offered a slight twist to the usual pure code form of golf: make the smallest SVG possible.

An SVG, or Scalable Vector Graphics file, is a standard for rendering images in a web browser that contains resolution-independent drawing instructions.

And so this challenge began with a basic icon:

Shrinking the instructions

Without any modification, exporting this file as an SVG resulted in 277 bytes.

How much smaller could we make it? And so the back-and-forth began amongst the team.

The first pass of reducing the SVG’s size was to move the stroke properties, since every path is black, into the svg element.

This brings the SVG down from 277 to 235 bytes. Next, we can collapse the multiple path elements into a single one:

191 bytes. Lastly, we drop the newlines and unnecessary spaces:

186 bytes. This is the simplest solution we came up with for shrinking the original SVG instructions to fit in an external SVG.

Lossy improvements

We rounded the overly-precise values found in this path: <path d="M5.47222 2H1V9H8V5.69444"/> to <path d="M5.5 2H1V9H8V5.7"/>. In other words, the measurements 5.47222 and 5.69444 becomes simply 5.5 and 5.7.

178 bytes. This optimization is a lossy change, modifying the drawing itself. That might fall afoul of someone’s technical definition of code golfing, but it’s quite practical: there’s no observable difference to this icon which is typically rendered at 10x10px.

Inlining in HTML

If the file is small enough, the headers to make the request will be bigger than the request body. This is wasteful. It can make sense to bring the data into the document itself, either by pasting an <svg> element directly in HTML. When we do this, we can drop the long xmlns attribute. That leaves us with:

The SVG is now 96 bytes. That’s a 65% reduction in size.

Embedding in CSS

The icon is used several times throughout the page, so the <svg> approach above will mean copying and pasting the icon. Ideally, we’d like to specify it in one place. That leaves the data: URI.

You typically see this done by base64-encoding the image:

Base64 encoding is good when working with binary data, but SVGs are not binary. This means you’ll get a larger payload than the original bytes. Although you don’t see it in the wild often, you can swap base64 for utf-8 and inline the image itself:

Note that the xmlns property has to come back with this approach, as it’s required for SVGs loaded externally (i.e. through a <image> element or url() property). So we’re back up to 178 bytes. The advantage is that we only have to specify it once in the page, no matter how many times we use it.

Shifting SVG properties into CSS

The icon is black, but we’d like to be able to customize its color, too. When inlining an <svg> in HTML, you can do this with stroke="currentColor" or by using SVG CSS properties. However, when referencing an external SVG (including through a data: URI), you can’t manipulate the colors directly. For this we went with creating an :after pseudo-element and using the image as a mask:

Now we can customize the color by changing the background-color property – useful for :hover, :active states, and transitions.

The properties in the CSS create some redundancy; we can drop the width and the height from the SVG now. And, since the color no longer matters, we’re free to use values other than black. Why not red instead and save ourselves two bytes?

Now SVG itself is down to 140 bytes.

Three solutions

For a standalone, external SVG file, the best we could do was 178 bytes (36% reduction):

For a reusable data: URI friendly with CSS’s url(), we managed 140 bytes (49% reduction):

For an HTML inline-friendly SVG, got it down to 96 bytes(65% reduction):

We release these into the public domain. You are welcome to use this icon in any of your project, commercial or otherwise.

For Fun, Not Profit

Of course, spending time shaving bytes off of an SVG isn’t a real world scenario. Time would be better spent attending to bottlenecks elsewhere and serving pages gzipped will negate these benefits. That said, code golf can be great puzzle fodder for a coffee break.

It’s also helpful to get into the mindset of thinking about optimization. Why make servers and clients burn more resources at the expense of the planet? A change like this one might be insignificantly small, but computers are the product of running impossibly large amounts of insignificantly small operations. Insignificantly small concerns add up. Spending a little more time appreciating this fact pushes you away from complexity toward more efficient, simpler, faster solutions.

Can you improve our solution? Happy golfing!

Like what you've read?
Let's talk
Connect with us on LinkedIn to see our latest content!

Want to work with people like this?

Kilterset is always looking for great people to join our team

Get in contact