Search code examples
svgencodinglessdata-uriocticons

How to include UTF-8 data: URIs (for SVGs), in LESS?


Reasoning

I'm bundling small minified SVGs (icons) with my CSS via LESS's data-uri method, to reduce HTTP requests similar to the purpose of icon fonts such as Octicons or Ye Olde CSS Sprites.

However, LESS encodes them in Base64.
This is sub-optimal in the case of SVG, which can be Data URI'd in UTF-8 (example).

There's three reasons why this is sub-optimal:

1: Base64 is silly for text

The purpose of Base64 is to encode binary data using only 6 bits per byte, making it safe to embed in text files. This is great for PNGs and JPEGs, but it makes any text file 33% larger for no reason. If you're now thinking "well gzip takes care of that", then keep in mind that...

2: Encoding text in Base64 makes gzip much less effective

To understand why this is the case, consider this:

btoa('width')   === 'd2lkdGg='
btoa(' width')  === 'IHdpZHRo'
btoa('  width') === 'ICB3aWR0aA=='

As a practical example, let's take an actual SVG and experiment with it:

$ wc -c *
68630 tiger.svg
25699 tiger.svg.gz
91534 tiger.txt
34633 tiger.txt.gz

Even after gzipping, it's still ~35% larger.

3: It disregards some free sources of redundancy

Think about the width example above. Every SVG will have this substring, and if you embed SVGs in a CSS, you'll probably have this keyword somewhere else (or others), which gzip could benefit from (because this is how Huffman Coding works), but not if it's hidden by Base64.


The Question

How can I embed SVGs in LESS as data: URIs using UTF-8 instead of Base64?

I can imagine a thousand ways to do this involving build tools like Grunt, but it breaks my workflow because I won't be able to do things like style: include:less all.less from a Jade view (I do this in development), or even just @import 'images.less'; from a less file.


Solution

  • I'm an idiot. This is simple:

    data-uri('image/svg+xml;charset=UTF-8', 'path/to.svg')
    

    I had to read LESS's source to figure this one out.

    All the benefits I mention above are gained here, in particular that if you have tons of small SVGs, they will benefit from the redundancy between each other. And it works in all browsers.