Skip Navigation
Madison, Wisconsin
Powderkeg Web Design
June 8, 2018

Implementing YouTube Background Videos

Nick
Nick
Implementing YouTube Background Videos

Even though Chrome is trying its best to kill it, background videos aren’t going anywhere. The methods and technology behind them are evolving though!

Enter: YouTube background videos. That’s right, there is now a way to use a youtube video as the background of some nice banner / container on your website.

If you still want to host a video on your website you should definitely keep these best practices and recommendations in mind, but the new Youtube way takes a lot of the guess work out of making the perfect video. They’ve also made it very easy for you to upload and organize your videos, so this is quite an ideal solution for a lot of parties.

The first thing you are going to need is a YouTube video to use. You will need the video id of what you select, which is the part after the “?v” in the URL. So with the url of “https://www.youtube.com/watch?v=GquEnoqZAK0”, the video id is “GquEnoqZAK0”. Typically you want to use videos with no sound. Background videos work best when an overlay is on top of them so being super crisp 4K ULTRA HD isn’t important.

The Code

Before we dig in to the code, here’s a link to a working Code Pen.

The HTML

<html>
  <body>
    <script src="https://code.jquery.com/jquery-3.3.1.min.js" integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8=" crossorigin="anonymous"></script>

    <section id="page-banner" class="bg-image" style="background-image: url('https://images.pexels.com/photos/531880/pexels-photo-531880.jpeg?auto=compress&cs=tinysrgb&h=650&w=940');">
      <div class="overlay">			
        <div class="inner">		
            <h1>YouTube Background Video!</h1>	
        </div>
      </div>
      <div class="video_wrap" style="display:none"><div id="player"></div></div>
    </section>
  </body>
</html>

We have the basic html template with jQuery enqueued. There is a container element with an id of “page-banner” that has a background image. The background image is used as a placeholder while the video is loading or if the video fails to load — so it’s a good idea to make it a relevant image or even the first frame of the video if you can get that.

Inside of the container we have an overlay element that we’re using to drown out the video a little bit and provide a canvas for any text we want on top of it. Overlays are needed on background videos a lot of times because they are either not super great quality or they are not suppose to be a prominent part of the page.

Next, there is an “inner” element with a header tag. This is completely for your own preferences on what you want to show and how you want to show it over the video.

The important part of the HTML is the “video_wrap” element and the inner div with an id of “player”. This acts as a placeholder for where the video iframe is going to be loaded dynamically.

The CSS

* { box-sizing:border-box;  }
#page-banner  { text-align:center; position:relative; background-color:#00176e; color:#ffffff; height:679px; overflow:hidden; }
.bg-image     { background-size:cover; background-position:center center; }
.overlay    { position:relative; background-color:rgba(0,23,110,.9); height:100%; width:100%; z-index:2; }
.inner      { padding-top:50px; }
  h1      { color:#ffffff; margin:0 auto; }
.video_wrap   { height:100%; width:100%; position:absolute; left:0; overflow:hidden; top:0; padding-bottom:56.5%; } 
iframe      { height:100%; position:absolute; width:100%; top:0; left:0; }

The css for this is relatively straight forward. An important thing to note is the box-sizing:border-box on everything. Most frameworks have this and the sizing won’t be quite right if you do not use it yourself.

Setting a height on your #page-banner container with an overflow of hidden is important as well. All of the inner elements have a relative height so there needs to be something set with an actual value. The background video also bleeds out of the container so we need to hide the overflow. There is also some background properties for the placeholder image to just make sure it covers the available space and it is centered vertically and horizontally.

The overlay has a typical background color with opacity applied to it so you can see through while also having something to work with if you want text.

The inner and header tag again are just there for you to flavor however you want.

Video wrap and iframe are both absolutely positioned so it always starts in the top left corner of the container. The video_wrap has a padding-bottom of 56.5% and is hidden by default. This is actually very important. YouTube videos follow a specific ratio of width and height (16:9) with a black background showing through on the left and right if your viewing area is larger than the video. This percentage is exactly what it it needs to show in the full size of the viewing area without the black borders. It is hidden so that nothing shows while the video loads. We only want to show this video_wrap if/when the video is ready to play.

The Javascript

// Loads the YouTube IFrame API JavaScript code.
var tag = document.createElement('script');
tag.src = "https://www.youtube.com/iframe_api";
// Inserts YouTube JS code into the page.
var firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);

var player;

// onYouTubeIframeAPIReady() is called when the IFrame API is ready to go.
function onYouTubeIframeAPIReady() {
  	player = new YT.Player('player', {
    	height: '360',
      width: '640',
      videoId: 'GquEnoqZAK0',
      playerVars: { 'autoplay': 1, 'controls': 0, 'showinfo': 0, 'rel': 0, 'enablejsapi':1, 'wmode' : 'transparent'},
      events : {
     	 	'onReady' : pkOnPlayerReady,
         'onStateChange' : pkOnPlayerStateChange
      }
  	});
}

function pkOnPlayerStateChange(e) {
  	var frm = $(e.target.getIframe());
  	if (e.data === YT.PlayerState.ENDED) {
      if ('player' === frm.attr('id')) {
          player.playVideo();
      }
  	}
  	if (e.data === YT.PlayerState.BUFFERING) {
      if ('player' === frm.attr('id')) {
         e.target.setPlaybackQuality('hd720');
		}
  	}
}
function pkOnPlayerReady(e) {
	player.mute();
 	e.target.setPlaybackQuality('hd720');
}

//Load a youtube pixel
var pkEnableYoutube = function() {
     var deferred = jQuery.Deferred();
     var img = new Image();
     img.onload = function() { return deferred.resolve(); };
     img.onerror = function() { return deferred.reject(); };
     img.src = "https://s.ytimg.com/yts/img/pixel-vfl3z5WfW.gif?"+ new Date().getTime();
     return deferred.promise();
};

//When the video starts to load, set a timer for the video wrap to fade in
jQuery(function($){
	$.when(pkEnableYoutube()).done(function(){
		setTimeout(function() {
	 		$('.video_wrap').fadeIn();
	 	}, 2000);
	});
});

This is the bread and butter of what makes the magic happen. Basically we’re creating a script element and calling the YouTube iframe API. When that script is loaded and ready it fires off an event called “onYouTubeIframeAPIReady”. We can hook in to this and set the video properties such as height, width, and video id to load. We also set parameters for the video such as autoplaying and hiding the controls. This hook also listens for events as well that we hook in to next. This iframe replaces the “player” id element.

pkOnPlayerStateChange checks to see if the video is over and then plays it again. It checks any time the state of the video changes ( such as when it starts or when it ends ). This creates a loop if that is what you are going for. You can comment out that portion if you do not want it to play more than once. It also makes sure the video quality is set to 720p. That appears to be a good quality for displaying a video without it loading slow or being hard to make out due to poor compression.

The other event from the “ready” call is pkOnPlayerReady. This is mutes the video ( if you have chosen a YouTube video that has sound ) and also sets the video quality.

pkEnableYoutube is a function that creates an image object and attempts to load a pixel from the YouTube servers. Honestly the exact reasoning behind this is somewhat of a mystery to me, but I believe it has something to do with checking to make sure the YouTube servers are up and running and can load video. The idea being that if the pixel can’t load then the video certainly won’t. We’re using the jQuery promise API to check for this pixel. If it loads, the promise is fulfilled and we run the block of code to fade the video_wrap in. We wrap this in a 2 second timeout to make sure the video has definitely had time to load. If you show it too soon you will see the loading animation. Doing it this way ensures that the transition from placeholder image to actual playing video is seamless.

You can see this in actual over at Code Pen.

That’s it! Depending on how you want to apply this, you may need to tweak a few things here or there but the basics should remain the same.

Nick Kalscheur

Nick Kalscheur

Lead Developer