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)">
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.
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
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
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
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.
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!
<source src="/sandbox/video-media/roar.mp3" media="(max-width: 599px)">
Unsupporting browsers will simply hear the t-rex roar, is a phrase I never thought I would write.
Let's get back to video.
picture, and also not!
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
picture, the first source that meets the needs of the browsing conditions will be chosen, but unlike
videoONLY selects a source when the element is first initialized (say, at initial page load or when a new
videoelement is added to the DOM). So again,
picturesources 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.
video, you specify sources using a
srcattribute, while in
picture, you'll use
sizes). Once again, this might change in the future if
srcsetsupport, but for now, it uses
sourcesare the only child elements used for displaying a source, whereas with
sourceelements control a sibling
imgelement. 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
video elements use the
track element to specify captions.
Reminder: HTTPS Live Streaming video is great and often better!
At its simplest form, the markup for an HLS video embed can look something like this:
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!
By the way... I am currently exploring work opportunities for 2024! If you think I might make a good addition to your team, whether full-time or as an independent contractor, please reach out.