Posted on

How to create a HTML5 background video using HTML, CSS and JavaScript

programming-ide

Video backgrounds are becoming more and more popular in web design these days, for a number of reasons:

  • Internet connections are getting faster
  • HTML5 video has great support
  • Encoding techniques are allowing video to stream faster

If done wrong, they can annoy your users with slow speeds, hard to read text, and distracting movements; however when done well they can be a great subtle touch that adds an extra layer of thoughtfulness to your design.

Before we start with the code, let’s just set some guidelines to avoid doing it the wrong way:

  • The background video should load quickly, and should not block any other page elements while loading
  • The motions in the video should be slow and smooth to avoid being jarring or distracting
  • Any text placed over the video should be easily readable

With those in mind, let’s get started.

Step 1. Convert your video to the required HTML5 compatible formats

The first problem you’ll encounter with HTML5 video is that different browsers support different encoding formats for video. Luckily, the <video> tag supports adding multiple versions of your video, in different formats. So what formats should you include for the best browser compatibility? Right now for the best cross-browser support you should include three versions:

  1. Webm (with VP8 video codec and Vorbis audio codec) is the preferred format for Chrome, Opera and Firefox 4+ as it provides the best compression to quality ratio of the available formats.
  2. Ogg (with Theora video codec and Vorbis audio codec) is also fully supported in Chrome but has even earlier support in Firefox (supported since v3.5).
  3. Mp4 (with H.264 video codec and AAC audio codec) is supported by most other browsers. Including the Mp4 format adds support for Internet Explorer 9+, Safari, iOS Safari, Android Browser, Opera and Chrome for Android.

To convert your video file into these formats, we recommend using this free online HTML5 video converter. If you need help using the converter, there’s a demo video here: How to convert video to HTML5 compatible formats.

Step 2. Preparing your <video> tag

If you converted your video using the tool provided in the first step, you’ll already have your video tag, but let’s run through what’s required so you understand what it entails. We’ll start with an example tag.

<video loop autoplay muted poster="path/to/screenshot.jpg">
	<source src="path/to/video.webm" type="video/webm">
	<source src="path/to/video.ogg" type="video/ogg">
	<source src="path/to/video.mp4" type="video/mp4">
</video>

The <video> tag can have a few attributes. We’ll only go over a few, but for a full list see MDN.

  • src – the path to the video file. We won’t be using this because we’re using <source> elements to declare multiple sources.
  • poster – the path to an image that will be displayed before the video starts playing. We’re definitely going to use this one, go ahead and grab a screenshot from your video, or if you’ve got a better photo to display – even better.
  • autoplay – whether to start playing the video automatically. This is a boolean attribute, so you can add it without a value, or as autoplay="autoplay". Omit the attribute entirely if you don’t want your video to autoplay.
  • loop – another self-explanatory boolean attribute.
  • muted – also boolean and self-explanatory. I recommend adding this to all video backgrounds to avoid annoying your users.

We didn’t specify a src in our <video> tag because we’ve got multiple video files (our aim is to get the best browser support). Instead, we’re adding <source> elements as children of the <video> element. Each <source> tag has a src attribute and a type attribute. type is optional, but highly recommended, as it helps the browser decide which video file to play without downloading a bit of each of them.

So our tag is complete. Try adding it to your page and it will look something like this:

Step 3. Positioning your <video> tag as a background

Now that our video is working, it’s time to position it. The following method will stretch the video over any containing element, which means you can use it as a full-screen background, or the background of a layer or module – whatever your design calls for. We’re going to make it the background of a ‘callout’ layer in our page design.

First, the HTML:

<section class="callout">
    <div class="video-bg">
        <video autoplay loop muted poster="path/to/poster.jpg">
            <source src="path/to/webm.webm" type="video/webm">
            <source src="path/to/ogg.ogg" type="video/ogg">
            <source src="path/to/mp4.mp4" type="video/mp4">
        </video>
    </div>
    <div class="video-overlay"></div>
    <div class="callout-inner">
        <!-- Our callout content goes here -->
    </div>
</section>

The callout section spans the width of the screen, which means the video and video overlay need to do the same. The elements inside the callout are ordered so that each appears above the previous layer. The inner section is centred and only as wide as the content inside. Here’s the corresponding CSS:

.callout {
    position: relative;
    overflow: hidden;
}
.video-bg,
.video-overlay {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    display: block;
}
.video-overlay {
    background: rgba(0,0,0,0.5);
    pointer-events: none; /* Allows right clicking on the video to pause etc */
}
.video-bg video {
    min-width: 100%;
    min-height: 100%;
    width: auto;
    height: auto;
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
}
.callout-content {
    position: relative;
    text-align: center;
    margin: 50px 0; /* This adds some space around the video */
    color: #FFF;
    text-shadow: 0 0 5px rgba(0,0,0,0.4);
}

What’s happening here? First the .callout div is given a relative position so that it’s child elements can be positioned relative to it. It’s also given overflow: hidden; to prevent the video from visually overflowing it’s container.

Then the .video-bg and .video-overlay divs are made to take up the whole area of the container using absolute positioning.

The .video-overlay div is given a semi-transparent background to make the content of the callout easier to read. If you don’t want this, feel free to completely remove the div from your HTML.

The .callout-content div has been given some example styles. What goes here is up to your design.

The video itself is the tricky part. First we give it a minimum width and height of 100% to ensure it always is at least as large as it’s container. Then the width properties are set to auto so that they remain in proportion with each-other. From there it’s simply a matter of positioning the video in the centre of it’s container. We’ve chosen to use absolute positioning along with transform: translate(-50%, -50%);. This is necessary because we don’t know exactly how large our video is going to be. This will work in IE9 and up (you should also pass this through an auto-prefixer for the best browser support). The result of all this is a video that will always be centred at least as wide and high as it’s container.

Step 4. Use JavaScript to make some final adjustments

We’ve now got essentially what we came here for. Some might be happy leaving it as-is, but there are a few problems:

  1. There’s no transition from the poster to the first frame of the video, and it might look a bit jerky (remember this is one of the things we wanted to avoid).
  2. iOS doesn’t play nice with video backgrounds – it will add it’s own play button, which when clicked will open up the media player.

Transitioning between the poster and playing video

The approach I take to smooth the transition from poster to first frame is to give the video opacity: 0; then attach an event in JavaScript to transition to full opacity when the video starts playing. This does mean that the poster will never be visible, but that’s fine – we’ll just remove it and instead add it as a background-image to our .video-bg div.

Here’s what that looks like (important parts only).

HTML – remove the poster attribute and add a class telling it to fade in:

<video class="fade-in-video" autoplay loop muted>

CSS – add the poster as a background image instead, and styles for the opacity classes:

.video-bg {
    ...
    background: url(path/to/poster.jpg) center center no-repeat;
    background-size: cover; /* Should be run through an auto-prefixer */
}
.fade-in-video {
    opacity: 0;
    transition: opacity .8s linear;
}
.fade-in-video.is-playing {
    opacity: 1;  
}

JavaScript – add the .is-playing class when the video starts:

var fade_in_videos = document.querySelectorAll('.fade-in-video');
for( i=0; i<fade_in_videos.length; i++ ) {
    fade_in_videos[i].addEventListener("playing", function(){
        this.className += ' is-playing';
    });
}

This JavaScript allows for multiple background videos on your page, and should be placed after all your video tags, or if you’re using jQuery, inside $(document).ready().

Dealing with iOS

To my knowledge, there’s no way around the problems iOS throws up around background images, so I’ve found it best to just remove the video element entirely on iOS. After all, background videos are only an enhancement, they’re not  required to get our point across (and if yours is, you should re-think it).

Just add to your JavaScript:

var iOS = /iPad|iPhone|iPod/.test(navigator.platform);
if( iOS ) {
    var background_videos = document.querySelectorAll('.video-bg video');
    for( i=0; i<background_videos.length; i++ ) {
        background_videos[i].parentNode.removeChild(background_videos[i]);
    }
}

Step 5. Relax

We’re done, and you earned it :)