HTML5 Video

HTML5 Rocks


In modern browsers, adding a video to your page is as easy as adding an image. No longer do you need to deal with special plug-ins or require crazy markup, you can do it with a single element.

The Markup

Let's jump in with a really simple example:

<video src="video.webm" controls>

That's all you need to embed a simple video on your page and show the basic controls so that a user can play, pause or otherwise control the video.

Specifying Sources

You can specify multiple source files by using the <source> element. The source element lets you specify multiple formats as a fallback in case the user's browser doesn't support one of them. For example:

<video controls>
  <source src="devstories.webm" 
          type='video/webm;codecs="vp8, vorbis"'/>
  <source src="devstories.mp4"
          type='video/mp4;codecs="avc1.42E01E, mp4a.40.2"'/>

When the browser parses the <source> tag, it uses the optional type attribute to help decide which file to download and play. If the browser supports WebM and has the VP8 and Vorbis codecs, it will play devstories.webm, if not, it will check if it can play MPEG-4 videos with the avc1.42E01E and mp4a.40.2 codecs, and so forth.

To improve performance, you should always include the type attribute in the source element. Otherwise the browser will need to load each video file until it can find one that it can play!

It's also a good idea to make sure that your videos are being served with the right MIME type. In some cases, the browser won't play the video if the MIME type isn't set properly.

Media Fragments

Adding a media fragment to the media URL, you can specify the exact portion you want to play. To add a media fragment, you simply add #t=[start_time][,end_time] to the media URL. For example, to play the video between seconds 10 through 20, you could specify:

<source src="devstories.webm#t=10,20" 
        type='video/webm;codecs="vp8, vorbis"' />

You can also specify the times in hours:minutes:seconds, such as #t=00:01:05 to start the video at one minute, five seconds in. Or, to only play the first minute of the video, you would specify #t=,00:01:00. You need to make sure Range Requests are supported by your server: check for Accept Ranges: bytes. It's on by default for Apache and many other servers, but worth checking.

Providing captions and subtitles

The <track> element provides a simple, standardized way to add subtitles, captions, screen reader descriptions and chapters to your video, which improves accessibility but also makes it possible for search engines to understand what's in the video. As well as subtitles and captions, it's possible to put metadata in cues, for example in JSON format. This can enable innovative use cases such as DOM manipulation synchronised with video playback.

<video controls style="width:640px;height:360px;" poster="poster.png">
  <source src="devstories.webm" 
          type='video/webm;codecs="vp8, vorbis"' />
  <source src="devstories.mp4" 
          type='video/mp4;codecs="avc1.42E01E, mp4a.40.2"' />
  <track src="devstories-en.vtt" label="English subtitles" 
         kind="subtitles" srclang="en" default></track>

The <track> element functions like a <source> element within the <video> element, and has a src attribute that points to a file in WebVTT format. You can specify the label that will be displayed in the UI to the user, as well as the source language (srclang) and if there are multiple track elements, which one should be used as the default.

Here's the first few lines of devstories-en.vtt:


00:00:00.500 --> 00:00:02.000 D:vertical A:start
The Web is always changing

00:00:02.500 --> 00:00:04.300
and the way we access it is changing

00:00:05.000 --> 00:00:07.000
The source of that change is <c.highlight>you</c>

Check out Getting Started With The Track Element for more information.


The <video> element has several special attributes that can change or enhance its default behavior.

autoplay* Tells the browser to immediately start downloading the video and play it as soon as it can. Note that mobile browsers generally do not support this attribute, the user must tap the screen to begin video playback.

Hint to the browser about whether optimistic downloading of the video itself or its metadata is considered worthwhile.

Options are:

  • none - Hints to the browser that the user likely will not watch the video, or that minimizing unnecessary traffic is desirable.
  • metadata - Hints to the browser that the user is not expected to need the video, but that fetching its metadata (dimensions, first frame, track list, duration, and so on) is desirable.
  • auto - Hints to the browser that optimistically downloading the entire video is considered desirable.
poster Provides an image to show before the video loads
controls* Shows the default video controls (play, pause, etc)
height & width Sets the width and height of the video in CSS pixels
loop* Tells the browser to automatically loop the video
muted* Mutes the audio from the video

*indicates a binary attribute, which enables that behavior when the attribute is present, or has it's value set to anything.


Because the <video> element is just another HTML element, you can style it like any other element. You can add borders, set the opacity, apply a filter or even do a 3D transform on the video. For example, by applying filter: grayscale(100%); to the video element, you can turn your video into a black and white video:

As of the January 2014, the filter effect is only supported in WebKit and Blink based browsers.


Media elements like <video> and <audio> have additional JavaScript functionality beyond normal HTMLElements that allow you to interact or control the media.


currentTime Gets or sets the current playback position in seconds
volume Gets or sets the current volume level for the video
muted Gets or sets the mute state
playbackRate Gets or sets the playback rate, where 1 is normal speed forward
currentSrc Returns the current video source file the browser is playing
videoWidth & videoHeight Returns the actual dimensions of the video, not the video element size


load() Loads the video and reset the play head to the beginning of the video
play() Plays the video from it’s current location
pause() Pauses the video at the current location

Tests to see whether the browser can play a specific type of video, for example 'video/webm;codecs="vp8, vorbis"'

The browser will return:

  • probably - if it’s most likely the video file can be played
  • maybe - if the video might be playable
  • [empty string] - if the video file is not playable


canplaythrough Fired when enough data is available that the browser believes it can play the video completely without interruption
ended Fired when the video has finished playing
error Fired if an error occurs
playing Fired when the video starts playing, for the first time, after being paused or when restarting
progress Fired periodically to indicate the progress of downloading the video
waiting Fired when an action is delayed pending the completion of another action
loadedmetadata Fired when the browser has finished loading the metadata for the video and all attributes have been populated

These are only a subset of the media events that may be fired. Refer to the Media events page on the Mozilla Developer Network for a complete listing.

There are many things that you can do using these JavaScript functions, events and attributes; you can build your own set of rich video controls, control multiple videos at the same time, jump to specific times within the video and plenty more. You can also use one of the many custom player controls that are available today to provide a rich experience.

Interacting with other elements

Video elements can interact with other elements like canvas to provide a completely new experience. Canvas' drawImage lets you grab a single frame from the video element, and draw it within the canvas.

function grabScreenshot() {
  ctx.drawImage(video, 0, 0, videoWidth, videoHeight);
  var img = new Image();
  img.src = canvas.toDataURL("image/png");
  img.width = 120;

You can then modify the captured pixels and change the video in real time. For example, you could provide your own chroma-key effect, make the video explode when you click on it, or change the background color of the page based on the primary colors in the video. The possibilities are almost limitless!

The same technique of importing images can be also applied to WebGL. With WebGL you can import the frames of a video and render them on a spinning 3D cube.

Formats & codecs

You can think of a video file as a container (like a ZIP file), that contains the encoded video stream and an audio stream. There are many different types of container formats and unfortunately there isn't a single 'one-ring' format that will work in all browsers. If you're wondering why you need to use two encodings, be sure to read Licensing issues with H.264 video.

Thankfully, we can get coverage for all modern (and mobile) browsers using only two formats:

  • WebM - uses the VP8 codec for video and the Vorbis codec for audio
  • MP4 - uses the H.264 codec for video and the AAC codec for audio

WebM was designed specifically for serving video on the web, and has many benefits. Its low computational footprint means that it plays well on high-end desktops but also on low-powered devices like tablets or phones. High compression rates for video, which means videos can be downloaded faster, or you can improve the quality without a significant size increase. The encoding process is also significantly simpler with fewer profiles and sub-options.

Support for WebM is available natively in Chrome, Firefox and Opera, and can be added to Internet Explorer or desktop Safari by installing a plug-in. When not available natively or if the plug-in isn't installed, you'll need to provide the video encoded using the MP4 format.

The video chapter on has an excellent section on how best to encode your videos. They recommend using ffmpeg for WebM videos and HandBrake for MP4 videos.


Mobile provides some unique challenges for video. Sending a 1080p video to a mobile device like a phone doesn't make much sense, the video will likely be too big for the screen, and the bandwidth required to send the video may use all of the users limited data connection extremely quickly.

Browser vendors have accounted for this and have disabled the autoplay and preload attributes on mobile devices. It's also a good idea to include poster image that can be displayed until playback begins, though this does potentially require an additional download. This gives viewers a meaningful idea of content without needing to download video or start playback.

Further Reading

Encrypted Media Extensions - EME

Encrypted Media Extensions (sometimes referred to as EME) is a JavaScript API that enables web applications to interact with content protection systems, in order to allow playback of encrypted audio and video. EME is an extension to the HTMLMediaElement specification, and browser support is optional. If a browser does not support EME, it will simply silently fail to play the encrypted media.

Streaming video with the MediaSource API

The MediaSource API extends the HTMLMediaElement to allow JavaScript to generate media streams for playback. Allowing JavaScript to generate streams facilitates a variety of use cases like adaptive streaming and time shifting live streams.


Including video on the modern web is easier than ever before and opens some amazing new possibilities. What will you do next?