SVG Golf

July 8, 2024
Pete Nicholls

“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 lot of code

A golfed version might look like:

Not much code

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:

The icon rendered on screen

Shrinking the instructions

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

Optimization attempt one

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.

Optimization attempt two

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

Optimization attempt three

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

Optimization attempt four

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.

Optimization attempt five

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:

Optimization attempt six

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:

Base Encoding the image

Adding the encoded string to the page css

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:

Inlining the svg as utf-8

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:

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?

Removing the width and height

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):

36% reduction

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

49% reduction

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

65% reduction

We release these into the public domain. You are welcome to use this icon in any of your projects, 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!

LEARN MORE

Let’s talk

Contact Us

Stories & insights

read the blog