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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | < 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.
1 2 3 4 5 6 7 8 9 | 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.
1 2 3 4 5 6 | .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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 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.
1 2 3 4 5 6 7 | . 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.
1 2 3 4 5 6 | .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.
1 2 3 4 5 6 7 8 9 10 11 | .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.)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | 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 ( 45 deg); -moz- transform : rotate ( 45 deg); -ms- transform : rotate ( 45 deg); -o- transform : rotate ( 45 deg); transform : rotate ( 45 deg); 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.
1 2 3 4 5 6 7 8 9 10 11 12 | <!-- BigVideo Dependencies --> < 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 > <!-- 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.
1 2 3 4 5 6 | $( 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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | $( '#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.
1 2 3 4 5 6 | 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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 | 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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | 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.
1 2 3 4 5 | $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.
0 comments:
Post a Comment