1 of 23

a11y &

video controls

Chris Callahan

Software Engineer, Video

The New York Times

09.21.2017

2 of 23

Overview

  • The Problem
  • Progress
  • Challenges
  • Next Steps

3 of 23

The Problem

4 of 23

Videos are not accessible on nytimes.com

semantic markup

text descriptions

keyboard controls

focus styles

5 of 23

Demo

6 of 23

7 of 23

So what?

👋💰💰💰

  • accessibility laws => missing out on many bulk subscribers

Bad UX

  • ignoring different types of users with different needs at different times

8 of 23

Progress

9 of 23

Keyboard accessible controls

Semantic markup

  • use <button>, <input>, and friends where possible
  • otherwise use ARIA attributes and tabindex

  • add title attribute for screen readers

10 of 23

<button

class=”...”

title=”Play”

aria-label=”Play”

>

</button>

11 of 23

<input

class=”...”

type=”range”

title=”Adjust Volume”

aria-label=”Adjust Volume”

min=”0”

max=”100”

step=”10”

value=”100”

aria-valuemin=”0”

aria-valuemax=”100”

aria-valuenow=”100”

/>

12 of 23

Keyboard accessible controls

Keyboard controls

  • add keydown event handlers to all keyboard controllable elements
  • update markup on keyboard events

Custom focus styles

  • on brand
  • designer-approved

13 of 23

Demo

14 of 23

15 of 23

Challenges

16 of 23

Technical challenges

Media playback and focus

  • the spacebar toggle plugin is focusing the container on playback
  • we want to retain focus on keyed elements

Impacted elements

  • play/pause button
  • toggle HD on/off

17 of 23

// event listener setup

element.addEventListener(‘focus’, () => {

this.focusedElement = element;

});

element.addEventListener(‘blur’, () => {

this.focusedElement = null;

});

// media playback hook

const lastFocusedElement = this.focusedElement;

if (lastFocusedElement) {

setTimeout(() => {

lastFocusedElement.focus();

}, 0);

}

18 of 23

Technical challenges

Focus styles

  • applied during keyboard navigation
  • removed during mouse navigation
  • keep designers happy

19 of 23

const onMousedown = (e) => {

e.preventDefault();

if (this.focusedElement) {

this.focusedElement.blur();

this.focusedElement = null;

}

};

elements.forEach((element) => {

element.addEventListener(

‘mousedown’, onMousedown);

});

20 of 23

Technical challenges

Bug with `input` events on <input type=”range”>

  • getting a stale value for `e.target.value` on keydown events
  • reproduced on codepen

Temporary solution

  • use a <div> with role=”slider” and ARIA attributes

21 of 23

<div

class=”...”

title=”Seek”

tabindex=”0”

role=”slider”

aria-label=”Seek”

aria-valuemin=”0”

aria-valuemax=”150”

aria-valuenow=”0”

aria-valuetext=”0:00 of 2:30”

>

</div>

22 of 23

Organizational challenges

Getting team buy-in

  • open JIRA tickets and github issues
  • a11y sprint on our JIRA board 🎉

  • keep a11y in mind when implementing new UI elements
  • work with designers

23 of 23

Next steps

  • make the entire player accessible
  • + audio player
  • other initiatives