A New Technique for Image Optimization: SVG Short Circuiting
Working on an Image Optimization tutorial for CloudCannon (using Eleventy), I stumbled into what I think is a neat little trick for automated image optimization.
There are three kinds of optimization that Eleventy Image can do:
- Raster to raster: Convert a large raster input image (PNG, JPEG, WebP, AVIF, etc) into smaller raster output images (pretty standard).
- One nice feature here is that Eleventy Image will automatically swap between
<img>
and<picture>
for you automatically based on the combination of outputformats
andwidths
options you’ve used for any specific image.
- One nice feature here is that Eleventy Image will automatically swap between
- Vector to raster: Convert a large vector image (SVG) into smaller sized raster outputs (again, pretty standard).
- This also includes an option to leave SVG inputs as SVG-only (skipping raster outputs altogether) with
svgShortCircuit: true
.
- This also includes an option to leave SVG inputs as SVG-only (skipping raster outputs altogether) with
- Vector to raster/vector: this new approach uses
svgShortCircuit: "size"
to convert a large vector image (SVG) into a mixture of vector and raster outputs while discarding the raster images that are larger in file weight than their vector counterpart.
Read more about the Eleventy Image options for SVG.
Astute readers might remember the post Vector? Raster? Why not Both! which detailed an approach to manually subset and overlay an image as two separate layers: a vector layer and a raster layer.
SVG Short Circuiting Examples
Mexico
The Mexico Flag is a pretty complex SVG (139.55 kB uncompressed). If we use Eleventy Image, we can look at the output images:
Size | Format | Percent | Width |
---|---|---|---|
53 kB (Brotli compressed) |
svg |
100%
|
980w |
56.28 kB (Discarded) |
jpeg | 106.19% |
1600w |
31.07 kB |
webp | 58.63% |
1600w |
18.52 kB |
avif | 34.95% |
1600w |
6.68 kB |
jpeg | 12.60% |
400w |
3.85 kB |
webp | 7.27% |
400w |
3.39 kB |
avif | 6.39% |
400w |
When using svgShortCircuit: "size"
and svgCompressionSize: "br"
, the largest JPEG is discarded from the output as its file size is larger than the SVG. We prefer the vector output!
Here’s what the generated markup looks like:
<picture>
<source type="image/avif" srcset="1IB2wrqzRT-400.avif 400w, 1IB2wrqzRT-1600.avif 1600w" sizes="…">
<source type="image/webp" srcset="1IB2wrqzRT-400.webp 400w, 1IB2wrqzRT-1600.webp 1600w" sizes="…">
<source type="image/jpeg" srcset="1IB2wrqzRT-400.jpeg 400w, 1IB2wrqzRT-980.svg 980w" sizes="…">
<source type="image/svg+xml" srcset="1IB2wrqzRT-980.svg 980w" sizes="…">
<img src="1IB2wrqzRT-400.jpeg" alt="Flag of Mexico" width="980" height="560" loading="eager" decoding="async">
</picture>
(sizes
attribute omitted for clarity)
This approach is somewhat experimental (and is not enabled by default in Eleventy Image), although it works well in practice. This technique involves replacing large raster formats in <source>
with SVG. Specifically, you might notice the image/jpeg
type above has an SVG image included: <source type="image/jpeg" srcset="1IB2wrqzRT-400.jpeg 400w, 1IB2wrqzRT-980.svg 980w">
.
Tiger
The Ghostscript Tiger is less complex (68.63 kB uncompressed) but still benefits from SVG short circuiting. Let’s look at the Eleventy Image output here:
Size | Format | Percent | Width |
---|---|---|---|
19.63 kB (Brotli compressed) |
svg |
100%
|
900w |
254.67 kB (Discarded) |
jpeg | 1297.30% |
1600w |
179.77 kB (Discarded) |
webp | 915.77% |
1600w |
81.36 kB (Discarded) |
avif | 414.43% |
1600w |
38.84 kB (Discarded) |
jpeg | 197.84% |
400w |
35.04 kB (Discarded) |
webp | 178.49% |
400w |
21.28 kB (Discarded) |
avif | 108.41% |
400w |
Using this technique, the output HTML looks like this:
<img src="59IGmw9rii-900.svg" alt="Ghostscript Tiger" width="900" height="900" loading="eager" decoding="async">
After size comparisons, only the vector is used in the final output and all of the raster outputs are discarded—the markup is simplified to an <img>
.
The output above using svgShortCircuit: "size"
is identical to the output if we had used svgShortCircuit: true
to automatically discard the raster outputs. At some point in the future we may have a feature that uses heuristics to swap between "size"
and true
to avoid unnecessary image processing.
It should be noted that this image optimization technique only works for build-time image optimizations and is a great example of how a build step can take the performance of your web site beyond what request-time image optimization is capable of.
Demo
With a nod to the tech stack, here are a few things I used to construct the demo:
Walkthrough on YouTube
Originally posted on:
2 Comments
Ashur Cabrera
@zachleat say no more fam``` <svg> <image href="beefy.png” /> </svg> ```
Zach Leatherman
@ashur well wait a second