Disable loading images on mobile

In the quest of making Yoast just a bit faster, I dove into the world of images. In this case, I’m talking about showing images on small screens, for example smartphones. Images can be important to strengthen or clarify the content you’re writing, but most of the time they are there to spice things up. For Yoast images are part of our branding. On mobile, we assumably deal with slower connections and devices compared to desktops or laptops. To help speed things up, we don’t want those images to show up. To be more specific, we don’t want them to load.

The reason we want to have a faster loading website is that it helps you rank better in search engines (something we love at Yoast), but more importantly, it makes for overall better user experience. And to achieve this, we are willing to sacrifice part of our branding.

Searching for a way to accomplish this challenge, I checked the options that were available. After a quick search on the internet, developers mostly recommended the following:

“Use the image as a background”

This is indeed a great idea. But search engines won’t index the image. That’s something we don’t want to happen.

“Set the image to display:none;”

Good idea. It will hide the image for visitors, but still loads in the code of your website in multiple browsers.

“Use JavaScript with a user-agent.”

If we use JavaScript to check what kind of device you’re using and based on the outcome, tell the browser if we want an image or not, is not something I would suggest. Yup, it could work in some cases and in most of the time it’s faster than rendering the image. But It just feels so “hacky” to me. And besides that, using JavaScript to remove an object that you just loaded with HTML feels off.

Sourceset is your friend.

After searching and testing a bunch of options, including the ones above, I came to the conclusion that there is no way of not loading an image in a specific browser with just HTML and CSS. The closest we get to targeting images on different screen resolutions is the scourseset within a picture element. A sourceset is part of a HTML element that gives you the ability to load an image based on the resolution of the visitor. If the visitor is on a screen higher than 1000 pixels, show image A. If the visitor is using a screen between 500 pixels and 800 pixels, show image B. If none of the sizes match or the image can’t be found, the browser falls back to the default <img> element within the picture element. And even better, if the browser does not understand the <picture> element, it also falls back to the <img> element!

How it looks in HTML code:

<picture>
<source media="(min-width: 1000px)" srcset="http://sjardo.test/img/large.jpg">
<source media="(min-width: 481px) and (max-width: 999px)" srcset="http://sjardo.test/img/medium.jpg">
<source media="(max-width: 480px)" srcset="http://sjardo.test/img/small.jpg">
<img src="http://sjardo.test/img/medium.jpg" alt="Image alt">
</picture>

In the example I set three sizes:

That last one, that’s the one I want to remove! We don’t want an image on mobile. What’s the easiest thing to do in this case? Right. Remove the source for 480px and smaller. Let’s put this to the test. The results: The image false back on the default <img>. We didn’t set a size for the particular screen resolution, so the browser falls back to the fallback. That’s good for the browser, but not what I want. I want no images to load at all.

Let’s see what it does if I remove the fallback <img>. Results: It works, no more image! What did we get: An error. And the error is slower than loading the small image. That is, once again, not what we want.

One pixel to rule them all

So, what did we do to get the best result possible? It’s pretty simple and straightforward. On the smallest size, we load an empty pixel. The pixel is 1kb in size, so it’s small. We cache the image, making it even faster to load.

How does this look:

<picture>
<source media="(min-width: 1000px)" srcset="http://sjardo.test/img/large.jpg">
<source media="(min-width: 481px) and (max-width: 999px)" srcset="http://sjardo.test/img/medium.jpg">
<source media="(max-width: 480px)" srcset="http://sjado.test/img/empty-pixel.png">
<img src="http://sjardo.test/img/medium.jpg" alt="Image alt">
</picture>

At this point of time, it’s our best solution. Especially on pages with multiple images that we don’t want to load on mobile devices. For example, on our knowledge base page, we had 8 images that are around 50kb each. That means 500kb and 8 server connections. With the above solution, we decreased the size of the image to 1kb and just 1 connection, because the site only needs to connect to the image once and place it 8 times on the page. And to be sure, we place a display:none on the <picture> element, because we don’t want that empty-pixel floating around somewhere.

UPDATE: Base64 images!

There is an even better solution. After a quick chat with Jono Alderson, he came up with the idea to put an base64 image instead of the pixel. A base64 image is kind of the “code” that makes up an image in a image file, but now you load it in directly into the page (like a embedded SVG) This way, you have 0 connections and even less bytes to load on mobile. It looks like this:

<source media="(max-width: 480px)" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8/5+hHgAHggJ/PchI7wAAAABJRU5ErkJggg==" sizes="100%">

The solution we need

The solution above is a great compromise, but not really something we cheer for. It’s not logical we must load an image, that we don’t want to load. What can we do and what do we think we need?

The fallback to the <img> is necessary for the situations an image of a particular size can’t be found or a mistake is made. Leaving a source blank is not in line with other elements. And what if by accident no URL got set in the source?

A solution I would like to see is the ability to pass an attribute that declares that I don’t want to load a image on a particular screen size. Easy to read and easy to implement.

For now the solution with the empty 1x1px works and is supported by multiple browsers. In this point of time it’s the best option and it looks like this will stay for a while.