Fix blurry SVG rendering

Sharpen blurry SVG rendering by using CSS to rasterize at a higher resolution and then downscale to the target size.

Screenshot of SVG rendered poorly
Figure 1: PNG screenshot of blurry SVG before applying scaling solution.
Screenshot of SVG rendered sharply
Figure 2: PNG capture of sharpened SVG rendering with CSS scaling solution applied.

Problem

SVG rendering doesn’t always work as expected. To output a vector graphic as pixels on a display, browsers need to rasterize the image, sometimes not resulting in the level of quality you would expect from a graphics standard like SVG, which theoretically supports scaling to arbitrary sizes.

Solution

The simplest solution I’ve implemented to solve this blurry SVG issue is instructing the browser to rasterize the SVG at a larger size, then scale down the output using a CSS transform. After transforming the element, use a negative margin to make it fill the same space as before. This is needed because CSS transforms don’t affect an element’s impact on its surroundings.

In other words, render at double the intended size, then scale to half the rendered size.

The result is a SVG at exactly the size you want and free from SVG rendering blur. Although it’s theoretically not ideal to upscale the image rendering and then downscale the output on the page, I haven’t found any real-world downside for this SVG sharpening technique in use cases I’ve encountered.

I’ve put together a CodePen demonstration of the CSS required for this solution: view solution. This particular example is a scenario where Internet Explorer 11 struggles, where the downscaling solution is effective.

.before {
    display: inline-block;
    height: 2.62em;
    width: 2.62em;
}

.after {
    display: inline-block;
    margin: -1.31em; /* .25x desired size */
    height: 5.24em;  /* 2x desired size */
    width: 5.24em;   /* 2x desired size */
    transform: scale(.5);
}

.before, .after {
    background-size: 100%;
    background-image: url('...');
    background-repeat: no-repeat;
}