Hero videos

Display a video in your Hero in an accessible way

Often you see a big video on the homepage of a website. It can look very nice, but it can also be annoying to users. Here is my way to respect users’ preference and still keep a great experience.

Considerations

To have an autoplaying video in a Hero as a background, I would make some considerations how it works and behaves:

  • It plays automatically, but:
  • It doesn’t play automatically if the user prefers it not to
  • It has no sound
  • It can be paused
  • It stays paused if the user paused it and reloads the page
  • The filesize is not too big
  • It has great quality and detail, on different screen sizes

Step 1: create the video files

Autoplaying a video might have an impact on data usage. If a user is on a small or expensive data plan, I wouldn’t want this video to take a big chunk out of it.

Step 1a: get the original uncompressed video

To get the best results, I ask the video file supplier to provide the original video in the highest quality possible, without any compression. For a couple of seconds this file might already be quite large, so I don’t add this file to my webpage!

Step 1b: compress the video

To reduce the file size of the video, I recommend using HandBrake, but there are plenty of other tools available to do the same thing. I will allow me to resize the video and apply compression.

I set the format to MP4, which has good support for all modern browsers. If I apply a max-inline-size of 1920px to the <video> element with CSS, I convert the video to have a size of 1920 pixels wide too.

I recommend testing with various levels of compression and the output quality. There is no golden rule here. You should think about your audience, their data plans, and the locations where your site will be used. Will people be mainly on Wi-Fi or on expensive data plans? Are they mostly on low-end mobile devices, or will they be on fast desktops? Also, is it really necessary to autoplay a video, in all situations?

Step 1c: optionally, create a large and small version

If I want to serve a smaller version of the video instead of a Full HD resolution for mobile devices, I create a secondary file with a lower resolution (and a lower file size) in this step too.

Step 2: add an ‘invalid’ video element in HTML

I can autoplay the video by setting an HTML attribute on the <video> element: autoplay. This will only work if the video contains no audio, or if it is muted by another attribute called muted. The browser simply blocks autoplaying with audio because autoplaying sound is considered annoying to almost all users.

Disable preloading

If the user does not choose to autoplay the video, I don’t want the browser to preload it either. In the following code snippet the video won’t play because there is no src attribute on the <source> element. Yet. With plain JavaScript I like to have the element in place already, clone it, and append it. With videos, you can’t just copy the data-src attribute to a src value, otherwise it won’t play.

<video autoplay muted loop playsinline>
  <!--  optionally, add a larger video for bigger screens -->
  <source data-src="/video-large.mp4" type="video/mp4" media="(min-width: 64rem)">
  <source data-src="/video.mp4" type="video/mp4">
 </video>

Autoplay on iOS

To make it work on a iOS, I need another attribute: playsinline. This is because iOS will play videos fullscreen by default, and this makes it appear as a block element in your page, so it can be positioned anywhere.

Step 3: Add a play/pause button

WCAG Success Criterion 2.2.2 states that users need to be able to stop autoplaying videos and animations manually.

This means I need to add a play/pause button to the Hero component. I place it in an easily discoverable place. If the button consists of only a play/pause icon, I also add a visually hidden text that acts as the label of the button.

Step 4: check if I should autoplay the video

I also want to take another user preference into account: users that don’t prefer any motion at all.

Although it’s not hard to autoplay the video and incorporate a pause button, this will still be annoying to see the video autoplaying again everytime they visit the page.

Step 4a: check if the user prefers reduced motion

A user can choose to reduce the animation and motion in the settings of the Operating System. For example, in iOS this will disable all the transitions between screens and reduce it to simple fades.

I can query this setting with CSS and JavaScript and respect the preference with autoplaying video:

window.matchMedia('(prefers-reduced-motion: reduce)').matches

This will return a boolean value which I can use to determine if I should autoplay the video.

Step 4b: check if the user paused the video before

When starting or stopping the video with the play/pause button, I save that state to localStorage.

When loading the scripts for the video, I check for that setting in localStorage. If it was paused before by the user, I don’t autoplay the video again.

Step 5: autoplay the video

If the checks from step 4a and 4b say I can autoplay the video I start it by calling videoElement.play() on the DOM node. That’s it.

Step 6: pause/play the video on click

Also persist the play/paused state in localStorage. This will make the video stay paused on page reload (see step 4b). So if a user didn’t like the playing video initially, it will not be playing again each time that user visits that same page.

And that’s it!

This is my way of adding an autoplaying Hero video to a webpage. I think it takes the user preferences into account nicely.

Testing for accessibility

If you want to ‘automatically’ test this with some tools or browser-extension: you can’t. There is too much context, considerations, and situations. Test it manually by changing browser or OS settings and see what happens.

Live example

At the time of writing, an example of this implementation is present on the homepage of has.nl. Check it out.