Saving Bandwidth with Images

part of The Standard

Sam Thorogood
Dev Channel
Published in
6 min readMay 9, 2017

--

Saving Bandwidth with Images — The Standard

In the video, I make a few points about saving bandwidth. I tell you to:

  • serve real videos, not GIFs
  • use pngcrush to compress PNGs
  • keep an eye on when images are loaded — images hidden with CSS or outside the user’s viewport, will still load

In this article, I’ll expand on the above — as well as covering SVGs, high-DPI and when you should inline images. In no particular order, let’s start.

Visualize your viewport

If you place an image on your page — anywhere, even when it’s out of your viewport or its style contains e.g.,display: none, opacity: 0 —it will still be loaded and consume bandwidth.

The lower image is still loaded, even though it’s out of the viewport

Why? Well — browsers are really, really dumb. To be more precise, they’re dumb in that they don’t know what you want. If your page has images that are only visible after a scroll or other action, then you should make sure that nothing loads until that happens.

For bonus points, you should show a tiny, low-quality JPEG (or solid primary color) until the real image is loaded — this prevents the page from appearing unresponsive or as if parts are ‘missing’.

Sanitize your SVGs

If you’re using SVGs — good for stylized, vector images — there’s a checklist you should go through.

  • SVGs take time for a browser to render. Is your image small enough that a tiny PNG is more suitable? You might even save bandwidth (although a few hundred bytes isn’t worth worrying about).
  • Is the SVG unnecessarily complex? In Santa Tracker, we found that many assets — provided by our incredibly talented artists— contained detail and nuances that were too small to be discernible!
    Paths could be simplified, and occluded assets could be removed.
  • Finally, be sure to run a compression tool — like svgo — on your SVGs before serving. These tools aren’t smart, and won’t simplify paths or remove unnecessary detail, but they will shrink your XML.

Pinch your PNGs

Do run pngcrush or zopflipng on your PNGs. These tools will improve the compression of your images without changing the image itself.

zopflipng asset.png asset-zopfli.png
pngcrush asset.png asset-crush.png
pngcrush -ow asset.png # this overwrites the existing file

Rectify your Retina

Is a pixel always one pixel? Well, not when it’s a device-independent pixel (dp). The number of real, screen pixels (px) used to render a dp is referred to as the ‘density’ of a screen — a density of 2.0 means that 4px are used to render one dp (i.e., 2² px per dp).

(If you use e.g., a recent MacBook, this won’t be a surprise to you. However, the most common PC 💻 runs at 1366x768 with a 1.0 density —this is a hallmark of low-cost laptops). Mobile devices typically start from 1.5 and up — all the way to 4.0 for high-end devices like Samsung’s Galaxy phones.

Most PCs are still 1.0, but mobile devices are 1.5 and up

2.0 is fairly common, however, and in my opinion — looks good, even on those high-end devices. So it might be tempting to just ship this everywhere! However, every image you ship — no matter how compressed — is eventually going to be uncompressed and live in a buffer inside the user’s memory (e.g., a tiny 1000x1000 image is still going to consume a few mb).

So, sending 2x images for low-end devices might cause their machines undue CPU load or memory pressure. Instead, use <img srcset /> — which lets you specify 1x, 2x images etc — to let the user’s browser choose what image to display (WebKit demo).

Inline your icons

It might seem counterintuitive, but for small, repeatable icons — like the PNG vs SVG example above — you can actually inline them directly in your CSS or HTML. You can encode them using base64, which has a ~33% overhead. Why would you want to do this? 🤔

  1. Each HTTP fetch costs you ~hundreds of bytes of headers (even if you’re using HTTP/2). If a small icon is <1kb, header cost is equal to overhead.
  2. If your images are specified in your CSS as background-image: url(...), then this could increase the number of round-trips taken to fetch everything required to display your page.
If an image is specified in your CSS, this means at best, you’ll have three round-trips to fetch it

Instead, use the command-line tool base64 to generate a base64-encoded version of an asset, and then specify it in CSS like this—

#selector {
background-image: url(data:image/png;base64,iVBORw0KGgo…);
}

For more information on base64 encoding with Data URLs, including how to use them inside an <img /> tag, see MDN.

Give up on GIFs

In the 2010s area, GIFs have come back — but GIFs are a standard quite literally out of the 80’s (yes, in the top video I say 90's — please call me out on my mistake). They’re now a synonym for short, sharable animations.

But a GIF has terrible compression. You should send the user actual videos — they’re supported everywhere. And most video editing tools will generate a mp4 file encoded correctly. To include a video like a GIF, use this HTML —

<video autoplay loop muted playsinline>
<source src="https://path/to/video.mp4" />
</video>

To learn more about autoplay, loop, and muted (although they mostly do what they say on the tin), check out the MDN reference page. Note that most browsers will not autoplay videos unless they are muted or have no audio track — just think how annoying GIFs would have been if they also contained audio. 🙄 🔊

Finally, the playsinline is vital to make a <video> tag feel like it’s actually just an animated image: it allows mobile browsers to play the video inline inside a HTML page. Without this attribute, a user must tap to make the video fullscreen before it starts — better for an actual movie or trailer. 🎬

There is still one reason you might want to serve a GIF file, and it’s worth calling out. H.264-encoded videos — or even WebP, APNG etc — have great compression, which costs CPU cycles (aka battery life) to decompress.
So if you’re trying to optimize for battery over bandwidth, you could serve GIFs — but remember that a device’s radio “costs” battery to run too. 🔋

Summary

If you’re in the 1st world, bandwidth is almost a right—albeit one that is regularly abused (e.g., the irony of posting this on Medium — a 2015 talk, Website Obesity points out that every article downloads about 1mb).

Using less of your users’ limited resources is always going to be an admirable goal regardless of the sorts of connections they’re using. While images will rarely block the loading of your site, note that e.g., 40% of users will abandon a retail or travel site if it’s not ready after 3 seconds (Google). 💥

Hopefully this article has expanded on The Standard, cleared up a few misconceptions, and given you some tips and tricks. If you’d like further reading, Web Fundamentals covers similar content: Image Optimization.

Do you have questions?

Please leave comments and queries in Medium, or contact me on Twitter. I’m also eager to hear your suggestions or improvements. 🕵️

--

--