Zach’s ugly mug (his face)

Zach Leatherman

Vector? Raster? Why Not Both!

August 25, 2021 #9 Popular

This week I ran into an interesting class of problem that—in hindsight—could use a much better workflow. Does it exist?

Screenshot of jamstackconf.com

It has to do with the hero image on the right side of the home page on jamstackconf.com. We work using Figma on the marketing team at Netlify and my first attempt at exporting this image was fraught with peril.

Attempt 1: SVG

  • 10.1 MB Original Export from Figma as SVG
  • 9.9 MB SVG optimized with SVGOMG

Now I know that these sizes are the uncompressed file sizes (before GZIP/Brotli) but I think we can both agree that even an optimized 9.9 MB is a bridge too far for even the starchiest of compression algorithms (Update: 9.9 MB gzipped to 7.36 MB). There are just too many embedded raster images inside of this SVG to yield good results from SVGOMG alone. Let’s swap to raster and see how far we can go.

Attempt 2: PNG

1.2 MB Original Export from Figma as PNG Full PNG version

So y’all know me well enough that I won’t be putting a 1.2 MB hero image in that prime area of viewport real estate. Let’s try some basic optimizations. The important thing to note here is that we need to preserve the image’s transparency. If the background color changes, I don’t want to have to reoptimize this image. That rules out a conversion to JPEG.

ImageOptim

831 KB PNG optimized with ImageOptim ImageOptim PNG version

I was impressed with the ~400 KB savings here from a single drag-and-drop onto ImageOptim but 831 is still too high.

Squoosh

376 KB PNG optimized with Squoosh (Reduced palette to 256 colors) Squoosh PNG version

Now we’re cooking with gas. That Reduced Palette option offered a huge savings! I did play around with the AVIF format settings on Squoosh a bit but wasn’t able to beat the PNG file size. (Update August 27: take note of the new Attempt 4: AVIF section below)

Attempt 3: WebP

152 KB WebP optimized with Squoosh (Lossless, Reduced palette to 256 colors, demo offers PNG fallback) Squoosh WebP version

Wow, this is a really nice file size savings! And we’ll use <picture> here to progressively enhance our PNG to WebP. Many might consider this to be “good enough” but the entire point of this blog post is the last trick (*waves jazz hands*).

Attempt 4: AVIF

Update August 27: Jake Archibald offered some good advice to try the AVIF format again (in Lossy mode) without reducing the color palette. I think it was a good prompt! The reduced palette options (while offering large file size improvement) did take a toll on the image. My informal goal here was to get as much quality out of the AVIF format with a similar file size to the WebP reduced palette version.

Read Jake’s excellent blog post: AVIF has landed.

Squoosh settings: Lossless (off), Quality: 45, Subsample Chroma (off), Effort: 6

168 KB AVIF optimized with Squoosh (Full palette, demo offers WebP and PNG fallback) Squoosh WebP version

The Winner: Two Separate Layers: SVG + AVIF/WebP/PNG

If we separate the stuff that vectors are good at (gradients, lines, etc.) and put that into an SVG and put the rest into the raster format, we can achieve even more savings! Now I did take a bit of the easy way out here—I didn’t put as much into the vector layer as I could have. And you may want to preserve more of the image in the foreground for things like “printing” (as if anyone still did that).

2 Layers, SVG version optimized with SVGOMG
Squoosh WebP version

Using the raster layer as the foreground image and the supplementary vector image as a CSS background-image, we can combine the two! You may even be able to dump the optimized raster back into the SVG as a Data URI embedded in an <image> if you want to get real fancy—I didn’t go down that road.

74 KB + 4.2 KB Optimized SVG plus AVIF/WebP/PNG Two layers

Final Results

From 10.06 MB to 78 KB—a savings of 9.9 MB. Not too bad.

Method Size Savings
Original SVG 10.06 MB
SVG optimized with SVGOMG 9.92 MB -0.14 MB
PNG 1.16 MB -8.76 MB
PNG optimized with ImageOptim 831 KB -329 KB
PNG optimized with Squoosh (Reduced palette) 376 KB -455 KB
WebP optimized with Squoosh (Reduced palette) 152 KB -224 KB
AVIF optimized with Squoosh (Full palette) 168 KB +16 KB
Two Layers: SVG (SVGOMG), AVIF/WebP/PNG (Squoosh) 78 KB -90KB

Savings are in comparison to the previous attempt.

Disclaimer: If you check the above sizes to the currently implemented version on jamstackconf.com the raster image layer may be larger than expected! I still need to merge a PR to ship some final optimizations! The PR has shipped!

Zach’s ugly mug (his face)

Zach is a builder for the web with IndieWeb Avatar for https://www.netlify.comNetlify. He created the IndieWeb Avatar for https://www.11ty.devEleventy site generator and is still fixated on web fonts. His public speaking résumé includes talks in eight different countries at events like Jamstack Conf, Beyond Tellerrand, Smashing Conference, CSSConf, and The White House. He is an emeritus of Filament Group, NEJS CONF, and still helps out with nebraskajs’s AvatarNebraskaJS. Read more about Zach »

Previous
Two Million npm Downloads for Eleventy
Next
Fire SVG animations (SMIL) when the SVG is visible

72 Retweets

JamstackMartin SchneideramberleyBotónJean Pierre KolbPunky! Laboratorio DigitalGabriel LuethjeEric PortisTyler Sticka, ☁️4Henri Helvetica v2.2 👩🏾‍🚀 🇭🇹Thomas SteinerFynn BeckerAhmad ShadeedSami Keijonen4rontenderPaul AyoYoav WeissFrançois REMYSara SoueidanBasix JackyJono AldersonJoan León 🏞⚡️Mike AparicioDan RodneyNoble DesktopKamen NaydenovMinimalist Wall ClocksВеб-стандартыIndieWeb Avatar for https://www.bram.usRyan MulliganDuncan MackenzieDan DenneyEric Guo 过纯中Ollie BoermansShawFresh Frontend LinksJyrki AlakuijalaIndieWeb Avatar for https://mailsgun.rudailydevlinks.Thiery MichelMartin UnderhillIndieWeb Avatar for https://coduza.comFriday Front-EndPablo Lara HFront-End FrontFatih HayrioğluFrontend Daily 🚀manuIndieWeb Avatar for https://www.67nj.orgIndieWeb Avatar for https://www.67nj.orgIndieWeb Avatar for https://hnikoloski.comIndieWeb Avatar for https://tympanus.netWP Expert | WordPress,Web Design & MarketingRSSFeeds CloudFullStack BulletinIndieWeb Avatar for https://coduza.comAndy Jackson 🌍Josué AcevedoB891_tankredVisyu SolutionJoan León 🏞⚡️IndieWeb Avatar for https://www.itry.topIndieWeb Avatar for https://www.reddit.comIndieWeb Avatar for https://guruitsource.comIndieWeb Avatar for https://www.sweetsaw.xyzIndieWeb Avatar for https://breakingpoint.roIndieWeb Avatar for https://mailsgun.ruIndieWeb Avatar for https://programmer.chimpymail.comIndieWeb Avatar for https://programmer.chimpymail.comIndieWeb Avatar for https://graphics-unleashed.com

122 Likes

Eric Guo 过纯中Ahmad SaleemAlexei AccioRoberto ModicaMarkus CadonauMichele InvernizzipudymodyBrian MilneKiran SonleyShawPierre FarTRST_Blogkev ePaul Shryock (he/him)Stephen LindbergMatthew PhillipsRyan MulliganSubramanya ChakravarthyGoerpᴊᴏɴᴀs sᴄʜᴍɪᴅᴛMahdiMisbah ansoriLeoaeeMike AparicioAndrew ChouPhil KeysKevin MacKenzieSubaru Tempest 🐉Dave MethvinSue PoohGolmoteM Haidar Hanif 🧊Danuel, the Cruella🤍Gregor AlbrechtSteinErik SkotkjerraSebiNicolas GiethlenShireen TajJeremy JayMaëligCorentinSérgio JardimMyCool KingStephen CunliffeAndrea Pernici丁一Johannes SchröderFrançois REMYBob MassarczykMatthias OttRobert McCrearyDan Shappir 💉💉💉AdrianNiiAyi AnkrahHazim Sami / حازم ساميnemzes 🇪🇺dies das 🦂 contentPeppouptonkingLeo BernarddovydenflakiMaxime RichardFynn BeckerBradley TaylorPaul AyoPhil HawksworthJamund FergusonJacob 'KurtXTRM' GroßMark Tomlinson𝒟𝑜𝑔𝓊𝓀𝒶𝓃Sami KeijonenMilo VermeulenAhmad ShadeedSven WolfermannHélio Correia4rontenderKaiFynn BeckerTimon ForrerChrisArchitectRafael Calvo 🔰Scott McCrackenMatt KaneKyle Mitofsky #BLMAlfredo LopezDion AlmaerflakiDaniel Ehnissdodiameer 🧡Aodhan HamiltonEric PortisSøren Birkemeyer 🦊ced 404Tyler Sticka, ☁️4Gaël PoupardBernard Nijenhuisdodiameer 🧡Ben DelarreCallieAs soon as I spot one 👾bkardellJoe Lamyman𝕕𝔾𝕣𝕒𝕞𝕞𝕒𝕥𝕚𝕜𝕠amberleyGuus HoeveJózsef Polgárashur.cab/reraSanti CrosColin FahrionBotónAlexis DeveriaChris Price 🏳️‍🌈Jaqueline Bica⚡Stephanie EcklesOwen Buckley 💡Lars Knudsen in 🇩🇰Robin RendleLee FisherPunky! Laboratorio DigitalNikita Voloboev
22 Comments
  1. Alexis Deveria

    @Fyrd

    Very cool! Love the vector + raster solution. If you were bored, one further optimization would be to hand-craft the SVG to use a for that grid instead of that big path...or possibly have a repeating background in CSS. 🤔

  2. Punky! Laboratorio Digital

    @punkyio

    Great solution! Thanks for sharing 🙌

  3. Zach Leatherman

    @zachleat

    BOrEd?? neVER 😅 AlTHoUgh I wiLL saY That BecaUSE The svg iS AbOut 4 kB gZipPEd it mIGHT nOT qUIte FIt THe BAck-Of-the-NAPkiN coSt/beNefIt matH I woulD WaNT 🥸

  4. Zach Leatherman

    @zachleat

    You’re welcome!

  5. Dave Rupert

    @davatron5000

    Here to say excellent use of

  6. Roel Nieskens

    @PixelAmbacht

    Sweet, yo! Would you be able to do the same layering but inside the SVG image instead of layered backgrounds of a DIV? It can do bitmap and vector after all. Or am I missing something? (DISCLAIMER: "am I missing something" is my middle name)

  7. Zach Leatherman

    @zachleat

    is the real MVP

  8. Zach Leatherman

    @zachleat

    Yeah—I think so! I did mention that in the middle somewhere

  9. Alexis Deveria

    @Fyrd

    Haha, yeah absolutely agree.

  10. Roel Nieskens

    @PixelAmbacht

    Ah see, it's there!! Apologies for the noise. Sincerely, Roel " " Nieskens

  11. Berkay🥤

    @raufsamestone

    I think you can update/re-index OG image for previous Tweet with Card Validator. cards-dev.twitter.com/validator

  12. Zach Leatherman

    @zachleat

    yeah, I think Twitter lets you opt-out of a preview on a tweet if it pops one up and you delete it—which I normally like! But this time I did the wrong thing

  13. Adam Stoddard

    @AdamStddrd

    yes yes yes along similar lines, love to use filter drop shadows instead of baking them into semi-transparent images so you can get nice soft shadows *and* those sweet gainz (reductionz?) from reducing the palette

  14. Zach Leatherman

    @zachleat

    ooooh yes—this is good 🏆

  15. Henri Helvetica v2.2 👩🏾‍🚀 🇭🇹

    @HenriHelvetica

    nice. PNG-8s are awesome. w/o naming names, I can hear them screaming that was too much work, and send that to a service, but w/o source files, this won’t be done. Added, some will say that 8 bit webp isn’t sharp enough. It was made for this though. 👏🏾

  16. Henri Helvetica v2.2 👩🏾‍🚀 🇭🇹

    @HenriHelvetica

    what do you call this? Vitmap? Rastor?

  17. Zach Leatherman

    @zachleat

    For me the weak point is that blue oval in the SVG, I don’t think it’s raster but it ain’t looking good on iOS when I zoom in. Worth another look, that part might need to go into the raster version. Approach is still sound tho

  18. Zach Leatherman

    @zachleat

    SV-BMP

  19. Henri Helvetica v2.2 👩🏾‍🚀 🇭🇹

    @HenriHelvetica

    for sure the approach is wild. Ppl might not realize that putting a face on a plain background sends the file size in the clouds, and possibly forces a new format choice

  20. Jake Archibald

    @jaffathecake

    Nice! The raster layer would be around 50-55kb as an AVIF. It isn't a huge saving, but it means you wouldn't need to drop to 256 colours.

  21. Mark Tomlinson

    @NeuesAltes

    So, so satisfying. Thanks a lot for sharing

  22. Chriztian Steinmeier

    @greystate

    Nice - and layering offers the neat possibility of adding a subtle parallax effect... 🤔

Shamelessly plug your related post:

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)