HTML & CSS · Lesson 3 of 13
Images, Media and Accessibility
Add images, video and audio to HTML the right way, write useful alt text, and make pages accessible with landmarks, ARIA basics and keyboard support.
- Beginner
- 16 min read
- 4 objectives
Before this lessonLesson 2: Forms and Semantic HTML
What you will learn
- Choose the right image format and write alt text that actually helps
- Embed video and audio with captions and sensible defaults
- Use figure, picture and lazy loading correctly
- Test a page with only the keyboard and fix common accessibility gaps
Your Progress
0 of 13 lessons 0%
- Lessons0 / 13
- Completed0
- Est. time left~ 4 hours
Create a free account to keep your progress on every device.
Tip: pressing Next marks this lesson complete automatically.
A page is more than text. Photos, diagrams, product shots, screencasts and podcasts make content easier to understand, but only if everyone can use them. Roughly one in six people lives with some form of disability, and many more use a screen reader, keyboard, zoom or captions some of the time (think of watching a video on a quiet train). Accessibility is simply making sure your page works for all of them.
The good news is that most accessibility comes for free when you use the right HTML element and fill in a few attributes. This lesson covers media elements first, then the accessibility habits that go with them.
Images: formats and the img element
An image needs a source, alternative text, and ideally its dimensions. Setting width and height lets the browser reserve space before the file downloads, so the text below does not jump around (this jump is called layout shift).
<img
src="/images/ada-at-desk.webp"
alt="Ada pair-programming with a teammate at a standing desk"
width="1200"
height="800"
loading="lazy"
decoding="async">- WebP / AVIF: modern formats for photos, much smaller than JPEG at the same quality. Supported by every current browser.
- JPEG: the safe fallback for photos.
- PNG: screenshots and images that need sharp edges or transparency.
- SVG: logos, icons and diagrams. It is vector, so it stays crisp at any size and is usually tiny.
loading="lazy" tells the browser to wait until the image is near the viewport before downloading it. Use it for images further down the page, but not for the main image at the top, which should load immediately.
Writing alt text that helps
The alt attribute is read aloud by screen readers and shown if the image fails to load. Good alt text describes what the image means in context, not every pixel.
- Informative image: describe the content.
alt="Bar chart: sign-ups doubled from March to June". - Image inside a link or button: describe the action. A magnifying glass icon becomes
alt="Search". - Decorative image (a background swirl, a divider): use an empty
alt=""so screen readers skip it. - Never start with "Image of" or "Picture of"; the screen reader already announces that it is an image.
figure, figcaption and picture
When an image has a visible caption, wrap both in <figure>. The caption is then linked to the image for assistive technology. <figure> works for code samples, charts and quotes too.
<figure>
<img src="/images/latency-chart.svg" alt="Line chart of API latency falling from 400ms to 120ms" width="800" height="400">
<figcaption>API latency after adding a cache layer, week 1 to week 6.</figcaption>
</figure><picture> lets you offer several formats and let the browser pick the best one it supports. The inner <img> is required: it is the fallback and it carries the alt text.
<picture>
<source srcset="/images/hero.avif" type="image/avif">
<source srcset="/images/hero.webp" type="image/webp">
<img src="/images/hero.jpg" alt="The stackcone dashboard on a laptop" width="1600" height="900">
</picture>Video and audio
The <video> and <audio> elements play media natively, no plugin needed. Add controls so users can pause and adjust volume. A <track> element adds captions from a WebVTT file, which helps deaf users, people in noisy places and non-native speakers.
<video controls width="960" height="540" preload="metadata" poster="/video/intro-poster.jpg">
<source src="/video/intro.webm" type="video/webm">
<source src="/video/intro.mp4" type="video/mp4">
<track kind="captions" src="/video/intro.en.vtt" srclang="en" label="English" default>
Your browser does not support video. <a href="/video/intro.mp4">Download the video</a>.
</video>
<audio controls preload="none">
<source src="/audio/episode-12.mp3" type="audio/mpeg">
</audio>preload="metadata"fetches only duration and size, saving bandwidth until the user presses play.postershows an image before playback starts.- Autoplay is blocked by browsers unless the video is also
muted. Background videos should beautoplay muted loop playsinline, and should never carry important information. - For podcasts and talks, link a text transcript near the player.
Landmarks and headings
Screen reader users navigate by jumping between landmarks and headings, much like sighted users skim. Semantic elements such as <header>, <nav>, <main> and <footer> (covered in the forms and semantics lesson) create those landmarks automatically. Two extra habits make them useful:
- Use exactly one
<h1>per page and do not skip levels (h2 then h4) just to get a smaller font. Style size with CSS instead. - Add a "skip to content" link as the first focusable element so keyboard users can jump past the navigation.
<body>
<a class="skip-link" href="#main">Skip to content</a>
<header>...</header>
<nav aria-label="Primary">...</nav>
<main id="main">
<h1>Pricing</h1>
...
</main>
</body>ARIA: the last resort
ARIA attributes (aria-label, aria-expanded, role and friends) add extra meaning for assistive technology. They are powerful, but the first rule of ARIA is: if a native HTML element does the job, use it instead. A <button> is focusable, clickable with Enter and Space, and announced as a button. A <div onclick> is none of those things until you add a pile of ARIA and JavaScript.
<!-- Bad: looks like a button, but keyboard and screen reader users cannot use it -->
<div class="btn" onclick="openMenu()">Menu</div>
<!-- Good: native button, plus state for the screen reader -->
<button type="button" aria-expanded="false" aria-controls="site-menu">Menu</button>
<!-- Icon-only button: give it an accessible name -->
<button type="button" aria-label="Close dialog">
<svg aria-hidden="true" width="16" height="16">...</svg>
</button>Keyboard, focus and contrast
Put your mouse away and press Tab through your page. You should be able to reach every link, button and form field, in a logical order, and always see where focus is. The most common bug is CSS that removes the focus ring:
/* Never do this without a replacement */
button:focus { outline: none; }
/* Do this: a clear ring for keyboard users only */
:focus-visible {
outline: 3px solid #2563eb;
outline-offset: 2px;
}Also check colour contrast. WCAG 2.2 asks for at least 4.5:1 between normal text and its background (3:1 for large text). Browser DevTools shows the ratio when you inspect a colour, and Lighthouse flags failures automatically.
Recap
- Give every image an
alt(empty for decoration) pluswidthandheightto avoid layout shift. - Prefer WebP/AVIF for photos and SVG for icons; use
<picture>for format fallbacks andloading="lazy"below the fold. - Video needs
controlsand captions via<track>; autoplay only works muted. - Native elements beat ARIA; use ARIA to name icon buttons and expose state.
- Test with the keyboard, keep a visible
:focus-visiblestyle, and meet 4.5:1 contrast.
// Write your solution here
Finished reading? Mark this lesson complete to track your progress.
