loading...
Cover image for Greatly Reduce PNG Weight With This One Trick

Greatly Reduce PNG Weight With This One Trick

jamesthomson profile image James Thomson ・2 min read

Preface: In this article I'm assuming you're already familiar with SVG. If not, now's a great time to familiarise yourself! The power of SVG is truly amazing.

More than likely you've found yourself in this situation... You get handed a design, it's beautiful and full of color and images.

The designer then informs you that the hero banner has text that changes and so does the background color.

Here's what that hero banner may look like (though likely far better designed, but hey, it gets the point across):

Ice cream hero banner design

Ok, no problem, that means we can't just use a background image and be done with it, we need to break the hero up into piece so portions of it can be dynamic.

Usually you'd reach to a PNG for the ice cream cone image. But, PNGs are usually pretty big, especially once we start catering to high DPI screens. Our ice cream as a PNG would clock in at a whopping 1.9mb! So instead, we're going to use a trick with SVG masks.

Isolated ice cream image and mask

Jpg (left) 292kb, 8-bit PNG (right) 17kb

First, we're going to save our ice cream as a jpg. I'll use a black background in place of the transparency.

Next, we'll save another image as an 8-bit png to use as the mask image. Any part that is black will be invisible and any part that is white will be visible.

Those 2 images we'll then use together in our SVG like this:

<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" preserveAspectRatio="xMinYMin" version="1.1" viewBox="0 0 938 1912">
  <defs>
    <mask id="mask">
      <image width="938" height="1912" xlink:href="/images/ice-cream-mask.png"/>
    </mask>
  </defs>
  <image mask="url(#mask)" width="938" height="1912" xlink:href="/images/ice-cream.jpg"/>
</svg>

You can reference the images as seen in the code above or you can even inline them as base64 which you can see in this Codepen.

And there you have it. We've gone from a 1.9mb transparent PNG to roughly 309kb SVG without compromising quality or transparency. Pretty sweet, hey?

As always, happy coding! 🤓

It should be noted, I haven't tested all the browsers out there, but SVG support is now very wide spread so I wouldn't expect many issues. That said, if you've encountered any, let me know in the comments.

You can also use this great Codepen to help with your tests.

Posted on by:

jamesthomson profile

James Thomson

@jamesthomson

Just another front-end web dev junkie

Discussion

pic
Editor guide
 

I clicked because I saw ice cream.

 

This is a really cool trick, definitely something I'll be looking at using in the future since I've come across this specific use case.

Do you know if there are any compatability issues with different browsers?

 

In modern browsers SVG support is very good so there shouldn't be any issues. I've even tested in IE11 and it works fine. There are a few ways to approach it though, inline SVGs seem to offer the best support while externally references ones (e.g. as an img) may differ from browser to browser. This codepen samples a number of those options which is useful for testing.

 

Thanks for your reply, James. IE11 support sounds great, that's as far down as I'm willing to go. ;) I'll take a look at the codepen samples.

 

Designers HATE him!

 

I find that using those lossy png optimizers like ImageOptim (MacOS) can get file sizes around the same or even lower than use jpg with masks.

 

Definitely a good option as well. I ran the same 1.9mb PNG through ImageOptim and it got it down to around 600kb so still about double the size. Certainly a great improvement though, especially if you have a batch of PNGs to do, but you do compromise some quality with lossy compression.