Optimize Page Load Times Using Responsive Images

Optimize Page Load Times Using Responsive Images

·

13 min read

Introduction

Making sure that your images look excellent on all screen sizes could prove to be a complex undertaking since you must consider the image's size, location, how much of the image is visible, the user's connection speed, and many other factors. Most developers end up using the same image for all screen widths and letting the browser scale it to fit. This is a terrible practice since the browser will continue to download the full-size image (which is typically rather huge) even if it is only displayed at a fraction of its original size. This wastes your users' bandwidth and drastically slows down your page load times (especially on slower connections).

The solution to this issue is to use responsive pictures. Responsive images are those that are tailored to the user's screen size. This means that the image will be downloaded in the appropriate size and resolution for the user's device. This will dramatically minimize the amount of data delivered to the user, resulting in faster page load times. There are numerous approaches to implementing responsive images, ranging from easy to sophisticated, and in this article, I will demonstrate all of them.

Methods

To ensure your images are fully responsive and optimized for different screen sizes, here are three powerful methods you should know as a web developer. These methods will not only improve the visual quality of your images but also enhance the overall performance of your website.

  1. img srcset Attribute

  2. img sizes Attribute

  3. picture Element


img srcset Attribute

By far the simplest way to implement responsive pictures is to use the img tag's srcset attribute. This feature allows you to specify numerous distinct picture sizes, and the browser will automatically select the image that best fits the user's screen size.

<img
  src="house-1200.png"
  alt="A house"
  srcset="house-400.png 400w, house-800.png 800w, house-1200.png 1200w"
/>

This code may appear confusing or not, so let me explain exactly what is going on. To get started, we have the standard src and alt attributes that you are accustomed to with all photos. If your user's browser does not support srcset, the image will be served from the src url. This is quite unlikely, given that srcset has been supported by all major browsers for atleast 10 years.

This somewhat confusing srcset attribute allows a comma-separated list of image URLs and widths. The first item in the list, house-400.png 400w, has the URL house-400.png. The name of this link is irrelevant, however if you have multiples of the same image at different sizes, you should name them with the size in the name.

The second element in this item is 400w. This is presumably puzzling since w is not a CSS unit; rather it represents the image's intrinsic width in pixels. This is the image file's real width. You can simply determine this width by viewing the image in your file browser/explorer. If you're using Windows, right-click the image and select Properties; on a Mac, there should be an option named Get Info. In this situation, the image is 400 pixels wide, so we set the width to 400w.

The browser will then use this information to automatically select which image to download. For example, if the user's screen is less than 400px wide, it will use the house-400.png image, which is the smallest image that can be utilized without pixel stretching/blurring. When the browser's width exceeds 400 pixels, it will transition to the house-800.png image. This is because the 400px image is now smaller than the current screen size and will appear stretched/blurred if used. This would continue across all screen sizes until the browser reached the largest image provided.

This is excellent because the browser will now download a reduced image on small screen sizes while maintaining a high resolution image on large screen sizes. This will dramatically minimize the amount of data delivered to the user, resulting in faster page load times. This is an example of how it looks. Try adjusting your browser size to a tiny size and then reloading the page to see whether the smaller image was downloaded.

<img
  style="width: 100%; border-radius: 1rem;"
  src="https://warehouse.co/3200x800/png"
  srcset="
    https://warehouse.co/800x200/png   800w,
    https://warehouse.co/1600x400/png 1600w,
    https://warehouse.co/3200x800/png 3200w
  "
/>

💡
While testing, you may have noticed that the image downloaded was larger than intended. For example, if your screen width was 700px, your browser may have downloaded the 1600px wide image rather than the 800px wide image. This is because the browser also considers the pixel density of your screen. If you are using a high resolution device or have a high zoom level in your browser, the browser will download a larger image to ensure that it looks nice on your screen, as each CSS pixel correlates to several pixels on your screen. To check your device's pixel density, use the console command window.devicePixelRatio.

Handling Different Pixel Densities

When you have a picture that will always be the same size on the screen, you want to ensure that it appears nice on high-resolution screens. For example, if you just submit a 100px wide image for your logo, it will appear blurry on high-resolution devices. To handle this, you can use the srcset attribute to offer numerous images of sizes, where the x unit denotes pixel density.

<img
  src="logo-200.png"
  alt="my Logo"
  srcset="logo-100.png 1x, logo-150.png 1.5x, logo-200.png 2x"
/>

The above code is fairly similar to our last srcset example, with the main difference being that we use units such as 1.5x and 2x rather than hard-coded pixel values. This metric relates to the screen's pixel density. For example, if a user's screen has a pixel density of 1.25 device pixels per CSS pixel, the logo-150.png picture will be utilized because it is the smallest image that can be used without stretching or blurring pixels.

💡
No need to include the 1x unit, as that is set by default. If you only have two images, use logo-100.png, logo-200.png 2x rather than logo-100.png 1x, logo-200.png 2x.

img sizes Attribute

What we've discussed so far is the most basic method for implementing responsive photos, but in many cases, the image size does not match the width of your screen. This article is an excellent illustration of that. On small screen sizes, the content on my blog (including images) takes up the entire width of the screen; but, on higher screen sizes, the content is centered on the page with a limited maximum width. If we merely utilized srcset, as seen above, our photos would scale to the entire size of the browser window, making them larger than necessary on larger screen sizes. This is where the size attribute comes in.

The sizes attribute allows you to specify a single size for your image, such as 50vw, or a list of media queries that will be used to determine the appropriate size for your image. When you do not add the sizes attribute to your img, it defaults to a size of 100vw, which is why the images above scaled off the entire width of the browser window. Let's look at how we may use the sizes attribute to account for a blog like this, which has a maximum size.

<img
  src="house-1200.png"
  alt="A house"
  srcset="house-400.png 400w, house-800.png 800w, house-1200.png 1200w"
  sizes="(max-width: 800px) 100vw, 800px"
/>

The code above is identical to the previous code, but we've added the sizes attribute. The sizes parameter allows comma-separated lists of media queries and sizes. To further understand what's going on, let's break down each item on the list.

Our first item (max-width: 800 pixels) 100vw consists of two sections. The first portion is the media query we wish to compare to. In this scenario, we are checking to see if the screen width is less than 800 pixels. The second section specifies the size of our image if the media query is true. In this situation, we're using 100vw, which means we want the browser to select an image size depending on the entire width of the browser window.

The second item, 800px, does not have a media query and instead only has a size. This is our "fallback" size. If all of the media queries defined before this size return false, this fallback size will be used instead. Essentially, it's like having a media query that always returns true. With this item, we are indicating that our image should be selected assuming that it takes up 800 pixels on the screen. The browser will then use this size to select which image to download. If your browser is set to a high resolution or you are zoomed in on the website, it may download an image larger than 800 pixels. However, in general, this is an effective method of ensuring that your images are not larger than necessary.

If we combine these two items, we are effectively saying that our image should be picked based on the browser width up to 800px. At this point, the image will never take up more than 800 pixels on our screen, therefore we should size it accordingly. This is how I would write code to add responsive photos to this blog, as my blog has a maximum width at higher screen sizes. Let us see an example of this in action.

<img
  style="width: 100%; border-radius: 1rem;"
  src="https://warehouse.co/3200x800/png"
  srcset="
    https://warehouse.co/400x100/png   400w,
    https://warehouse.co/800x200/png   800w,
    https://warehouse.co/1200x300/png 1200w,
    https://warehouse.co/1600x400/png 1600w,
    https://warehouse.co/3200x800/png 3200w
  "
  sizes="(max-width: 800px) 100vw, 800px"
/>

Potential Pitfalls

The sizes attribute is extremely powerful, but there are a few things to consider while utilizing it.

  1. Order Matters

  2. Using Percentages

Order Matters

If you have a sizes attribute with several media queries, the image selected will be the first media query that returns true. This means that the sequence of your media queries is important.

<img
  src="https://warehouse.co/3200x800/png"
  srcset="
    https://warehouse.co/400x100/png 400w,
    https://warehouse.co/800x200/png 800w
  "
  sizes="(max-width: 800px) 100vw, (max-width: 500px) 50vw, 1200px"
/>

If you wrote out your sizes as shown above, your code would not work as intended. The reason for this is that the initial media query (max-width: 800px) 100vw will be true for all screen widths smaller than 800px. This means that the second media query (max-width: 500px) 50vw will never be used because it is only true when the screen is less than 500px, whereas the first media query is always true in those size ranges, therefore it will always be chosen first. To remedy this, organize your media queries so that the most particular searches appear first and the least specific queries appear last.

<img
  src="https://warehouse.co/3200x800/png"
  srcset="
    https://warehouse.co/400x100/png 400w,
    https://warehouse.co/800x200/png 800w
  "
  sizes="(max-width: 500px) 50vw, (max-width: 800px) 100vw, 1200px"
/>

It is also critical to ensure that your default size, the one without a media query, is always last because it always evaluates to true; if it is first, it will always be chosen over any other media query.

Using Percentages

So far, I've shown you how to utilize exact measurements, such as px, and measurements that scale off the browser window, such as vw. But what about percentage sizes, such as 50%? Unfortunately, percentage sizes are not supported by the sizes attribute. The reason for this is that the browser cannot determine how wide anything defined in percentages will be until it knows the width of the parent element. This implies that the browser will have to wait for the complete page to load before deciding which image to download. This would provide a poor user experience because the visitor would have to wait for the entire website to load before viewing any images.


picture Element

Up to this point, we have particularly discussed how to render the same image at multiple sizes to help with load speeds, but this does not address the scenario in which you wish to display a different image at different screen sizes. For example, if you had a large header on your page that took up the full width of the page, you might want to display a different image on mobile than you do on desktop because desktop allows you to utilize a more detailed image. This is where the picture element comes in.

The picture element allows you to declare numerous source elements, which are used to define distinct pictures for use on different screen sizes. The browser will then select the first source element that fits the current screen size and use that image. If none of the source elements match the current screen size, it will fall back to the img defined in the picture element.

<picture>
  <source media="(max-width: 500px)" srcset="stairs-narrow.png" />
  <img src="stairs-wide.png" alt="Someone coming down the stairs" />
</picture>

When testing this code; If you adjust the size of your browser, the image will shift between the two versions. If you're using a mobile device, you might need to zoom in or out to see the image change to a cropped version of the image stairs-narrow.png for smaller screen sizes because the image's focal point.

Now, let's look at the code to understand how it works. To make the picture element work, you must include a regular img tag at the end.

<picture>
  <img src="stairs-wide.png" alt="Someone coming down the stairs" />
</picture>

This will simply render the image as a normal img tag. Where things gets more complicated is with the source element. Each modification of your image, aside from the default one, should have its own source element. In our example, we only had one source, but you might have as many as you require.

<picture>
  <source media="(max-width: 500px)" srcset="stairs-narrow.png" />
  <source media="(max-width: 1000px)" srcset="stairs-medium.png" />
  <img src="stairs-wide.png" alt="Someone coming down the stairs" />
</picture>

Each of these source items contains two major attributes. The srcset attribute functions similarly to the srcset attribute of the img tag. This means that if we have several resolutions of the stairs-narrow.png image, we may include them in the source set. However, when utilizing the picture element, you will most likely only have one resolution in each source element, thus you can just specify that as the single url in the srcset property.

The other attribute is the media attribute. This is similar to how media queries function with the sizes attribute, except the source element media attribute allows you to define only one media query. These searches are then tested from top to bottom, much like the sizes attribute, and the first one that matches is used. If none of the media queries match, the img tag is utilized as a fallback, which is why we don't have a source element tailored to bigger screen sizes.

Why Choose picture Element Over Others

One common question about the picture element is why you would use it instead of the img element's sizes attribute or CSS.

Why not sizes

The key reason to utilize the picture element is that it will always switch to the image defined in the source element that corresponds to the current screen size. This implies that if you zoom or resize the window, it will switch to the appropriate image.

The sizes attribute works similarly, but only when the screen size is increased. If your screen size shrinks, the browser will not switch to or download the smaller image because it already has the larger image and will continue to render it. This is wonderful since it saves bandwidth because there's no use in downloading a smaller image when you already have a larger image, but it might be difficult to display different images on different screen sizes, which is why the picture element is so useful.

Why not vanilla CSS

If you're familiar with CSS, you might see that we can get a very similar outcome by using a few simple CSS attributes.

img {
  object-fit: cover;
  object-position: center;
}

This will cause the image to cover the complete width of the parent element before cropping it so that the image's center remains visible. This will produce fairly similar results, but the problem is that we will still need to download the full quality version of the image, even on small screen sizes when just a quarter of it is displayed. This contradicts everything we're trying to achieve by employing responsive pictures.

Conclusion

Responsive pictures may appear to be a tedious topic, but they do not have to be. Basic responsive pictures can be implemented by just adding a srcset attribute to your img tag and allowing the browser to handle the rest. If you want to be more specific, you can use the sizes attribute to assist the browser in selecting the appropriate image, or you can use the picture element to display different images at different screen sizes.