# Responsive images

srcset, sizes en picture

Multimedia & Creatieve Technologie · 2.1 Web production · Bite · versie 1.3.1 · 2026-10-21

Tags: html, responsive, performance

Slides: <https://slides.mctantwerp.be/nl/web-production/responsive-images>

Speaker notes: <https://slides.mctantwerp.be/nl/web-production/responsive-images.notes.md>

<!-- slide 2 -->

## Eén beeld op mobiel en desktop

```html
<img src="campus.jpg"
     alt="Studenten op een bank">
```

```css
img {
  max-width: 100%;
  height: auto;
}
```

Dit werkt. De foto schaalt mee en houdt haar verhouding.

Maar elk toestel downloadt hetzelfde bestand. Een grote foto is scherp op desktop en kost op een telefoon onnodig veel data.

Een kleine foto laadt snel, maar wordt wazig zodra ze breder staat dan het bestand.

<!-- slide 3 -->

## Twee opties

**1 Dezelfde foto in meerdere groottes**: In `srcset` staan de bestanden die er zijn, in `sizes` hoe breed de foto op de pagina staat. De browser kiest zelf het bestand.

**2 Zelf kiezen met picture**: Met `picture` beslis jij welk bestand wanneer laadt: een WebP voor een browser die het kent, of een staande uitsnede op mobiel.

<!-- slide 4 -->

## Optie 1: dezelfde foto in meerdere groottes

Je exporteert dezelfde foto in een paar breedtes. Een telefoon laadt dan een klein bestand, een groot scherm krijgt genoeg detail.

| Bestand | Afmetingen | Beeldverhouding |
| --- | --- | --- |
| campus-480.jpg | 480 × 320 pixels | 3:2 |
| campus-960.jpg | 960 × 640 pixels | 3:2 |
| campus-1440.jpg | 1440 × 960 pixels | 3:2 |

<!-- slide 5 -->

## srcset: welke bestanden zijn er?

```html
<img
  src="campus-960.jpg"
  srcset="campus-480.jpg 480w,
          campus-960.jpg 960w,
          campus-1440.jpg 1440w"
  alt="Studenten op een bank">
```

1. `src` blijft staan, als fallback voor een browser die srcset niet kent.
2. `srcset` begint de lijst. `480w` betekent: dit bestand is 480 pixels breed. Het is geen breakpoint.
3. Na de komma volgt de volgende versie: dezelfde foto, 960 pixels breed.
4. De grootste versie, 1440 pixels breed. De browser kiest er één uit, hij downloadt ze niet allemaal.

<!-- slide 6 -->

## sizes: hoe breed staat de foto?

```css
img {
  width: 100%;
  max-width: 600px;
  height: auto;
}
```

```html
sizes="(width >= 600px) 600px,
       100vw"
```

In de CSS is de foto zo breed als het venster, tot maximaal 600px. In sizes schrijf je hetzelfde nog eens.

1. Vanaf een venster van 600px breed staat de foto 600px breed. De voorwaarde gaat over het venster, niet over de foto.
2. Daaronder geldt `100vw`, de volle breedte van het venster. De laatste waarde heeft geen voorwaarde en geldt voor de rest.

Waarom twee keer? De browser kiest de foto al terwijl de HTML binnenkomt, voor hij je CSS gelezen heeft.

<!-- slide 7 -->

## De volledige img

```html
<img
  src="campus-960.jpg"
  srcset="campus-480.jpg 480w,
          campus-960.jpg 960w,
          campus-1440.jpg 1440w"
  sizes="(width >= 600px) 600px,
         100vw"
  width="1440" height="960"
  alt="Studenten op een bank">
```

1. De bestanden waaruit de browser kan kiezen, met hun werkelijke breedtes.
2. Vanaf een venster van 600px rekent de browser met een foto van 600px breed.
3. Op een smaller venster rekent hij met de volle vensterbreedte.
4. `width` en `height` geven de verhouding mee (3:2), zodat de browser plaats vrijhoudt voor de foto geladen is. De CSS bepaalt nog altijd hoe breed ze staat.
5. `alt` blijft hetzelfde, welk bestand de browser ook kiest.

<!-- slide 8 -->

## Een klein scherm vraagt soms toch veel pixels

DPR (device pixel ratio) is het aantal schermpixels per CSS-pixel. Bij DPR 2 heeft een foto van 390 CSS-pixels breed een bestand van ongeveer 780 pixels nodig om scherp te zijn.

| Foto op de pagina | Scherm | Benodigde pixels | Passende versie |
| --- | --- | --- | --- |
| 390px breed | DPR 1 | 390 × 1 = 390 | 480w |
| 390px breed | DPR 2 | 390 × 2 = 780 | 960w |
| 600px breed | DPR 2 | 600 × 2 = 1200 | 1440w |

Je eigen DPR: typ `window.devicePixelRatio` in de console.

<!-- slide 9 -->

## Hetzelfde beeld, een ander bestand

De browser rekent breedte × DPR en neemt het kleinste bestand dat groot genoeg is. Met sizes is de foto hooguit 600px: 960w op DPR 1, 1440w op DPR 2. Zonder sizes rekent hij met het hele venster.

De foto groeit mee tot maximaal 600px. De bestandsnaam toont welke resolutie de browser kiest, met en zonder sizes.

<!-- slide 10 -->

## Een foto staat 300px breed op een telefoon met DPR 3. Welk bestand kiest de browser?

```html
srcset="campus-480.jpg 480w,
        campus-960.jpg 960w,
        campus-1440.jpg 1440w"
```

- A. campus-480.jpg
- B. campus-960.jpg
- C. campus-1440.jpg

**Antwoord:** B. campus-960.jpg

300 × 3 = 900 pixels. 480w is te klein, 960w is het kleinste bestand dat groot genoeg is. De browser mag afwijken, bijvoorbeeld als hij 1440w al in zijn cache heeft.

<!-- slide 11 -->

## Optie 2: meer controle met picture

**Een ander bestandsformaat**: Je exporteert de foto ook als WebP, een formaat dat meestal kleiner is dan jpg. Een browser die WebP kent, krijgt die versie, de rest de jpg.

**Een andere uitsnede of verhouding**: Op mobiel een staande close-up, vanaf een breakpoint de liggende foto. Elk bestand mag een andere verhouding hebben.

<!-- slide 12 -->

## WebP met een jpg als fallback

```html
<picture>
  <source
    type="image/webp"
    srcset="campus.webp">
  <img src="campus.jpg"
       width="1440" height="960"
       alt="Studenten op een bank">
</picture>
```

1. `picture` groepeert de alternatieven voor één afbeelding.
2. `source` biedt een alternatief aan. Die komt vóór de img.
3. `type="image/webp"` zegt: gebruik deze bron als de browser WebP ondersteunt.
4. `srcset` geeft het WebP-bestand. Op source heet dit srcset, ook als er maar één bestand is.
5. Ondersteunt de browser WebP niet, dan gebruikt hij de jpg uit `src` op de img.
6. De afmetingen en alt blijven op img. In dit voorbeeld hebben beide bestanden dezelfde verhouding.

<!-- slide 13 -->

## Meerdere formaten: de volgorde telt

```html
<picture>
  <source type="image/avif"
          srcset="campus.avif">
  <source type="image/webp"
          srcset="campus.webp">
  <img src="campus.jpg"
       alt="Studenten op een bank">
</picture>
```

1. Eerst AVIF. Ondersteunt de browser dat formaat, dan gebruikt hij deze bron.
2. Anders probeert hij de volgende bron: WebP.
3. Past geen source, dan toont de img de jpg. Er verschijnt altijd maar één afbeelding.

<!-- slide 14 -->

## Art direction: een andere uitsnede op mobiel

![Staande close-up van twee studenten op een bank](https://slides.mctantwerp.be/decks/nl/web-production/04-responsive/campus-stories/images/campus-close.jpg)

Mobiel: een staande close-up, 600 × 800 pixels. Verhouding 3:4.

![Liggend beeld van de studenten met meer campusomgeving](https://slides.mctantwerp.be/decks/nl/web-production/04-responsive/campus-stories/images/campus-wide.jpg)

Desktop: het liggende beeld, 1200 × 800 pixels. Verhouding 3:2.

<!-- slide 15 -->

## Vanaf 640px een liggende foto

```html
<picture>
  <source
    media="(width >= 640px)"
    srcset="campus-wide.jpg"
    width="1200" height="800">
  <img src="campus-close.jpg"
       width="600" height="800"
       alt="Studenten op een bank">
</picture>
```

1. Een source vóór de img, zoals bij de formaten.
2. `media` geeft de voorwaarde: het venster is minstens 640px breed.
3. Als die voorwaarde klopt, wordt campus-wide.jpg gebruikt.
4. Dit bestand is liggend: 1200 × 800 pixels, dus 3:2.
5. Onder 640px wordt geen source gekozen. Dan gebruikt img de close-up in haar eigen src.
6. De close-up is staand: 600 × 800 pixels, dus 3:4. De alt past bij beide uitsnedes.

<!-- slide 16 -->

## Een andere foto én een andere verhouding

Onder 640px verschijnt de staande close-up. Vanaf 640px verschijnt de liggende foto. Ook de beeldverhouding verandert.

<!-- slide 17 -->

## srcset of picture

|   | srcset en sizes | picture |
| --- | --- | --- |
| Wie kiest | De browser, hij mag afwijken | Jij, de eerste source die past |
| Wat verandert | De resolutie van dezelfde foto | Het formaat of de uitsnede |
| Voorwaarde | De breedte in sizes en de DPR | `type` of `media` op een source |
| Wanneer | Bijna elke foto | WebP met een jpg erbij, een andere crop op mobiel |

<!-- slide 18 -->

## Controleren wat er geladen wordt

In DevTools toont Network met het filter Img welk bestand geladen wordt en hoeveel kB het kost.

Test je een andere breedte, zet dan Disable cache aan en herlaad. Anders houdt de browser een groot bestand vast dat al geladen is.

[MDN: Responsive images](https://developer.mozilla.org/en-US/docs/Web/HTML/Guides/Responsive_images)

```js
const foto = document.querySelector('img');
foto.currentSrc;
```

1. De eerste img op de pagina ophalen.
2. `currentSrc` toont de URL van het bestand dat de browser echt gekozen heeft.

<!-- slide 19 -->

## Opdracht: Dezelfde foto, minder data

*10 minuten, Alleen*

De foto vult een artikel van maximaal 720px breed. De starter bevat de CSS en de url's van de foto's.

1. Open en bewaar de starter in CodePen
2. Voeg srcset toe met de versies van 480, 960 en 1440 pixels breed
3. Voeg sizes toe op basis van de breedte in de CSS
4. Kijk in de Network-tab welk bestand laadt bij een smal en een breed resultaatvenster, met de cache uit

Een knop die een nieuwe pen op CodePen opent met de starter "Responsive images: het juiste bestand" (HTML en CSS).

<!-- slide 20 -->

## Opdracht: Een andere vorm op mobiel

*5 minuten, Alleen*

Werk verder in dezelfde CodePen. Onder 640px moet de staande close-up verschijnen.

1. Zet picture rond de img, met een source ervoor die vanaf 640px geldt
2. Verplaats srcset en sizes naar die source, met width 1440 en height 960
3. Geef img campus-close.jpg als src, zonder srcset of sizes, met width 600 en height 800
4. Maak het resultaatvenster smaller en breder rond 640px en kijk of de uitsnede wisselt

## Begrippen

- **DPR**: Device pixel ratio, het aantal schermpixels per CSS-pixel. Op DPR 2 heeft een afbeelding van 320 CSS-pixels breed een bestand van ongeveer 640 pixels nodig om scherp te zijn. (slide 8)
- **srcset**: Een lijst met bestanden van dezelfde afbeelding. 480w en 960w geven de echte breedte van elk bestand in pixels aan. De browser kiest er één. (slide 5)
- **sizes**: Geeft de browser vooraf een verwachte breedte van de afbeelding in de layout. De eerste voorwaarde die klopt, wint. Zonder sizes rekent hij met 100vw. (slide 6)
- **Art direction**: Een andere crop van een afbeelding tonen op een andere breedte, met picture en een source met media. (slide 14)
- **picture**: Een element rond een img met een of meer source-elementen. De browser neemt de eerste source die past, op media of op type. Binnen de gekozen source kan de browser nog een resolutie uit srcset kiezen. (slide 11)

## Links en bronnen

### In de presentatie

- [MDN: Responsive images](https://developer.mozilla.org/en-US/docs/Web/HTML/Guides/Responsive_images) (slide 18)

### Bronnen

- [MDN: img, srcset en sizes](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/img)
- [MDN: picture](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/picture)
- [MDN: Afbeeldingsformaten](https://developer.mozilla.org/en-US/docs/Web/Media/Guides/Formats/Image_types)
