Responsive images
A photo 800 pixels wide does not fit on a phone screen, and a huge file for a small screen wastes traffic. Responsive images solve both problems: CSS fits the picture into its place, and HTML lets the browser choose a suitable file.
A fluid image
By default an <img> is shown at its real size and can stick out over the edge. Two properties make an image fluid — shrinking together with its parent:
<style>
img { max-width: 100%; height: auto; }
</style>
<img src="/media/photo-800x500.jpg" alt="A river in the mountains" width="800" height="500">max-width: 100% forbids it to be wider than the parent, height: auto keeps the proportions. The width and height attributes are still worth setting: they let the browser reserve the space in advance, so the text does not jump while the picture loads.
Proportions: aspect-ratio
The aspect-ratio property sets the ratio of a block's sides: the width stretches, and the height is calculated by itself. This is how space is prepared for a video or a preview:
<style>
.video { aspect-ratio: 16 / 9; max-width: 320px; background: black; color: white; display: grid; place-items: center; }
</style>
<div class="video">16 : 9</div>Filling: object-fit
When an image gets both a width and a height, it gets distorted. object-fit says how to fit it into the frame:
<style>
.row { display: flex; gap: 8px; }
.row img { width: 140px; height: 140px; border: 2px solid gray; }
.cover { object-fit: cover; }
.contain { object-fit: contain; }
</style>
<div class="row">
<img src="/media/photo-400x250.jpg" alt="Stretched">
<img class="cover" src="/media/photo-400x250.jpg" alt="cover">
<img class="contain" src="/media/photo-400x250.jpg" alt="contain">
</div>| Value | Result |
|---|---|
fill | Stretches, the proportions break (the default) |
cover | Fills the whole frame, the excess is cut off |
contain | Fits completely, empty margins remain |
Choosing a file: srcset and sizes
The srcset attribute lists several versions of one picture with their widths — 400w means "a file 400 pixels wide". The sizes attribute hints how wide the picture will be on the page. The browser downloads the most suitable file by itself:
<style>
img { max-width: 100%; height: auto; }
</style>
<img
src="/media/photo-800x500.jpg"
srcset="/media/photo-400x250.jpg 400w,
/media/photo-800x500.jpg 800w"
sizes="(max-width: 500px) 100vw, 500px"
alt="A river in the mountains" width="800" height="500">The sizes value reads like this: on a screen up to 500 pixels the picture is as wide as the window, otherwise it is 500 pixels. How images affect loading speed is covered in the lesson "Page speed".
The picture element
<picture> is needed when different screens show different pictures — for example, a wide shot on a computer and a square one on a phone. The browser takes the first <source> whose media condition matches, and <img> serves as the fallback:
<picture>
<source media="(min-width: 600px)" srcset="/media/photo-600x200.jpg">
<img src="/media/photo-200x200.jpg" alt="A river in the mountains">
</picture>The narrow square shot appears if you narrow the browser window until the example is under 600 pixels wide.
Common mistake
Giving an image width: 100% and a fixed height produces a squashed photo:
<style>
.bad { width: 100%; height: 120px; }
.good { width: 100%; height: 120px; object-fit: cover; }
</style>
<img class="bad" src="/media/photo-800x500.jpg" alt="Squashed">
<img class="good" src="/media/photo-800x500.jpg" alt="Neatly cropped">Either keep height: auto, or add object-fit: cover.