SJ (Scott Jehl)

How to Use Responsive HTML Video (...and Audio!)

photo of scott jehl profile headshot

By Scott Jehl

In case you haven't already heard, you can use media queries for delivering HTML video again! Just a few days ago, Firefox 120 landed and it includes a patch (hey btw, I wrote it!) to bring back support for this web standard, and Chrome 120 will be out on November 29th with renewed support as well. Safari never removed their support in the first place, so that makes things wonderfully cross-browser now!

This is great news for web performance fans, as video is by far the heaviest type of media used on websites (the median weight of just the video files on pages that use video is almost 5 megabytes per page on mobile devices), and that weight has a huge impact on performance, users' data costs, sites' hosting costs, and overall energy usage. Using an HTML video element to display a static video file is one of the most common and portable ways to drop a video into a webpage today, so it's great we now have options to do it more responsibly.

If you'd like a recap on why this feature was removed and the process it took to reinstate it, I wrote about that here. Today however, I thought I'd post some examples of how to use responsive HTML video now that it works (again!).

Let's Talk Markup Patterns

I'll start with some example HTML and then explain what we're looking at...

    <source src="/sandbox/video-media/small.mp4" media="(max-width: 599px)">
    <source src="/sandbox/video-media/large.mp4">

That's a basic responsive video element. It's responsive because one of the source elements has a media attribute on it that includes a media query, making its source selection conditional to the browser's viewport size. If you've used the picture element before, that media attribute is going to look familiar, because picture was actually designed based on how this works in video (back when it was supported the first time).

Here's that video element in the page. Supporting browsers (Firefox and Safari at time of writing) will see a video that says "small video source" at small viewport sizes and a video that says "large video source" at wider viewport sizes. Other browsers (eg Chrome, Arc, or Edge for a couple more days at least) will just select the first small source because those browsers ignore the media attribute and pick the first source that matches.

Markup explained

There are a couple of sources listed in the example above, referencing 2 video sizes (small and large) in mp4 video format (which is broadly supported). When the page loads, the browser will look through these sources in order of appearance and pick the first source whose attributes (such as media, and type) all suit the browsing conditions. So in this example, if the browser viewport is less than 600px wide the browser will use the first source (small.mp4), and if it's equal-to or greater than 600px it will use the second large source, which has no media qualifications specified.

It's important to remember that "first-match" order, since it's likely the opposite order that you might expect from typical CSS media queries, where media queries can override prior ones that match. In both picture and video elements, the first matching source element is chosen and the rest are ignored, so you'll need to plan for that in how you structure your markup. You can of course list your sources in either small-to-large or large-to-small order if you'd prefer, but you'll need to use max-width media queries and min-width media queries accordingly.

Also! An opinionated note: I haven't thought about this too much yet, but I think I prefer to reference the least-harmful (in other words, the smallest) video file first in my video elements, just in case the browser doesn't support responsive video and simply selects the first source it finds. This might not be how you choose to do it, but I sort of like the idea of delivering mobile-first from a filesize perspective, and relying on cross-browser support to handle the selection properly in most cases.

Sources and Types

Here's another example with more sources and types. I've flipped the order to go large-to-small here too, just to show that either works.

    <source media="(min-width: 2000px)" src="large.webm" type="video/webm">
    <source media="(min-width: 2000px)" src="large.mp4" type="video/mp4">
    <source media="(min-width: 1000px)" src="medium.webm" type="video/webm">
    <source media="(min-width: 1000px)" src="medium.mp4" type="video/mp4">
    <source src="small.webm" type="video/webm">
    <source src="small.mp4" type="video/mp4">

There are a number of sources listed in this example, offering 3 video sizes (small, medium, and large), each of which in webm and mp4 formats. Once again, the first matching source will be used, and that match must satisfy both the media and type attributes. Note that I've listed webm formats before mp4 for each size. That's because webm is supported in fewer browsers than mp4, but it is often lighter in weight for the same quality. So I'd prefer webm to be chosen if the browser happens to support both formats.

The last source has no media specified so it acts as a fallback that will be chosen if all of the prior sources don't match.

Other Queries

How about other types of media queries? Go wild. They work! Here's an example that will serve portrait or landscape video depending on the device's orientation, which might be handy for making those "tiktoks" and "reels" the kids are into these days.

    <source src="landscape.mp4" type="video/mp4" media="(orientation: landscape)">
    <source src="portrait.mp4" type="video/mp4">

And you can of course combine queries, for example something like media="(orientation: landscape) and (max-width: 480px)".

Easter Egg: Responsive Audio Works Too?!

Uh, so yeah, it's true. You can use media queries in HTML audio elements to deliver different audio to different media conditions. This is true in Safari too, so it's not just some terrible side effect of letting me commit code to Firefox.

I'm going to assume responsive audio will be useful for some scenarios that I have not considered yet. It's sort of exciting to think about, and maybe there'll be a followup post here about it.

For now, here's an audio element that will roar like T-Rex for small viewport sizes and cluck like a chicken for larger viewport sizes!

<audio controls>
  <source src="/sandbox/video-media/roar.mp3" media="(max-width: 599px)">
  <source src="/sandbox/video-media/cluck.mp3">

Unsupporting browsers will simply hear the t-rex roar, is a phrase I never thought I would write.

Let's get back to video.

Just like picture, and also not!

While picture and video are different in many ways that are unrelated to responsive video delivery, the syntax is similar enough that it's worth pointing a few things out here.

  • In both video and picture, the first source that meets the needs of the browsing conditions will be chosen, but unlike picture, video ONLY selects a source when the element is first initialized (say, at initial page load or when a new video element is added to the DOM). So again, picture sources can change as conditions change, such as when the browser is resized, but currently, this is not true for video, so generally you will only see a video's source change if you refresh the page. It's possible this could change in the future, but complications around aligning video timecodes and such made it difficult to implement in the initial implementation.
  • In video, you specify sources using a src attribute, while in picture, you'll use srcset (along with sizes). Once again, this might change in the future if video gains srcset support, but for now, it uses src.
  • In video, the sources are the only child elements used for displaying a source, whereas with picture, the source elements control a sibling img element. Video has no similar pattern like that.

Also, this is not particular to responsive video per se, but it's very important to consider non-visual media alternatives for both images and for video content. While picture uses the alt attribute on its child img, video elements use the track element to specify captions.

Reminder: HTTPS Live Streaming video is great and often better!

Responsive HTML video is the only declarative, W3C-standard, and non-JavaScript dependent means of delivering different video sources to different viewport sizes, but it's not the only way to deliver video that adapts to browsing conditions and often it's not the best choice! HTTP Live Streaming is a common means of delivering video responsibly to a variety of browsing conditions, and it supports robust features for changing video bitrate dynamically as connectivity improves or degrades, so it's the most robust choice for delivering large and/or long-duration videos over the web.

At its simplest form, the markup for an HLS video embed can look something like this:

<video src=""></video>

I dropped that HTML into a codepen and added some autoplay and controls attributes here. That file source is an m3u8 playlist (borrowed from the folks behind HLS JS), which is essentially a manifest file referencing small chunks of your video that need to be generated by software like FFMPEG. That markup above will only play in Safari, by the way (HLS is a streaming format invented by Apple), so you'll need some JavaScript to polyfill the behavior of HLS in other browsers. I found this article to be a good overview of the considerations involved.

Streaming protocols are more complicated to implement than responsive HTML video, and HLS support relies on JavaScript to work at all in browsers other than Safari, but it is nonetheless incredibly common in the video streaming services you are used to using . HLS video is designed to accommodate browser environments and connection speeds and will result in a more tailored experience for video players. That said, if you're embedding shorter videos, are constrained by time or familiarity with how to implement HLS technology, responsive video is a great option to consider.

Thanks for reading!

Thank you for reading. As additional examples come to mind for how to use responsive HTML video, I'll aim to add them to this post. Feel free to reach out on Mastodon or via the contact form if you have ideas or questions!