Zach’s ugly mug (his face) Zach Leatherman

A New Technique for Image Optimization: SVG Short Circuiting

November 15, 2023 #4 Popular 2,161 Views

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:

  1. 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 output formats and widths options you’ve used for any specific image.
  2. 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.
  3. 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


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:

	<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">

(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">.


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.


Screenshot image for

With a nod to the tech stack, here are a few things I used to construct the demo:

Walkthrough on YouTube

Watch on YouTube: Stop worrying about huge image uploads with Eleventy Image and CloudCannon CMS

Originally posted on:

Screenshot image for
Zach’s ugly mug (his face)

Zach is a builder for the web at IndieWeb Avatar for He created IndieWeb Avatar for https://www.11ty.devEleventy (11ty), an award-winning open source site generator. At one point he became entirely too fixated on web fonts. He has given 72 talks in nine different countries at events like Jamstack Conf, Beyond Tellerrand, Smashing Conference, CSSConf, and The White House. Formerly part of Netlify, Filament Group, NEJS CONF, and NebraskaJS.

< Newer
An Attempted Taxonomy of Web Components
Older >
The Commit that Updated a Thousand Demos


IndieWeb Avatar for https://vermaden.wordpress.comJean Pierre KolbRichConor C. Peterson ????nucliwebJakub Iwanowski :bash:Zach LeathermanIndieWeb Avatar for https://zerobytes.monsterJonEleventy ???? v2.0.1Doctor Popular


haliphax ????Jean Pierre KolbAngela "Ge" RicciConor C. Peterson ????Thomas Maria HelzlenucliwebPhilip ZastrowKrzysztof JeziornyJakub Iwanowski :bash:Nelson Chu PavloskyRaffael JescheJustin PoehneltJonAmelia Bellamy-RoydsSimon Cox :SEO:Connor BärHeinz WittenbrinkTim Severien - open to workDee-Yell (Dave)Eleventy ???? v2.0.1Ashur CabreraCloudCannonDoctor Popular
  1. Ashur Cabrera

    Ashur Cabrera

    @zachleat say no more fam``` <svg> <image href="beefy.png” /> </svg> ```

  2. Zach Leatherman

    Zach Leatherman

    @ashur well wait a second

Shamelessly plug your related post

These are webmentions via the IndieWeb and

Sharing on social media?

This is what will show up when you share this post on Social Media:

How did you do this? I automated my Open Graph images. (Peer behind the curtain at the test page)