Advanced Media
Images and video are usually the heaviest part of a page by an order of magnitude. This lesson is the markup that decides how much of that weight the visitor actually pays for.
picture, srcset and sizes, decided properly
Three mechanisms, and choosing between them is the whole skill.
Same image, different sizes - srcset with sizes. The browser decides.
<img src="library-800.jpg"
srcset="library-400.jpg 400w, library-800.jpg 800w, library-1600.jpg 1600w"
sizes="(max-width: 700px) 100vw, 700px"
alt="Students working at laptops in the library"
width="800" height="450">
Open this example in the editor and change it. Nothing you type is saved.
Same image, different formats - picture with type. The browser takes the first it supports.
<picture>
<source srcset="library.avif" type="image/avif">
<source srcset="library.webp" type="image/webp">
<img src="library.jpg" alt="Students working at laptops in the library"
width="800" height="450">
</picture>
Open this example in the editor and change it. Nothing you type is saved.
Different image entirely - picture with media. You decide.
<picture>
<source media="(min-width: 800px)" srcset="team-wide.jpg">
<img src="team-portrait.jpg" alt="The six people who built this course"
width="400" height="600">
</picture>
Open this example in the editor and change it. Nothing you type is saved.
The rule for which to reach for: if the browser could work it out, let it - that is srcset. If the decision depends on something only you know, like which crop reads better on a phone, that is picture with media.
In all three the img is required and carries the alt. picture and source select a file; they do not replace the image element.
Optimisation, in order of effect
The order matters because the first item usually outweighs the rest combined.
1. Resize to the real display size. A 4000-pixel photograph displayed in a 600-pixel column is about forty times the bytes needed. No compression setting recovers that.
2. Choose the format. AVIF or WebP for photographs, SVG for anything drawn, PNG only for screenshots and transparency that WebP cannot better.
3. Compress. Quality 75 to 85 is usually indistinguishable from 100 at a fraction of the size.
4. Strip metadata. Camera files carry EXIF - GPS coordinates included, which is a privacy matter as well as a size one.
5. Serve several sizes. Then srcset as above.
For video: the single biggest win is deciding not to host it. A plain video element serves one file at one bitrate to everybody; a dedicated host serves adaptive streams that adjust to the connection. For short loops and clips, self-hosting is simpler and faster.
Loading priority
<img src="hero.jpg" alt="The campus at dusk"
width="1200" height="600" fetchpriority="high">
<img src="footer-map.png" alt="" width="400" height="300" loading="lazy">
<iframe src="https://maps.example.com/embed" title="Map of the campus"
loading="lazy" style="width: 100%; aspect-ratio: 4 / 3; border: 0"></iframe>
Open this example in the editor and change it. Nothing you type is saved.
loading="lazy" defers a fetch until the element is near the viewport. It belongs on everything below the fold and on nothing above it: lazy-loading the hero image delays the exact thing whose speed is being measured.
fetchpriority="high" tells the browser to prioritise an image it would otherwise treat as ordinary. Reserve it for the one image that defines the page - usually the largest element visible on load.
And the easiest win of all is still width and height on every image. They reserve the space, so nothing shifts as images arrive.
Making video fit
A video scales with two CSS declarations and one markup habit.
<figure style="max-width: 720px">
<video controls playsinline preload="metadata"
poster="walkthrough-preview.jpg"
width="1280" height="720"
style="width: 100%; height: auto">
<source src="walkthrough.webm" type="video/webm">
<source src="walkthrough.mp4" type="video/mp4">
<track kind="captions" src="walkthrough-en.vtt" srclang="en" label="English" default>
<p>Your browser cannot play this video.
<a href="walkthrough.mp4">Download it</a>.</p>
</video>
<figcaption>A walkthrough of the finished project</figcaption>
</figure>
Open this example in the editor and change it. Nothing you type is saved.
width and height give the aspect ratio so the space is reserved; width: 100% and height: auto let it scale inside its container. Both halves are needed: the attributes stop the layout jumping, the CSS stops the video overflowing.
preload="metadata" fetches enough to show the duration and let the scrubber work, and no more. preload="auto" on a page with three videos starts downloading all three.
poster matters more than it looks. Without one, a browser shows either a blank box or the first frame, and the first frame of most videos is black.
Media accessibility, properly
<figure>
<video controls width="640" poster="lecture-preview.jpg" preload="metadata">
<source src="lecture.webm" type="video/webm">
<source src="lecture.mp4" type="video/mp4">
<track kind="captions" src="lecture-en.vtt" srclang="en" label="English" default>
<track kind="descriptions" src="lecture-ad.vtt" srclang="en" label="Audio descriptions">
<p>Your browser cannot play this video.
<a href="lecture.mp4">Download it</a>.</p>
</video>
<figcaption>Lecture 3: how the parser builds a tree</figcaption>
</figure>
<details>
<summary>Read the transcript</summary>
<p><strong>Lena:</strong> The parser never refuses. That is the thing to
hold on to.</p>
</details>
Open this example in the editor and change it. Nothing you type is saved.
Captions for people who cannot hear it. Descriptions for people who cannot see it. A transcript for everyone else, and for search engines. Keyboard-operable controls, which the browser's own already are.
And one rule that is easy to break by accident: do not let audio be the only carrier of information. A video whose crucial number is only spoken aloud is a video that number is missing from, for a lot of people and in every noisy room.
autoplay deserves its own warning here. It is blocked unless muted, it costs the visitor data they did not ask to spend, and an autoplaying video with sound is the most complained-about behaviour on the web. If a clip must play on its own, it should be muted, short, looping and decorative.
Alt text at scale
A page with fifty images is where alt text stops being a per-image decision and becomes a policy. Four categories cover almost everything.
<article>
<h2>Quarterly review</h2>
<img src="chart.png" width="600" height="300"
alt="Revenue rose each quarter, from 1.2 million in Q1 to 2.1 million in Q4.">
<p>
<a href="/report.pdf">
<img src="pdf-icon.svg" alt="Download the full report (PDF)"
width="24" height="24">
</a>
</p>
<p>
<img src="tick.svg" alt="" width="16" height="16"> Target met
</p>
<figure>
<img src="office.jpg" alt="The Doha office on opening day, with staff on the terrace"
width="800" height="500">
<figcaption>The Doha office, March 2026</figcaption>
</figure>
</article>
Open this example in the editor and change it. Nothing you type is saved.
Informative - the alt is the information, not a description of the picture. A chart's alt is its finding.
Functional - an image that is a link or a button gets the action, not the appearance.
Decorative - alt="", present and empty. The tick is next to the words "Target met", so repeating it is noise.
Complex with a caption - the alt says what it shows, the figcaption says what it is for, and they should not be the same sentence or it is read twice.
The one rule that resolves most arguments: cover the image and ask what you would write in its place.
Practice task
Take a page with three images and do the arithmetic: open the Network panel, note the transferred size of each, then check its displayed size in the Elements panel. Resize any image that is more than twice its display width, add width and height to all three, loading="lazy" to the ones below the fold, and fetchpriority="high" to the hero. Reload and compare the totals.