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...
<video>
<source src="/sandbox/video-media/small.mp4" media="(max-width: 599px)">
<source src="/sandbox/video-media/large.mp4">
</video>
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.
<video>
<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">
</video>
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.
<video>
<source src="landscape.mp4" type="video/mp4" media="(orientation: landscape)">
<source src="portrait.mp4" type="video/mp4">
</video>
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">
</audio>
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
andpicture
, the first source that meets the needs of the browsing conditions will be chosen, but unlikepicture
,video
ONLY selects a source when the element is first initialized (say, at initial page load or when a newvideo
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 forvideo
, 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 asrc
attribute, while inpicture
, you'll usesrcset
(along withsizes
). Once again, this might change in the future ifvideo
gainssrcset
support, but for now, it usessrc
. - In
video
, thesources
are the only child elements used for displaying a source, whereas withpicture
, thesource
elements control a siblingimg
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="https://test-streams.mux.dev/x36xhzz/x36xhzz.m3u8"></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!