How accessible is the HTML video player?
Part of my day-to-day is working with teams to guide and test solutions for accessibility. Particularly with our Debut theme (running here on my blog and store), which I’ve been working with our Themes team to ensure a highly accessible experience for stores running this theme. Anything that gets added must be tested for accessibility pre-launch.
A new feature Shopify is starting to roll out is video for products. Video content, along with product imagery, will help to showcase product details in a dynamic fashion.
For the video player we decided to ship Plyr as the default. I made this recommendation to the team based on a few key criteria:
- Support of multiple platforms; native HTML, YouTube, and Vimeo
- Theme-able in order to have a custom look to "blend-in" with a storefront theme
- Open source (handy if and when we send some PRs), and finally
- Plyr was built with accessibility in mind
Other custom accessible video players were considered, but did not support all the features we required.
Some folks asked for more details on why we decided to go with Plyr as opposed to the native HTML video
player.
"How is Plyr more accessible than native players? Isn't HTML
video
accessible already?"
To answer this question I set out to conduct a series of tests for native video
player accessibility. This included various operating systems, browsers, and screen readers. The results are pretty much what I expected.
Tl;dr
In case you don’t make it all the way to the bottom, I feel, based on the results of testing each player (and comparing to my own Accessible Video Player project), that relying on native video players should be used with caution. This is my opinion stemming from experience, but I found most to have poor keyboard and screen reader support, which may lead to frustrated users.
There were a lot of inconsistencies across the board as far as keyboard and screen reader support. Some lose focus when the video controls receive focus then fade away, forcing the user to re-position themselves to adjust playback. Others did not trap keyboard focus in full-screen mode, leading to a similar situation as an inaccessible modal window allowing content to be accessed "behind" the window. One player in particular featured very awkward keyboard support where controls were visible on the screen but could not be focused.
I did not test either YouTube or Vimeo embedded players on their own. For our case, needing to support multiple platforms, it made sense to only test Plyr as a non-native solution.
Here are the notes on my findings, first using a keyboard alone and then a screen reader for the platform.
Test details
- This is not a comprehensive test – only keyboard and screen reader support has been inspected for accessibility
- Browser / screen reader combinations used during testing are most commonly used (source)
- Test sample:
- Test environment:
- Windows 10
- macOS Mojave
- iOS 13.2.3
- Android 10
- Chrome 79
- Firefox 71
- Internet Explorer 11
- Edge 44
- JAWS 2019.1909.28
- NVDA 2019.2.1
Native video
– Keyboard only
macOS + Safari
- ✅ Starts with one big play button
- ✅ Video is focusable
- ✅ Play button is focusable
- ❌ Focus style somewhat difficult to see
- ✅ Controls fade when in focus, return on Tab
- ❌ Cannot play/pause when video is in focus
- ❌ When opening caption control focus is lost (goes back to top of DOM)
- ❌ Caption menu allows Tab keypress, however, in doing so a selection is not made on Enter or Space – using arrow keys to browse menu allows for a selection to be made
- ❌ Exiting full screen mode results in non-functional controls
macOS/Windows 10 + Chrome
- ✅ Starts with all controls visible and available
- ✅ Each control is focusable
- ✅ Menu can be Tabbed through or use arrow keys
- ✅ Scrubber has arrow key support
- ✅ Focus styles highly visible
- ❌ Controls fade away while playing, focus is lost
- ✅ Can play/pause when video element is in focus
- ✅ Opening CC menu requires a selection, arrow keys, or Esc to continue
- ✅ Exiting from full screen sends focus to the currently selected element
macOS/Windows 10 + Firefox
- ✅ Starts with all controls visible
- ❌ Video element, CC control, and full screen controls are the only focusable elements
- ❌ Menu can be Tabbed through but is at the end of the player DOM
- ✅ Scrubber has left/right arrow key support, volume up/down arrow keys
- ❌ Focus styles difficult to see
- ❌ Controls fade away while playing, while Tabbing, and do no return unless volume is adjusted
- ❌ Can play/pause only when video element is in focus
- ✅ Opening CC menu prevents Tab key press outside of menu, forces selection, arrow keys, or Esc
- ❌ Controls are not available during full screen playback
- ❌ Exiting from full screen, focus is lost
Windows 10 + Edge
- ✅ Starts with all controls visible and available
- ✅ Each control is focusable, including time lapsed/remaining content
- ✅Menu and volume require use of arrow keys
- ✅ Scrubber has arrow key support
- ❌ Focus styles difficult to see
- ✅ Controls do not fade when in focus
- ✅ Can play/pause when video element is in focus
- ✅ Exiting from full screen sends focus to the currently selected element
- ✅ Space pauses video on any input focus
- ✅ Opening CC menu requires a selection, arrow keys, or Esc to continue
Windows 10 + IE11
- ✅ Starts with all controls visible and available, eventually fade
- ✅ Each control is focusable, including time lapsed/remaining content
- ✅ Menu and volume require use of arrow keys
- ✅ Scrubber has arrow key support
- ❌ Focus styles difficult to see
- ✅ Controls do not fade when in focus
- ✅ Can play/pause when video element is in focus
- ✅ Exiting from full screen sends focus to the currently selected element
- ✅ Space pauses video on any input focus
- ✅ Opening CC menu requires a selection, arrow keys, or Esc to continue
Native video
– Screen reader support
macOS + Safari + VoiceOver
- ✅ All controls feature clear labels
- ❌ Video container does not have an accessible name
- ❌ When scrubber is in focus, a continuous announcement is made declaring the time lapsed value
- ❌ When interacting with play, mute, etc, new label/value is not announced
- ❌ Content "behind" full screen video is still accessible
iOS + Safari + VoiceOver
- ✅ All controls feature clear labels via finger only (❌ swipe gestures do not reveal controls)
- ❌ Video container does not have an accessible name
- ❌ When scrubber is in focus, a continuous announcement is made declaring the time lapsed value
- ✅ When interacting with play, mute, etc, new label/value is announced
- ✅ Content "behind" full screen video is not accessible
Android + Chrome + Talkback
- ✅ All controls feature clear labels
- ❌ When video plays, controls fade and do not return
Windows + Chrome + JAWS
- ✅ All controls feature clear labels
- ❌ Video container does not have an accessible name
- ❌ When scrubber is in focus, a continuous announcement is made declaring the time lapsed value
- ✅ When interacting with play, mute, etc, new label/value is announced
- ✅ Content "behind" full screen video is not accessible
Windows + IE11 + JAWS
- ❌ Controls not announced when using the Tab key
- ❌ Video container does not have an accessible name
- ❌ Controls announce but non functional when using virtual cursor
- ✅ Controls announced and functional when navigating via Form control navigation only
- ✅ When scrubber is in focus, an announcement is made declaring the time lapsed value only
- ❌ When interacting with play, mute, etc, new label/value is not announced
- ❌ Content "behind" full screen video is accessible
Windows + Firefox + JAWS
- ❌ Some controls do not feature a label
- ❌ Video container does not have an accessible name
- ❌ A continuous announcement is made declaring the percentage lapsed value when any control has focus
- ❌ When interacting with play, mute, etc, new label/value is not announced
- ❌ Content "behind" full screen video is accessible
Windows + Chrome + NVDA
- ✅ All controls feature clear labels
- ❌ Video container does not have an accessible name
- ❌ When scrubber is in focus, a continuous announcement is made declaring the time lapsed value
- ✅ When interacting with play, mute, etc, new label/value is announced
- ✅ Content "behind" full screen video is not accessible
Windows + IE11 + NVDA
- ❌ Controls not announced when using the Tab key
- ❌ Video container does not have an accessible name
- ❌ Controls not found when navigating via Form control navigation
Windows + Firefox + NVDA
- ❌ Some controls do not feature a label
- ❌ Video container does not have an accessible name
- ✅ Controls announced and functional when navigating via Form control navigation
- ❌ A continuous noise is made declaring the percentage lapsed value when any control has focus
- ✅ When interacting with play, mute, etc, new label/value is announced
- ❌ Playing video sometimes loses access to button controls, users is unable to pause
Plyr – Keyboard only
All browsers
- ✅ Starts with one big play button and all controls visible
- ✅ Video container is focusable
- ✅ Play button and all controls are focusable
- ✅ Focus style highly visible
- ✅ Controls fade when in focus, return on Tab
- ✅ Can play/pause when video container is in focus
- ✅ When opening settings control, focus is sent to the current item, Esc sends focus back to settings control
- ✅ Settings menu allows Tab keypress or arrow keys
- ✅ Space pauses video on any (non button) input focus
- ✅ Exiting from full screen sends focus to the currently selected element
Plyr – Screen reader support
macOS + Safari + VoiceOver
- ✅ All controls feature clear labels
- ✅ Play control includes video title
- ❌ Video container does not have an accessible name or role
- ❌ When scrubber is in focus, a continuous announcement is made declaring the time lapsed value
- ❌ When interacting with play, mute, etc, new label/value is not announced
- ❌ Content "behind" full screen video is still accessible
- ✅ Adjusting mute announces value
- ✅ Settings controls are accompanied by ARIA attributes for context
iOS + Safari + VoiceOver
- ✅ All controls feature clear labels via finger and swipe gestures
- ❌ Video container does not have an accessible name
- ❌ When scrubber is in focus, adjustment not available
- ✅ When interacting with play, mute, etc, new label/value is announced
- ❌ Content "behind" full screen video is still accessible
Android + Chrome + Talkback
- ✅ All controls feature clear labels via finger and swipe gestures
- ✅ Video container does has an accessible name
- ✅ When scrubber is in focus, adjustment via volume rocker
- ❌ When interacting with play, mute, etc, new label/value is not announced
- ❌ Content "behind" full screen video is still accessible
- ❌ Focus is lost when swiping back past Caption control
Windows + Any browser + NVDA
- ✅ All controls feature clear labels
- ✅ Play control includes video title
- ❌ Video container does not have an accessible name or role
- ❌ When scrubber is in focus, a continuous announcement is made declaring the time lapsed value
- ❌ When interacting with play, mute, etc, new label/value is not announced
- ❌ Content "behind" full screen video is still accessible
- ✅ Adjusting mute announces value
- ✅ Settings controls are accompanied by ARIA attributes for context
- ❌ When interacting with mute, settings, etc, focus may be lost to video element, does not activate control
Windows + Any browser + JAWS
- ✅ All controls feature clear labels
- ✅ Play control includes video title
- ❌ Video container does not have an accessible name or role
- ❌ When scrubber is in focus, a continuous announcement is made declaring the time lapsed value
- ❌ When interacting with play, mute, etc, new label/value is not announced
- ❌ Content "behind" full screen video is still accessible
- ✅ Adjusting mute announces value
- ✅ Settings controls are accompanied by ARIA attributes for context
Test conclusion
- Native video players are quite inconsistent in their keyboard and screen reader support
- Firefox seems to have the poorest experience overall
- Plyr is our recommendation and while it provides a lot of positives, there’s room for improvement – we can send PRs if needs be