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

(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>

Tiny break: 📬 Want to stay up to date with frontend and trends in web design? Subscribe and get our Collective newsletter twice a tweek.

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.

John Polacek

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.

Stay in the loop: Get your dose of frontend twice a week

👾 Hey! Looking for the latest in frontend? Twice a week, we'll deliver the freshest frontend news, website inspo, cool code demos, videos and UI animations right to your inbox.

Zero fluff, all quality, to make your Mondays and Thursdays more creative!

Feedback 82

Comments are closed.
  1. This is great – so grateful for the tutorial.

    I am currently wracking my brain, trying to create navigation buttons that will take me to each page/div, instead of the ‘next’ button. I’m an amateur, so if anyone can help with this I would appreciate it greatly!

  2. do you have an example of auto slide with dot pagination, left and right click?

    • Here’s the script I use for previous navigation:

      // Prev button click goes to next div $('#prev-btn').on('click', function(e) { e.preventDefault(); if (!isTransitioning) { prev(); } }); function prev() { isTransitioning = true; // update video index, reset image opacity if starting over if (screenIndex === 1) { $bigImage.css('opacity',1); screenIndex = numScreens; } else { screenIndex--; } if (!isTouch) { $('#big-video-wrap').transit({'left':'-100%'},transitionDur) } (Modernizr.csstransitions)? $('.wrapper').transit( {'left':'-'+(100*(screenIndex-1))+'%'}, transitionDur, onTransitionComplete): onTransitionComplete(); }

  3. Hi Luca, thanks for contributing the “previous button” code to this cool slideshow by John.

    I downloaded the demo and like that images are being used (not videos), so naturally a “previous button” should in fact be displayed.
    I tried adding your code into the demo. Would you be able to zip the files with the “previous button” implemented?

    Would be greatly appreciated!!

  4. hi, thanks for this great script.
    I wanted to do this:
    When the last video played go to the first video and start it.
    Is it possible?

    Best Regards,
    Mark

  5. How can i get it on a auto slide?
    I prever a ‘timer’ over ‘end of movie’ because we want to display images as well as videos.

    Best Regards,
    wilco

  6. Does anyone know how to get this to auto advance to the next slide when a video reaches it end? I have been searching for a solution for a long time.

  7. Hey guys!

    I’m having a little problem when adding more than 5 videos.

    I just add the “id=screen-number” and the class “screen”, but it does not work.

    Can anyone help me?

    Thanks!

  8. It is only by me, thet the videos are silent? It is possible to hear the audio of the each video?

  9. Very nice! But it works only with Chrome? What to do that it’s works also with other browsers?

  10. I was able to get a ‘previous’ nav link added to this setup after some tinkering. So I modified my next() method and added a previous() method as follows:
    function next() { isTransitioning = true; // update video index, reset image opacity if starting over if (screenIndex === numScreens) { screenIndex = 1; } else { screenIndex++; } if (!isTouch) { $('#big-video-wrap').transit({'left':'-100%'},transitionDur) } $bigImage.css('opacity',1); $('.homepage-video-slider').transit( {'left':'-'+(100*(screenIndex-1))+'%'}, transitionDur, onTransitionComplete); } function previous() { isTransitioning = true; // update video index, reset image opacity if starting over if (screenIndex === 1) { screenIndex = numScreens; } else { screenIndex--; } if (!isTouch) { $('#big-video-wrap').transit({'left':'100%'},transitionDur) } $bigImage.css('opacity',1); $('.homepage-video-slider').transit( {'left':'-'+(100*(screenIndex-1))+'%'}, transitionDur, onTransitionComplete); }

    Hope that helps someone!

  11. I’m having trouble changing the number of videos or divs from 5. For example, I just want 3 videos. Or maybe 6 videos. The “next” button doesn’t seem to work once you change the amount of videos.