mediacodec.dev

Transparency in video

Which video codecs can carry an alpha channel, why MP4 usually cannot, and the tricks used when it cannot.

Updated

Putting a transparent video on a web page sounds like it should be as simple as a PNG. It is not, because most of the video ecosystem was built to fill rectangles, and alpha was an afterthought in nearly every codec that matters.

Which codecs can carry alpha

VP9 and VP8 support alpha in WebM, and browsers honour it. This is the workhorse for transparent video on the web and has been for years.

AV1 supports alpha, and browser support has arrived more recently. Efficient, and worth using where you can confirm the target decodes it.

HEVC supports alpha, but almost exclusively via Apple’s implementation. Safari plays HEVC with alpha in MP4; other browsers largely do not. This is the “works on iPhone, blank on Android” trap.

ProRes 4444 and 4444 XQ carry alpha and are the standard for production and interchange, not delivery. Enormous files, universally supported by editing tools.

H.264 does not. There is no alpha in any profile anyone ships. This is the single most consequential fact here, because H.264 in MP4 is the default delivery format for everything else.

Animated formats: APNG, animated WebP and animated AVIF all support alpha and are genuinely reasonable choices for short loops, sitting somewhere between image and video. GIF supports only 1-bit transparency, which is why GIF logos have those jagged fringes.

The web recipe

For transparent video in a browser today, serve VP9-in-WebM with an AV1-in-WebM alternative if you want the efficiency, and accept that Safari’s support for the WebM path has historically been the weak spot. Test on Safari specifically before committing.

ffmpeg -i input.mov -c:v libvpx-vp9 -pix_fmt yuva420p -crf 30 -b:v 0 output.webm

The critical part is yuva420p, with the a. Omit it and FFmpeg silently encodes without alpha, producing a file that looks correct in a preview against a white background and composites as an opaque rectangle in production. This is the most common way transparent-video work fails, and it fails quietly.

When you cannot have alpha

Two workarounds are widespread, both of which trade a little quality for universal codec support.

The alpha-matte side-by-side. Encode a frame that is twice as wide (or tall): the colour image on one half, its alpha channel as greyscale on the other. Any codec can carry it, because it is just an opaque video. At playback, a shader or a canvas composites the two halves back together. Every major “transparent video on the web” library works this way, and it costs roughly double the pixels.

Chroma keying at playback. Encode against a solid colour and key it out live. Cheap in bytes, and it fails exactly where chroma keying always fails: soft edges, motion blur, semi-transparency, and anything shot with 4:2:0 subsampling, which is why keying footage wants 4:2:2 or 4:4:4 sources.

Premultiplied vs straight alpha

Worth knowing because it produces a specific, recognisable bug. In straight alpha, colour values are independent of the alpha channel. In premultiplied alpha, colour values are already multiplied by it, so a half-transparent red is stored as half-brightness red.

Compositing premultiplied content as if it were straight gives dark fringes around edges; the reverse gives bright halos. If your transparent video has a suspicious outline everywhere it meets the background, this is almost always the reason, and the fix is telling the compositor which convention the file uses rather than re-exporting anything.

The honest recommendation

If the loop is short and the content is graphic rather than photographic, try animated WebP or AVIF first. They are simpler, they carry alpha without argument, and they avoid the entire video-codec question.

If it must be video, use VP9-in-WebM, test Safari early, and keep a non-transparent fallback. Alpha in video remains the corner of the ecosystem where “it works in my browser” is the least reliable evidence you can gather.