Fullscreen Video Slideshow with BigVideo.js

A tutorial about how to create a slideshow-like fullscreen video background using BigVideo.js, a jQuery plugin for big background video.

Fullscreen Video Slideshow with BigVideo.js

View demo Download source
(Please note that the ZIP file does not contain any video files due to their size.)

BigVideo.js is a jQuery plugin that makes it easy to create fit-to-fill background video on a web page. It can play silent ambient background video (or series of videos), or used as a player to show video playlist.

In this tutorial, we’ll be creating a page that shows a series of video screens, showcasing the free HD stock video footage and animated backgrounds available on Beachfront B-Roll.

Before we get started, give some thought as to whether using this technique at all is appropriate for your project. Background video is bandwidth heavy and can be a big drag on the user’s browser performance. If your site is already video-heavy or incorporating big video is essential to the design and purpose of your site, then using this technique may be a great choice. However, if you can accomplish the same goal with using cinemagraphs for example, maybe that is a better choice. This tutorial is can be helpful to you in either case, as we cover using big background images as well.

The first thing you’ll need to do is get video content. In this case, we went to Beachfront B-Roll and downloaded a few of their free videos. Some of them were quite large in file size, so I used Quicktime Pro to trim them to about 10 seconds or so in length. For each of the videos, we will also need to create a poster image image of the first frame of the video. I used Photoshop to save a 960×540 jpeg for each image. I used a trick of applying a .5 pixel blur and a quality setting of 50 to get a smaller file size (afterall, these are background images, so having a little blurriness on them is not a bad thing).

The Markup

First, let’s do the markup for the page:

We have a header on the center of the screen. Then we have a wrapper div that contains all the different video screens. Then, there is a button we will use to navigate between the screens.

<header>
    <h1>Fullscreen Video Slideshow <span>with BigVideo.js</span></h1>
    <p>The videos in this demo are from <a href="http://beachfrontprod.blogspot.com" target="_blank">Beachfront B-Roll</a>, a great place to download unique HD stock video footage and animated backgrounds for any production purpose (for free!).</p>
    <p><small>A demo for</small> <a href="http://dfcb.github.com/BigVideo.js/" target="_blank">BigVideo.js</a> <small>by <a href="http://twitter.com/johnpolacek" target="_blank" rel="author">@johnpolacek</a></small></p>
</header>

<div class="wrapper">
    <div class="screen" id="screen-1" data-video="vid/bird.mp4">
        <img src="img/bird.jpg" class="big-image" />
        <h1 class="video-title">#1 Bird</h1>
    </div>
    <div class="screen" id="screen-2" data-video="vid/satellite.mp4">
        <img src="img/satellite.jpg" class="big-image" />
        <h1 class="video-title">#2 Satellite</h1>
    </div>
    <div class="screen" id="screen-3" data-video="vid/camera.mp4">
        <img src="img/camera.jpg" class="big-image" />
        <h1 class="video-title">#3 Camera</h1>
    </div>
    <div class="screen" id="screen-4" data-video="vid/spider.mp4">
        <img src="img/spider.jpg" class="big-image" />
        <h1 class="video-title">#4 Spider</h1>
    </div>
    <div class="screen" id="screen-5" data-video="vid/dandelion.mp4">
        <img src="img/dandelion.jpg" class="big-image" />
        <h1 class="video-title">#5 Dandelion</h1>
    </div>
</div>

<nav id="next-btn">
    <a href="#" class="next-icon"></a>
</nav>

The CSS

Before we get into the video, we need to style the page.

Since navigation will be handled by a single big next button, we set the body overflow to hidden. While we’re at it, we’ll make all text on the page white.

html, body {
    margin: 0;
    padding: 0;
    color: #fff;
    overflow: hidden;
    font-family: 'Open Sans Condensed', Arial, sans-serif;
    font-weight: 300;
    font-size: 1em;
}

Next, for the wrapper, we know we have five content screens, so we set the width to 500% (100% per screen) and the height to 100%. We are going to navigate the page by animating the wrapper’s horizontal position, so it will use absolute positioning. We’ll use a z-index of zero to keep the wrapper content in the background.

Note the data-video attribute. This is where our script will grab the url for the video for each screen.

.wrapper {
    position: absolute;
    width: 500%;
    height: 100%;
    z-index: 0;
}

We’ll position the header in the center of the page and make. Also, give it a high z-index so it stays on top of our background content.

header {
    position: absolute;
    top: 50%;
    left: 50%;
    z-index: 999;
    color: #fff;
    background: rgba(0,0,0,0.5);
    padding: 60px;
    width: 400px;
    height: 400px;
    border-radius: 50%;
    margin: -200px 0 0 -200px;
    text-align: center;
}

We want each screen to fill the height and width of the screen, so we set the height to 100%, and the width to 100% divided by the number of screens, in this case this results in 20%. Let’s set them to float left and make the positioning relative so we can absolutely position content inside the screens. We center the position of the image inside the screen div, so we keep the overflow hidden.

.screen {
    position: relative;
    height: 100%; 
    width: 20%; /*  NOTE:numVideos/100%  */
    float: left;
    overflow: hidden;
}

Inside the screen divs, we have a large image of the first frame of the video and a video title. For the image, we use min-width, min-height to make sure the size of the image is never smaller than the size of the .screen container div (which is always the size of the browser window) and set height and width to auto so the image’s aspect ratio is maintained.

.big-image {
    min-width: 100%;
    min-height: 100%; 
    height: auto;
    width: auto; 
}

Let’s put the video titles in the bottom left, make the font size really big and have them be 50% transparent.

.video-title {
    position: absolute;
    bottom: 5%;
    left: 5%;
    opacity: .5;
    margin: 0;
    padding: 0;
    line-height: .65;
    font-size: 4em;
    text-transform: uppercase;
}

Next up, the arrow button. I’ve made a pure CSS arrow button using a technique of putting a box with a border top and left, then rotating that box 45 degrees and putting it inside a div with a large border-radius turning it into a circle. (Note: We will make the rotation work by applying an IE filter for rotating 45 degrees from Boog Design’s excellent Matrix Calculator. See the head of the HTML for the conditional comment.)

nav {
    position:absolute; 
    right: 5%; 
    top: 45%; 
    padding: 20px; 
    background: #000; 
    border-radius: 40px; 
    opacity: .4; 
    cursor: pointer;}
    nav: hover {
    opacity: .6;
}

.next-icon {
    display: block;
    border-top: solid 2px #fff; 
    border-right: solid 2px #fff; 
    width: 20px; 
    height: 20px;
    position: relative;
    left: -5px;
    -webkit-transform: rotate(45deg);
    -moz-transform: rotate(45deg);
    -ms-transform: rotate(45deg);
    -o-transform: rotate(45deg);
    transform: rotate(45deg);
    color: #fff;
    text-decoration: none;
}

The JavaScript

Ok, here’s where we make stuff happen. First, link to all the scripts at the bottom of the page, before the closing body tag. Download the BigVideo.js Github Repo. In addition to BigVideo.js and its dependencies, we will be using jQuery Transit for animations.

<!-- BigVideo Dependencies -->
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.1/jquery.min.js"></script>
<script>window.jQuery || document.write('<script src="js/jquery-1.7.2.min.js"><\/script>')</script>
<script src="js/jquery-ui-1.8.22.custom.min.js"></script>
<script src="js/jquery.imagesloaded.min.js"></script>
<script src="http://vjs.zencdn.net/c/video.js"></script>

<!-- BigVideo -->
<script src="js/bigvideo.js"></script>

<!-- Tutorial Demo -->
<script src="js/jquery.transit.min.js"></script>

Before we get to the video, let’s set up navigation. We will need some vars to help manage navigation.

$(function() {
    var screenIndex = 1,
    numScreens = $('.screen').length,
    isTransitioning = false,
    transitionDur = 1000;
}

Let’s go over what these vars do.

  • screenIndex – keeps track of what screen we are looking at
  • numScreens – the number of screens (in our case 5)
  • isTransition – boolean to prevent extra clicking interfering with the navigation
  • transitionDur – how fast the animation scrolls

Now, add a next button click event and callback to do navigation.

$('#next-btn').on('click', function(e) {
    e.preventDefault();
    if (!isTransitioning) {
        next();
    }
});

function next() {
    isTransitioning = true;
    
    // update video index
    if (screenIndex === numScreens) {
        screenIndex = 1;
    } else {
        screenIndex++;
    }
    
    $('.wrapper').transit(
        {'left':'-'+(100*(screenIndex-1))+'%'},
        transitionDur,
        onTransitionComplete);
}

function onTransitionComplete() {
    isTransitioning = false;
}

Now, that our navigation is working, time to set up the video. When creating a video heavy site, it is important to consider mobile devices. Typically they do not support autoplay, meaning ambient background video will not work. There are tricks to get around this, but we should also consider that it is likely that the user is on a lower bandwidth connection. One thing to consider would be to provide non-video content to these users. In this demo, we will demonstrate how to do that using Modernizr, which you should link to in the document head.

First, add a var for BigVideo (BV) and an isTouch boolean to the top of our script, which gets set by Modernizr’s touch feature detection.

var screenIndex = 1,
    numScreens = $('.screen').length,
    isTransitioning = false,
    transitionDur = 1000,
    BV,
    isTouch = Modernizr.touch;
   

Next, initialize BigVideo for non-touch devices. Create a showVideo() function where we will grab the video filepath from the data-video attribute for the current screen being viewed. Add a showVideo() call to the onTransitionComplete callback function. Also, when the video is loaded and ready to play, we need to fade the framegrab image out. To do that, we use the Video.js api to add a ‘loadeddata’ event listener to the BigVideo player. We attach a callback function to that event which makes the image of the current screen fade out so the video is displayed.

var screenIndex = 1,
    numScreens = $('.screen').length,
    isTransitioning = false,
    transitionDur = 1000,
    BV,
    isTouch = Modernizr.touch;

// Next button click goes to next div
$('#next-btn').on('click', function(e) {
    e.preventDefault();
    if (!isTransitioning) {
        next();
    }
});

if (!isTouch) {
    // initialize BigVideo
    BV = new $.BigVideo({forceAutoplay:isTouch});
    BV.init();
    showVideo();
    
    BV.getPlayer().addEvent('loadeddata', function() {
        onVideoLoaded();
    });

    // adjust image positioning so it lines up with video
    $bigImage
        .css('position','relative')
        .imagesLoaded(adjustImagePositioning);
    // and on window resize
    $(window).on('resize', adjustImagePositioning);
}

// Next button click goes to next div
$('#next-btn').on('click', function(e) {
    e.preventDefault();
    if (!isTransitioning) {
        next();
    }
});

function showVideo() {
    BV.show($('#screen-'+screenIndex).attr('data-video'),{ambient:true});
}

function next() {
    isTransitioning = true;
    
    // update video index, reset image opacity if starting over
    if (screenIndex === numScreens) {
        $bigImage.css('opacity',1);
        screenIndex = 1;
    } else {
        screenIndex++;
    }
    
    if (!isTouch) {
        $('#big-video-wrap').transit({'left':'-100%'},transitionDur)
    }
        
    $('.wrapper').transit(
        {'left':'-'+(100*(screenIndex-1))+'%'},
        transitionDur,
        onTransitionComplete);
}

function onVideoLoaded() {
    $('#screen-'+screenIndex).find('.big-image').transit({'opacity':0},200)
}

function onTransitionComplete() {
    isTransitioning = false;
    if (!isTouch) {
        $('#big-video-wrap')
            .css('left',0);
        showVideo();
    }
}

Tidying up

You may notice that the big image and the big video don’t line up during the fade animation, resulting in a bothersome jump in position.This is because the video is centered inside the screen. To fix the problem, we need also need to center our images. To do that, we create a function that adjusts the positioning of the images.

function adjustImagePositioning() {
    $bigImage.each(function(){
        var $img = $(this),
            img = new Image();

        img.src = $img.attr('src');

        var windowWidth = $window.width(),
            windowHeight = $window.height(),
            r_w = windowHeight / windowWidth,
            i_w = img.width,
            i_h = img.height,
            r_i = i_h / i_w,
            new_w, new_h, new_left, new_top;

        if( r_w > r_i ) {
            new_h   = windowHeight;
            new_w   = windowHeight / r_i;
        }
        else {
            new_h   = windowWidth * r_i;
            new_w   = windowWidth;
        }

        $img.css({
            width   : new_w,
            height  : new_h,
            left    : ( windowWidth - new_w ) / 2,
            top     : ( windowHeight - new_h ) / 2
        })

    });

}

Call the function on document ready and attach it to a window resize event.

$bigImage
    .css('position','relative')
    .imagesLoaded(adjustImagePositioning);
// and on window resize
$(window).on('resize', adjustImagePositioning);

Now the images and videos should be aligned, resulting in a clean transition between the poster image and the video.

Please note that the ZIP file does not contain any video files due to their size.

View demo Download source

Previous:
Next:

Tagged with:

John is a Chicago-based web developer and designer working in the trenches doing big agency/big client work. In his spare time, he writes fun jQuery plugins like Scrollorama, draws indie comics and builds silly sites like areyouabrogrammer.com.

View all contributions by

Website: http://johnpolacek.com

Related Articles

Feedback 82

Comments are closed.
  1. 1

    Preaty cool this bigvideo plugin… Imagine some animation with a video as a background and some html-defined and animated characters moving and interacting on top of it. Fully featured movie using the lates tools and technologies.

  2. 7

    PERFECT entry site but…
    I just can’t figure it out how to make video running. I just see my custom still image. Hmm?
    Help? PLEASE?

    • 10

      Please let us know what browser you are using? Note that the download file does not contain any videos like mentioned in the last part of the tut. Also, you will probably need a server environment for some browsers (i.e. Firefox). Cheers, ML

  3. 11

    Here it plays perfeclty on Firefox (updated) and on IE9.
    But it doesn’t work on Opera (display a still image) and on Google Chrome.

  4. 13

    Firefox playback isn’t as nice due to using a Flash fallback for .h264. I’ve just added the ability to use Ogg or WebM as a second source so that Firefox will play native HTML5 video instead of Flash. I’ve posted Ogg and WebM examples on the repo.

    • 14

      Great! But where I can see the code for all together – mp4, ogv, webm? Because on index.html I saw the code only for mp4. And it does’t work in Firefox – I see only the picture, but not the video.

  5. 16

    Hi John, I have a question, how I can add another picture in to the screen. I mean 6 photo? please help me,.

    <!– *****8

    wall wraps

    outdoor signs

  6. 18

    I can get this to work locally with the video I have chosen, but when I upload, video will never start.

    How do you get the videos you used to load so quickly?

    • 25

      Hi,
      I had some problem first but then I soon realised video playing problem is not a rocket science. :)
      In souce code (html) just enter the name of your video clip you have on your server and that ‘s pretty much it.

      My fresh example from today (still experimenting) downbelow.

      - vid/drift02.mp4 >>> vid is my source map on server / name of the video (you can use, mp4, mov,… just about anything)
      - img/PP.jpg >>> img is source map on server / image is actualy first frame of the video clip

      <!–#1 PP–>

      And USEFUL Quote from Mr. Polacek about he video and options:
      “For best results, I recommend using Vimeo. Sign up for Vimeo Pro, then use their direct mp4 link to serve the video. Vimeo not only has solid bandwidth for delivering video, they do great compression. If you start with a high def source at a bitrate of 10mbps or more, it does such a nice job that you can probably get away with using the standard def source as your background video.”

      Hope it helped! :)

    • 26

      Example was gone so again and without . Hope it will work now.
      SORRY 2 ALL!

      div class=”wrapper”
      div class=”screen” id=”screen-1″ data-video=”vid/drift02.mp4″
      img src=”img/PP.jpg” class=”big-image” /
      !–#1 PP–
      /div
      /div

      Cheers!

Comments are closed.