HTML attributes: srcset, sizes and tag

The problem of adaptive images has been bothering the minds of web developers for a long time. This is the task of displaying a large image on large screens and a small one on small screens. This problem is solved through HTML attributes srcset and sizes, as well as the <picture> tag. Let's take a closer look at them below.

HTML attributes srcset and sizes

srcset

  • srcset is a replacement for the src attribute - it takes precedence over src!
  • The src attribute should always be specified! This is necessary for search engine robots.
  • src will be used only if the browser does not support srcset.
  • Firefox and Chrome handle srcset slightly differently, but the general logic is preserved. For example, Firefox may reduce the size of the image when the screen width decreases, while Chrome, if it has loaded a larger size, will use it even on smaller resolutions. The logic for choosing which image to use also differs slightly.

srcset - contains a set of URLs for images (comma-separated), so that the browser can choose the most suitable option depending on the device screen parameters from which the page is viewed.

In srcset, you can specify one or several URLs.

In srcset, it is implied to specify different sizes of the same image. You can also specify different ones, but its logic implies the same image.

Each line in the list should contain a URL and a descriptor. If no descriptor is specified, the default is used - 1x.

The descriptor can be of two types:

  • Physical width of the image in pixels (actual width). For example, 600w, 1000w.
  • Device pixel ratio (DPR) - for example, 2x, 3x.

You can find out your current DPR in the browser console by checking the window.devicePixelRatio variable.

The descriptor is needed for the browser to make a decision on which URL from the set to load (since it doesn't know anything in advance about the image located at the URL). With the descriptor, the browser can understand in advance the width of the image or for which DPR it is suitable.

The syntax of srcset looks like this:

<img srcset="image-1200.jpg"
	 src="full.jpg">

<img srcset="image-640.jpg 640w, image-960.jpg 960w, image-1200.jpg 1200w"
	 src="full.jpg">

<img srcset="image-640.jpg, image-1280.jpg 2x, image-1920.jpg 3x"
	 src="full.jpg">
How it works in an example:
<img srcset="image-640.jpg 640w, image-960.jpg 960w, image-1200.jpg 1200w"
	 src="full.jpg">

In this example, the image full.jpg will not be used because there is the srcset attribute - the browser will choose the most suitable image from srcset.

Which image will the browser choose?

  • If your device's DPR=1:

    • image-640.jpg - if the screen width is > 0px and <= 640px.
    • image-960.jpg - if the screen width is > 640px and <= 960px.
    • image-1200.jpg - if the screen width is > 960px.
  • If your device's DPR=2 (the suitable image will be twice the actual width):
    • image-640.jpg - if the screen width is > 0px and <= 320px (640/2).
    • image-960.jpg - if the screen width is > 320px and <= 480px (960/2).
    • image-1200.jpg - if the screen width is > 480px.
How it works in an example:
<img srcset="image-640.jpg, image-1280.jpg 2x, image-1920.jpg 3x"
	 src="full.jpg">

Which image will the browser choose?

  • image-640.jpg - if the device's DPR=1.
  • image-1280.jpg - if the device's DPR=2.
  • image-1920.jpg - if the device's DPR=3.

On Samsung and other phones, the DPR often reaches 4!

sizes + srcset

When the image occupies only part of the screen width, srcset without sizes will not be enough.

Since the browser does not know anything about the layout (how the page looks), it will assume that the image occupies the entire width of the screen. But if the image occupies only a part, then more than necessary will be loaded as a result.

Wait a minute! What? The browser doesn't know about the layout?

It is logical to assume that the browser has CSS styles and can determine the final width of the image! But at the time of parsing the IMG tag, CSS styles are not yet interpreted, the layout is not yet drawn! If the browser waits until all style sheets are parsed and executed, this will lead to a delay in loading the images.

If no sizes are specified for the image in CSS, sizes will also limit the size of the image, as the width attribute does.

And if, for example, the CSS property max-width:100% is specified for the image, then this property overrides the value of the sizes attribute: i.e. if the width of the image according to sizes is greater than the width of the element in which it is located, its width will be equal to the width of the element (max-width:100%). In general, it works the same as for standard width and height attributes. But I'll repeat again - sizes is needed for the browser - it is an addition to the srcset attribute.

sizes contains a list of elements (comma-separated), where each element describes the size of the image relative to the screen width (viewport).

Using sizes gives the browser additional information to correctly choose the appropriate image from srcset and start loading it as soon as it sees the <img> tag, without waiting for the parsing of CSS styles.

Syntax:

<img
	srcset="small.jpg 300w,
			medium.jpg 600w,
			large.jpg 900w"

	sizes="(max-width: 300px) 100vw,
			(max-width: 600px) 50vw,
			(max-width: 900px) 33vw,
			900px"
	src="image.jpg"
/>

Note that the last size has no media condition - this is the default value. It will be used when none of the previous media conditions match.

Be careful with the order of declaration of checks, because the browser ignores all subsequent checks after the first successful one.

Elements in sizes can have:

  • Media condition - for example, (max-width: 300px) - it describes the width of the viewport area. (max-width: 300px) means that the specified size is suitable for a screen width from 0 to 300 CSS pixels (inclusive). This is similar to a media query, but with some restrictions. You cannot use screen or print.

  • Width of the image for the specified media condition. You can use different units (px, em, vw) to specify the width, but not %. More about units below.
Let's consider such an example:
<img
	 srcset="w-225.jpg 225w,
			 w-300.jpg 300w,
			 w-350.jpg 350w,
			 w-640.jpg 640w"

	 sizes="(max-width: 400px) 100vw,
			(max-width: 700px) 50vw,
			(max-width: 900px) 33vw,
			225px"
	 src="women-dress.jpg"
>
  • If the viewport width exceeds 900px, the image occupies a fixed width of 225px.
  • Up to 900px, the image occupies 33vw, i.e. 33% of the viewport width.
  • Up to 700px, the image occupies 50vw, i.e. 50% of the viewport width.
  • Up to 400px, the image occupies 100vw, i.e. the entire viewport width.

Based on this data, the browser will choose one of the images from the srcset (including all checks with DPR - see the description of srcset).

Units of measurement for sizes

Below is the full list of possible units of measurement that can be used in the sizes attribute.

Unit of measurement Value
em size of the element's font
ex height of lowercase letters in the element's font (height of the letter "x")
ch width of "0" (ZERO, U+0030) for the element's font
rem size of the root element's font (html)
vw 1% of the viewport width
vh 1% of the viewport height
vmin 1% of the smaller viewport dimension (smaller of vw or vh)
vmax 1% of the larger viewport dimension (larger of vw or vh)

Browser support for sizes and srcset

WordPress functions srcset and sizes

How to disable srcset and sizes for WordPress images

/**
 * Disable srcset and sizes for images in WordPress.
 *
 * @version 1.0
 */
if( 'Disable srcset/sizes' ){

	// Disable srcset - exit immediately, this filter is better than 'wp_calculate_image_srcset'
	add_filter( 'wp_calculate_image_srcset_meta', '__return_null' );

	// Disable sizes - this is a late filter, but there is no earlier one for srcset yet...
	add_filter( 'wp_calculate_image_sizes', '__return_false',  99 );

	// Remove the filter that adds srcset to all images in the post content
	// WP < 5.5
	remove_filter( 'the_content', 'wp_make_content_images_responsive' );
	// WP > 5.5
	add_filter( 'wp_img_tag_add_srcset_and_sizes_attr', '__return_false' );
}

An additional filter that removes the srcset and sizes attributes at the last moment. In 99% of cases, this hook is not needed, but you can use it just in case.

// Clear the `srcset` and `sizes` attributes if they have remained for some reason.
add_filter( 'wp_get_attachment_image_attributes', 'unset_attach_srcset_attr', 99 );
function unset_attach_srcset_attr( $attr ){

	foreach( array('sizes','srcset') as $key ){
		if( isset($attr[ $key ]) )
			unset($attr[ $key ]);
	}

	return $attr;
}

Read more in this question

HTML tag <picture>

In order to display different images depending on the device (screen width), you can also use the <picture> tag.

<picture> is a wrapper for the <source> and <img> elements, which allows the browser to choose the source.

The <img> tag is very important here - without it, <picture> cannot exist. This is the element for which the data from <source> will be applied after a suitable <source> is selected.

The <picture> tag itself is a more advanced analogue of the <img> tag and has an intuitive syntax.

<picture> outperforms sizes and srcset attributes in <img> in two cases:

1) When using different image formats.

<picture> allows the use of new formats (webp, avif) without worrying about the support of old browsers. To do this, you can specify the image's MIME type in the type attribute; the browser will use the first supported type.

The selection/analysis of the suitable option is done from top to bottom (the first suitable option will be used):

<picture>
	<source type="image/svg+xml" srcset="my-photo.svg">
	<source type="image/webp" srcset="my-photo.webp">
	<source srcset="my-photo.png">
	<img src="my-photo.png" alt="">
</picture>
  • The image type specified in <source> must match the type specified in type.
  • Do not use the media attribute if artistic styling is not needed.
  • You can also use srcset and sizes.

Multiple sizes (for retina displays):

<picture>
	<source type="image/avif" srcset="my-photo.avif 1x, [email protected] 2x">
	<source type="image/webp" srcset="my-photo.webp 1x, [email protected] 2x">
	<img class="some-class" src="my-photo.png" alt="Icon" srcset="my-photo.png 1x, [email protected] 2x">
</picture>

The media attribute

In the source tag, you can also use the media attribute to specify the screen width for which the specified source should be used:

<picture>
  <source media="(max-width: 799px)" srcset="my-photo-portrait.jpg">
  <source media="(min-width: 800px)" srcset="my-photo.jpg">
  <img src="my-photo.jpg" alt="Some text">
</picture>

The sizes attribute

Allows you to specify the image size (width) for the specified screen size:

<picture>
	<source
		type="image/webp"
		srcset="my-photo-lg.webp 1200w,
				my-photo-md.webp 800w,
				my-photo-sm.webp 500w"
		sizes="(max-width: 800px) 90vw, (max-width: 500px) 70vw, 50vw"
	>

	<img
		srcset="my-photo-lg.jpg 1200w,
				my-photo-md.jpg 800w,
				my-photo-sm.jpg 500w"
		sizes="(max-width: 800px) 90vw, (max-width: 500px) 70vw, 50vw"
		src="my-photo-lg.jpg"
		width="280" height="460"
	>
</picture>

2) Artistic styling.

Artistic styling is a technique where different images are displayed for different screen sizes. For example, if we have a landscape with a person in the middle. Such an image is suitable for a large screen, as the person can be easily seen, but for a small screen, it is better to show a cropped image with the person enlarged.

For example, we have an image that requires artistic styling:

<img src="my-photo.jpg" alt="">

Let's fix it using <picture>.

<picture>
	<source media="(max-width: 800px)" srcset="my-photo-portrait.jpg">
	<source media="(min-width: 800px)" srcset="my-photo.jpg">
	<img src="my-photo.jpg" alt="">
</picture>

Code comments:

  • The media attribute of the <source> element contains a media condition, using which the browser selects which image to use. From the above example, if the viewport width is 800 or less, the image from the first <source> element will be displayed; if it is larger, the second one will be used.

  • The srcset attribute contains the URL of the image. Here, you can also specify a set of descriptors and add the sizes attribute, but using the <picture> tag, this is unlikely to be productive.

  • <img src="" alt=""> with the src and alt attributes before the closing </picture> tag must be specified, otherwise the images will not appear! This tag is needed for robots and when the browser cannot select an image based on the specified conditions.

Showing different images (artistic styling) can also be done through srcset, but it is more convenient through <picture>.

Browser support

The <picture> tag for SEO and why you should forget about it

With this tag, it is easy and painless to transition to the implementation of alternative graphic formats. It is enough to simply list our images (jpeg, png, webp) inside this tag, and the browser will decide which one to use.

If you decide to seriously engage in technical optimization, then you should forget about the <picture> tag.

Because when you start rendering with the <picture> tag, the same as with the <img> tag, it will give a minimum threefold increase in nodes in the DOM tree for each image. The upper limit of your DOM tree should ideally be around 1500 nodes. For many, this limit is exceeded. And each node in the DOM tree is a memory expense and script slowdown.

Why srcset is needed and why CSS and JavaScript are not suitable?

When loading a page, the browser starts loading images before loading and interpreting CSS and JavaScript. This technique reduces the page load time by an average of 20%. But it is not suitable for creating adaptive images, for which the srcset attribute was created.

For example, it would not be possible to load the <img> element, then determine the screen width using JavaScript and dynamically change the image URL. The original image would have already been loaded (or sent for loading) by the time its smaller version was loaded.

--