Video with transparency in Chrome, Edge, Firefox, Safari, iOS and Android, circa 2022
This post on using video with a transparent background will probably not age well. At least I hope that is the case! Ideally, in the future, you can use a single .webm
video file and it will work everywhere.
But, as I write this post in January 2022, after a full day of research and trying different approaches, I’ve got a <video>
tag that will play a video with a transparent background across a wide variety of browsers.
- Chrome
- Firefox
- Safari on Desktop
- Safari on iPhone
- Android
I assume that the other browsers based on Chromium will also work, although I’ve not tested them when I write this.
If you’re trying to get a video with transparency working, let me show you what I’ve done. I hope this saves you some time.
This post on using video with a transparent background will probably not age well. At least I hope that is the case! Ideally, in the future, you can use a single .webm
video file and it will work everywhere.
But, as I write this post in January 2022, after a full day of research and trying different approaches, I’ve got a <video>
tag that will play a video with a transparent background across a wide variety of browsers.
- Chrome
- Firefox
- Safari on Desktop
- Safari on iPhone
- Android
I assume that the other browsers based on Chromium will also work, although I’ve not tested them when I write this.
If you’re trying to get a video with transparency working, let me show you what I’ve done. I hope this saves you some time.
Source material
I’m lucky in that I’m starting with a nice short piece of professionally-produced video with an alpha channel. If you don’t have an alpha channel in your source video, you need to solve that problem first.
The source video I had was very big. I used Adobe After Effects to trim and resize it to meet my needs. I wanted no audio channel on the video which allows me to autoplay the video using Javascript. I also resized the video dimensions. Pro tip: web video does not have to be the traditional video aspect ratio.
I exported that video using the Apple ProRes 4444 XQ
. This will result in a file that is still not usable on the web, but it will be ready for the next step in the process.
Source material #
I’m lucky in that I’m starting with a nice short piece of professionally-produced video with an alpha channel. If you don’t have an alpha channel in your source video, you need to solve that problem first.
The source video I had was very big. I used Adobe After Effects to trim and resize it to meet my needs. I wanted no audio channel on the video which allows me to autoplay the video using Javascript. I also resized the video dimensions. Pro tip: web video does not have to be the traditional video aspect ratio.
I exported that video using the Apple ProRes 4444 XQ
. This will result in a file that is still not usable on the web, but it will be ready for the next step in the process.
My hardware
Before going further, you should know I am using an Apple Silicon Mac, a MacBook Pro. If you’re on any other platform, your result may vary since I use the hardware acceleration option in one of the video conversions we’ll discuss below. This doesn’t mean you need a Mac, but I don’t have the hardware to test on other platforms.
My hardware #
Before going further, you should know I am using an Apple Silicon Mac, a MacBook Pro. If you’re on any other platform, your result may vary since I use the hardware acceleration option in one of the video conversions we’ll discuss below. This doesn’t mean you need a Mac, but I don’t have the hardware to test on other platforms.
Shutter Encoder
After many tests, I’ve chosen Shutter Encoder as the best encoder for this process. I tried FFmpeg, Handbrake, Adobe Media Encoder, and several other online video encoding services. None of them worked as well as Shutter Encoder, which is free. If you find the app useful, you should support the author. I did because I like the software I use to stick around.
Update, 10MAY2022: When I wrote this post originally, I used Shuttle Encoder version 15.7 during the encoding process. I worked on encoding another video, as described here, using Shuttle Encoder version 15.9, which failed. Based on what I’ve read, there is some issue with FFMPEG in versions after 15.7. Reinstalling version 15.7 allowed me to continue to convert videos successfully. I hope the bug is fixed in future versions of the software.
Update, 25MAY2023: I recently went through the process of creating a video with an alpha channel, as described in this post. I’m happy to report that using Shutter Encoder version 17.1, the current version as of May 2023, successfully encodes the alpha channel. Based on the changelog, it looks like this was fixed in Shutter Encoder version 16.8.
Creating a webm version of the video
I’ve made two versions of the video. The first is a .webm
version. Shutter Encoder will allow you to preserve the alpha channel when you’re creating your webm. Let’s review the options I used.
Shutter Encoder #
After many tests, I’ve chosen Shutter Encoder as the best encoder for this process. I tried FFmpeg, Handbrake, Adobe Media Encoder, and several other online video encoding services. None of them worked as well as Shutter Encoder, which is free. If you find the app useful, you should support the author. I did because I like the software I use to stick around.
Update, 10MAY2022: When I wrote this post originally, I used Shuttle Encoder version 15.7 during the encoding process. I worked on encoding another video, as described here, using Shuttle Encoder version 15.9, which failed. Based on what I’ve read, there is some issue with FFMPEG in versions after 15.7. Reinstalling version 15.7 allowed me to continue to convert videos successfully. I hope the bug is fixed in future versions of the software.
Update, 25MAY2023: I recently went through the process of creating a video with an alpha channel, as described in this post. I’m happy to report that using Shutter Encoder version 17.1, the current version as of May 2023, successfully encodes the alpha channel. Based on the changelog, it looks like this was fixed in Shutter Encoder version 16.8.
Creating a webm version of the video #
I’ve made two versions of the video. The first is a .webm
version. Shutter Encoder will allow you to preserve the alpha channel when you’re creating your webm. Let’s review the options I used.
Add your source video in the Choose files area then select VP9 as your function. Under the Advanced features area, choose Enable alpha channel.
Now click the Start function button and generate your .webm
video.
Add your source video in the Choose files area then select VP9 as your function. Under the Advanced features area, choose Enable alpha channel.
Now click the Start function button and generate your .webm
video.
Creating an H.265 version of the video, and not an H.264 video
Now that Safari added support for .webm
, you might be wondering why we’re making another version of the video at all. In my tests, Safari’s support of .webm
video doesn’t include support for the alpha channel. A black background is shown where you’d expect the transparency to be used.
Why not use an .mp4
with an alpha channel? That’s what we’re going to do, but it’s not the traditional H.264 video you may be familiar with.
After a little online research, you may incorrectly discover the .mp4
video file does not support an alpha channel. This was my assumption, too, but I was conflating an mp4 file and an H.264 video file as the same thing. There is a difference though. H.264 is the codec, the piece of software, that converts the uncompressed video into a stream of compressed bits. The filetype, .mp4
(or .webm
, or .avi
, etc.) contains the stream of video and/or audio.
In other words, the .mp4
file can use the H.264 codec. The H.264 coded doesn’t support having an alpha channel. But there is a newer codec called H.265. Spoiler alert: it supports the alpha channel.
Using Shuttle Encoder again, make the H.265 version of the video. Let’s review the options I used.
Creating an H.265 version of the video, and not an H.264 video #
Now that Safari added support for .webm
, you might be wondering why we’re making another version of the video at all. In my tests, Safari’s support of .webm
video doesn’t include support for the alpha channel. A black background is shown where you’d expect the transparency to be used.
Why not use an .mp4
with an alpha channel? That’s what we’re going to do, but it’s not the traditional H.264 video you may be familiar with.
After a little online research, you may incorrectly discover the .mp4
video file does not support an alpha channel. This was my assumption, too, but I was conflating an mp4 file and an H.264 video file as the same thing. There is a difference though. H.264 is the codec, the piece of software, that converts the uncompressed video into a stream of compressed bits. The filetype, .mp4
(or .webm
, or .avi
, etc.) contains the stream of video and/or audio.
In other words, the .mp4
file can use the H.264 codec. The H.264 coded doesn’t support having an alpha channel. But there is a newer codec called H.265. Spoiler alert: it supports the alpha channel.
Using Shuttle Encoder again, make the H.265 version of the video. Let’s review the options I used.
There are three options in the screenshot above.
After you’ve added your source video, select H.265 as your function. Under the Advanced features area, the Enable alpha channel option should be checked automatically. Also, turn on the Hardware acceleration option. In my tests, the hardware acceleration was the only way to get Shuttle Encoder to create the alpha channel successfully. Depending on your computer, you may achieve different results when using hardware acceleration.
Now click the Start function button and generate your .mp4
video.
There are three options in the screenshot above.
After you’ve added your source video, select H.265 as your function. Under the Advanced features area, the Enable alpha channel option should be checked automatically. Also, turn on the Hardware acceleration option. In my tests, the hardware acceleration was the only way to get Shuttle Encoder to create the alpha channel successfully. Depending on your computer, you may achieve different results when using hardware acceleration.
Now click the Start function button and generate your .mp4
video.
The video tag for your HTML
Let’s look at <video>
tag I’m using.
<video muted playsinline id='ambientVideo'>
<source src="~@/assets/my_video_H.265_2.mp4" type='video/mp4;codecs=hvc1'>
<source src="~@/assets/my_video_VP9_3.webm" type="video/webm">
</video>
This video tag is for a small animation that plays inline and it has no audio. You can see those parameters at the beginning of the video tag. I also have an id of ambientVideo
which I use to trigger the animation with an Intersection Observer that I’ll describe at the end of this post. (Read more about the options for the video tag in the MDN Web Docs.)
The two most important things are the order of the source tags and the type of each source.
The .mp4
source tag is the first tag. Browsers will see this as the first source, and if they can play it, that’s the one they’ll choose to use. In my tests, Safari on desktop and on mobile will use this. Be sure you’ve got the type set to include the codecs
portion. Without that, you’ll find browsers that think they know how to play a .mp4
trying to play that video unsuccessfully because they are not aware of the hvc1 codec.
Next, include the link to the .webm
source. This is what most browsers will end up displaying.
In case you’re wondering, the ~@/assets
path is how I refer to the root of my public folder. You need to use the path to the video that makes sense to your environment.
The video tag for your HTML #
Let’s look at <video>
tag I’m using.
<video muted playsinline id='ambientVideo'>
<source src="~@/assets/my_video_H.265_2.mp4" type='video/mp4;codecs=hvc1'>
<source src="~@/assets/my_video_VP9_3.webm" type="video/webm">
</video>
This video tag is for a small animation that plays inline and it has no audio. You can see those parameters at the beginning of the video tag. I also have an id of ambientVideo
which I use to trigger the animation with an Intersection Observer that I’ll describe at the end of this post. (Read more about the options for the video tag in the MDN Web Docs.)
The two most important things are the order of the source tags and the type of each source.
The .mp4
source tag is the first tag. Browsers will see this as the first source, and if they can play it, that’s the one they’ll choose to use. In my tests, Safari on desktop and on mobile will use this. Be sure you’ve got the type set to include the codecs
portion. Without that, you’ll find browsers that think they know how to play a .mp4
trying to play that video unsuccessfully because they are not aware of the hvc1 codec.
Next, include the link to the .webm
source. This is what most browsers will end up displaying.
In case you’re wondering, the ~@/assets
path is how I refer to the root of my public folder. You need to use the path to the video that makes sense to your environment.
Bonus: Play video when it appears on the screen
In my video tag, I’ve got an ID of ambientVideo
.
I’ve posted the Javascript file I’m using in this gist: ambient-video-play-on-enter.js
Since you are here already, I’ll share it in this post too.
var ambientVideo = document.getElementById("ambientVideo");
var io = new IntersectionObserver(
entries => {
entries.forEach(entry => {
if (entry.isIntersecting) {
ambientVideo.play();
} else {
ambientVideo.pause();
}
});
},
{
root: null,
rootMargin: "0px",
threshold: 0.5
}
);
// after confirming the element exists, look for the #ambientVideo when visible in viewport
if (ambientVideo) {
io.observe(ambientVideo)
}
In the first line, I look for my video tag with the id of ambientVideo
. Next, I create a new IntersectionObserver. Yes, this code could be made to be more reusable, but it works for this purpose.
What does this code do?
Basically, when the video element comes into frame, we tell it to play. When it leaves the frame, it gets paused.
If you want to customize when the Intersection Observer triggers, check out the Intersection observer options. As an example, my threshold setting of 0.5 means I want to detect the visibility of my video when 50% of it is visible. You may need different settings.
To make it work, I have the Intersection Observer that I create start observing, looking for the ambientVideo
video element.
Good luck!
Bonus: Play video when it appears on the screen #
In my video tag, I’ve got an ID of ambientVideo
.
I’ve posted the Javascript file I’m using in this gist: ambient-video-play-on-enter.js
Since you are here already, I’ll share it in this post too.
var ambientVideo = document.getElementById("ambientVideo");
var io = new IntersectionObserver(
entries => {
entries.forEach(entry => {
if (entry.isIntersecting) {
ambientVideo.play();
} else {
ambientVideo.pause();
}
});
},
{
root: null,
rootMargin: "0px",
threshold: 0.5
}
);
// after confirming the element exists, look for the #ambientVideo when visible in viewport
if (ambientVideo) {
io.observe(ambientVideo)
}
In the first line, I look for my video tag with the id of ambientVideo
. Next, I create a new IntersectionObserver. Yes, this code could be made to be more reusable, but it works for this purpose.
What does this code do? #
Basically, when the video element comes into frame, we tell it to play. When it leaves the frame, it gets paused.
If you want to customize when the Intersection Observer triggers, check out the Intersection observer options. As an example, my threshold setting of 0.5 means I want to detect the visibility of my video when 50% of it is visible. You may need different settings.
To make it work, I have the Intersection Observer that I create start observing, looking for the ambientVideo
video element.
Good luck!