A problem I have encountered while working with the <source>
element is that despite providing the width
and height
attributes on both the <source>
and the image fallback there is still substantial layout shift which I believe is because I have provided images with multiple dimensions(and as there is a substantial difference in size between them).
Simplified example to illustrate:
<picture>
<source
sizes="(min-width: 900px) 900px, (min-width: 640px) 600px, (min-width: 340px) 300px, calc(100vw- 56px)"
srcset="/images/demo-300.avif 300w, /images/demo-600.avif, /images/demo-900.avif 900w"
type="image/avif" width="300" height="400" />
<source
sizes="(min-width: 900px) 900px, (min-width: 640px) 600px, (min-width: 340px) 300px, calc(100vw- 56px)"
srcset="/images/demo-300.webp 300w, /images/demo-600.webp 600w, /images/demo-900.webp 900w"
type="image/webp" width="300" height="400" />
<source
sizes="(min-width: 900px) 900px, (min-width: 640px) 600px, (min-width: 340px) 300px, calc(100vw- 56px)"
srcset="/images/demo-300.jpg 300w, /images/demo-600.jpg 600w, /images/demo-900.jpg 900w"
type="image/jpg" width="300" height="400" />
<img src="images/demo-300.jpg" width="300" height="400" />
</picture>
I would expect that this would work the same way that providing the intrinsic size of an image as the value of the width
and height
attributes works with the <img>
tag to help browsers properly assign space for the image that will render, even when you use CSS later to modify the size of the image.
However this doesn't work with the <source>
tag and I want to know if there are any workarounds.
the error encountering here is that although providing width and height attributes for the sources and the image, there's still layout shift observed, specially when images of different dimensions are loaded. To make sure it doesnot happen we will wrap the in a which has the same ratio and we will add the required css as follows:
<style>
.container {
position: relative;
width: 100%;
}
.aspect-ratio-placeholder {
width: 100%;
padding-top: calc(400 / 300 * 100%);
}
.image {
position: absolute;
top: 0;
<!-- begin snippet: js hide: false console: true babel: false -->
left: 0;
width: 100%;
height: 100%;
}
</style>
<div class="container">
<div class="aspect-ratio-placeholder"></div>
<picture class="image">
<source
sizes="(min-width: 900px) 900px,
(min-width: 640px) 600px,
(min-width: 340px) 300px,
calc(100vw - 56px)"
srcset="/images/demo-300.avif 300w,
/images/demo-600.avif,
/images/demo-900.avif 900w"
type="image/avif"
width="300"
height="400"
/>
<source
sizes="(min-width: 900px) 900px,
(min-width: 640px) 600px,
(min-width: 340px) 300px,
calc(100vw - 56px)"
srcset="/images/demo-300.webp 300w,
/images/demo-600.webp 600w,
/images/demo-900.webp 900w"
type="image/webp"
width="300"
height="400"
/>
<source
sizes="(min-width: 900px) 900px,
(min-width: 640px) 600px,
(min-width: 340px) 300px,
calc(100vw - 56px)"
srcset="/images/demo-300.jpg 300w,
/images/demo-600.jpg 600w,
/images/demo-900.jpg 900w"
type="image/jpg"
width="300"
height="400"
/>
<img src="images/vila-demo-300.jpg" width="300" height="400" />
</picture>
</div>