Skip to content
easeweb
Search topics

Audio description with no gap to say what is shown

The roaster talks without a break over the cooling and pouring cards, so the described version fits only the first card's description and never pauses.

WCAG 2.2
SC 1.2.7AAA
Required by
Not required by Section 508 or EN 301 549
Broken
The accessibility problem illustrated: No vision:How long does the water cool?
01

The problem

People who can't see the video hear the first amount, then never learn the cooling time or when to stop pouring

02

Try it

Hide the picture, turn on audio description and play the video. How long does the water cool?

The switch covers the picture, as for someone who can’t see it; the player’s controls stay. The Audio description button is under the player, and what the soundtrack says is listed under the video.

Apply a fix to hear an extended version that holds the picture while the describer speaks, or a player that reads each description in your device’s voice and pauses when one runs over its gap.

Broken Can you fix this?

BrokenA described version that runs out of pauses

How to brew our house blend

Talked through by our roaster · waiting times are shortened.

What the soundtrack says

  • Narrator: Here’s how to brew our house blend.
  • Narrator: Weigh it out like this.
  • Narrator: Then let the water rest a moment. Straight off the boil, it scorches the grounds.
  • Narrator: Pour slowly, and stop here. Keep the stream thin, and let the grounds settle as you go.
  • [Kitchen timer rings]

A recreated demo. The broken version is intentionally inaccessible.

03

The fix

Hold the picture while the describer speaks

Before
BrokenA described version that runs out of pauses
<video id="brew-video" controls preload="metadata"  src="brew-talk.webm" poster="brew-talk.jpg"  data-described="brew-talk.described.webm">  <track kind="captions" srclang="en" label="English"    src="brew-talk.en.vtt" data-described="brew-talk.described.en.vtt"></video><button type="button" id="describe" aria-pressed="false">  Audio description</button> <script>  const video = document.getElementById('brew-video');  const track = video.querySelector('track');  const plain = { video: video.getAttribute('src'), captions: track.getAttribute('src') };  document.getElementById('describe').addEventListener('click', (event) => {    const button = event.currentTarget;    const on = button.getAttribute('aria-pressed') !== 'true';    const { currentTime, paused, playbackRate } = video;    const captions = track.track.mode;    video.src = on ? video.dataset.described : plain.video;    track.src = on ? track.dataset.described : plain.captions;    // Carry on from the same moment, at the same speed, with the captions as they were.    video.addEventListener('loadedmetadata', () => {      video.currentTime = currentTime;      video.playbackRate = playbackRate;      track.track.mode = captions;      if (!paused) video.play();    }, { once: true });    button.setAttribute('aria-pressed', String(on));  });</script>
What is wrong3 points

The button and the switch are right, and the first description is too. The captions file of the described version shows where it stops.

  • After the first card, each line of narration starts within about half a second of the last one ending, so there is no gap long enough for a description.
  • So the described version never says "Cool 30 s after boiling", or "Pour in 3 stages, stop at 3:00".
  • The video never holds to make room, and no extended version is offered.
After

An extended version, with the picture held

<video id="brew-video" controls preload="metadata"  src="brew-talk.webm" poster="brew-talk.jpg"  data-described="brew-talk.extended.webm"  data-holds="[[14.64, 3.02], [20.1, 3.7]]">  <track kind="captions" srclang="en" label="English"    src="brew-talk.en.vtt" data-described="brew-talk.extended.en.vtt"></video><button type="button" id="describe" aria-pressed="false">  Audio description</button> <script>  const video = document.getElementById('brew-video');  const track = video.querySelector('track');  const plain = { video: video.getAttribute('src'), captions: track.getAttribute('src') };  // Where the extended version holds the picture: a time in the original, and seconds held.  const holds = JSON.parse(video.dataset.holds);  const toExtended = (time) => time + holds    .filter(([at]) => at < time)    .reduce((sum, [, held]) => sum + held, 0);  const toOriginal = (time) => {    let shift = 0;    for (const [at, held] of holds) {      if (time < at + shift) break;      // Inside a hold, go back to where it began.      shift += Math.min(held, time - at - shift);    }    return time - shift;  };  document.getElementById('describe').addEventListener('click', (event) => {    const button = event.currentTarget;    const on = button.getAttribute('aria-pressed') !== 'true';    const { currentTime, paused, playbackRate } = video;    const captions = track.track.mode;    video.src = on ? video.dataset.described : plain.video;    track.src = on ? track.dataset.described : plain.captions;    // Carry on from the same moment, at the same speed, with the captions as they were.    video.addEventListener('loadedmetadata', () => {      video.currentTime = on ? toExtended(currentTime) : toOriginal(currentTime);      video.playbackRate = playbackRate;      track.track.mode = captions;      if (!paused) video.play();    }, { once: true });    button.setAttribute('aria-pressed', String(on));  });</script>
How it is fixed4 steps
  1. Edit an extended version of the described video (W3C technique G8). Where a description has no gap, hold the picture on a frame that still shows what it describes, play the description over the held frame, then let the video carry on. Here the picture holds twice, just after the roaster's line over the second and third cards, for 3.02 and 3.7 seconds.
  2. Give it its own captions file, with each description marked as the describer's at the time it is heard.
  3. Point the Audio description button at the extended files instead of the described ones.
  4. List the holds on the video, in data-holds, so the script can map a place in one file to the same moment in the other: the extended version is longer, so the same moment comes later in it.

This fixes the Before and passes 1.2.7. The descriptions are recorded, so they sound the same in every browser, and the file plays in any player, including on a video platform that has no audio description feature of its own.

04

Verify the fix

4 checks, no mouse.

Test with: Screen off, Keyboard, Screen reader

0 of 4 checked

Record the OS, browser and assistive-technology versions, the build, the date, and the actual result of each step. Repeat whenever the video, its narration or its descriptions are replaced.

Limits

This is a starting pattern, not a guarantee for every application. Whether a video needs extended description, and what each description should say, depends on the video: this guide can't judge that for you. Extended audio description is Level AAA, so most laws and policies that cite WCAG at Level AA don't require it; it is still the only way some videos make sense without the picture. Test the complete journey with people who will listen to it, in the players and platforms the video really plays in.

This is a recreated teaching example, not a finding about a named client. The code is a starting pattern: test it in your own product. No completed assistive-technology test is claimed here.

EaseWeb service

Fixed it? Keep it from coming back.

I turn guides like this one into rules your coding agents follow and checks your CI runs. Then I retest by hand with a keyboard and screen readers, periodically.

See the service