How to Add a Background Video to Your Homepage with Vimeo

GuidesWeb Developmentvideo backgroundsvimeo

Author: Mike Ciffone

Published: 03.05.2021 / Updated: 03.24.2022

If you’re here for preconnect examples head here
Update: Friday, April 16, 2021: Added a method to destroy the Vimeo iframe on mobile, thus cutting off the “chop segment” requests. 


How To Add a Video Background Without a Plugin

There are a lot of ways to pull off a video background. In my opinion, this is the best way to do it without a plugin.

Why I Was Against Using a Plugin

  • More plugins = more problems
    • Our site uses eleven plugins, and only one of which we depend on for front end functionality (Gravity Forms). The others are all for non-critical back-end services
    • The more plugins you rely on for front end purposes, the less stable your site becomes. I’m not risking a key staple of our site’s design breaking because a plugin wasn’t updated or the developer stopped maintaining it
  • It would also be really awkward to use a plugin for this while at the same time claiming to offer custom WordPress sites. I couldn’t honestly defend that

Should You Use Vimeo Host the Video Background?

Before landing on Vimeo we tried both self hosting and YouTube. At the time we didn’t have caching either.

Vimeo offered the most pros with the least amount of cons. I’ve heard a lot of great things about Wistia, but after taking a look at the features, plans, and pricing I ruled it out. Great platform for video hosting, not designed for one-off video backgrounds. If we did a lot more video content, I would have definitely considered it.

Why I decided to use Vimeo:

  • Self hosting the video was a mess
    • To reliably self host I’d need multiple fallback file types (mp4, webm and logic to decide which to serve), a CDN, as well as load balancing since our content is globally relevant.
    • Also, I’d have to worry about compression and proper caching/headers. No thanks! Not worth the headache.
  • Lowest cost
    • Vimeo Plus unlocks the following:
      • Player customization (must have)
        • Which is required to get rid of the gear icon for quality, sharing options, and is necessary in order to enable certain future optimizations
      • Privacy controls (must have)
        • If using a stock video, think about licensing.
        • Vimeo Plus grants the ability to make a video only privately available
      • Embed anywhere (must have)
      • HDR support (nice to have)
      • Domain level privacy (must have)
        • If there’s another platform that offers all of those customization options at a comparable cost or cheaper, please let me know. I’ll include it in this post.
  • Highest quality background video (vision subjective)
    • The clarity and resolution blew YouTube out of the water. It wasn’t even a contest.
    • I realize that low resolution video is commonly masked with overlays and filters at the sake of page speed. Especially since a video background is primarily a design asset and not intended as consumable content.
    • While that’s true, I’d offer a counter argument centered around the fact that since a video background is a design asset, then it should be beautiful. But I’m also a perfectionist…so I can’t help it.

Now for the important part, the optimization.

Not All Videos Are Suitable for Video Backgrounds

Video backgrounds are awesome, that’s why a lot of sites use them. Here are some guidelines:

  1. Keep the video as short as possible
    1. Our video is 30 seconds long, I wouldn’t recommend trying to use anything longer than that. The longer the video, the larger the file, and the longer it’s going to take for the browser to load it.
  2. Don’t use videos that have a ton of movement and fast transitions. Slow panning landscape shots are great. So are time lapses like we use on our site.The smoother the better.
    1. This will ensure that buffering doesn’t become an issue. It will also help keep file size down. The less moving parts the better.

Vimeo Player Embed Options

 

Option Default Value Video Background Parameters
Background False Set to 1 or true, this hides player controls
Muted False Set to 1 or true, this mutes the video
Autoplay False Set to 1 or true, this plays on page load
Dnt False Set to 1 or true, this blocks tracking of player stats

Below are the proper Vimeo Player SDK embed options for the best performance. While frameborder has been deprecated for a while now (replaced by the CSS ‘border’ property), it is still included for compatibility just in case.


 <iframe src='https://player.vimeo.com/video/".$video_id."?background=1&muted=1&autoplay=1&dnt=1' frameborder='0' allow='autoplay; encrypted-media;'></iframe>

Most of these options are very typical but there is one that I don’t see used very often, which is “dnt=1”.

By default, the Vimeo Player tracks session data and sets cookies in order to provide users to get insights about their views, watch time, etc. This adds unnecessary JavaScript and additional callback requests to Vimeo’s API, and impacts our page load performance.

Since we’re really only using the video as a design element, these metrics are sort of irrelevant. We’ve got nothing to lose by removing it.

Turning this off will improve load time and increase your Lighthouse score. On our site, this improved our mobile Lighthouse score by ~25 points. I saw a slight visual difference, but our site is very light to begin with and I was also spamming refresh all day.

Add Preconnect Headers to Establish an Early Connection With Vimeo’s API

Screen Shot 2021 03 09 at 11.57.15 PM


  <link rel='preconnect' id='preconnect-vimeo-css'  href='https://player.vimeo.com' type='text/css' media='all' />
  <link rel='preconnect' id='preconnect-vimeo-i-css'  href='https://i.vimeocdn.com' type='text/css' media='all' />
  <link rel='preconnect' id='preconnect-vimeo-f-css'  href='https://f.vimeocdn.com' type='text/css' media='all' />

If you have a process for injecting code directly into the <head> of your document, you can copy and paste the above code. Since the video background is critical to our website’s design, but also an extremely large payload, it’s important that we do everything in our power to lighten the load on the browser’s main thread.

When we include preconnect headers, we’re essentially giving the browser a hint of any resources that might give it a hard time so it can grab them first.

We handle preconnects (as well as preloads for fonts) in our functions.php like this:


            
    wp_enqueue_style('preconnect-vimeo', "https://player.vimeo.com", array(), null);
    wp_enqueue_style('preconnect-vimeo-i', "https://i.vimeocdn.com", array(), null);
    wp_enqueue_style('preconnect-vimeo-f', "https://f.vimeocdn.com", array(), null);

 
    function custom_function_to_preload( $html, $handle ){
    
        if( strpos($handle, 'preconnect') === 0 ){

            return str_replace("rel='stylesheet'", "rel='preconnect'", $html);
        }
        return $html;
    }

        

Getting the Video: Example Custom Method

We needed an easy way to change the video file to ensure that anyone on our team could update our video background if needed. So creating custom fields for the within the WP admin backend was the best solution to add that convenience factor. So instead of hard coding the video URL in our script we get it from that database table.

custom wp admin fields for video background static images and urls

Not everyone is going to want to go to that extent, though. Another reason I like Vimeo for video backgrounds is because they allow you to replace a video without changing the URL. So that’s a nice workaround.

replace video without changing link vimeo

Injecting the Markup



<header class="video-header-with-type"><?php

	?><div class="background-video-wrapper"><?php

		?><div class='background-video-inset' 

                    <?php DavidsHelperClass::inline_background_attach( get_sub_field('placeholder')['url'] ); ?><<?php

		    DavidsHelperClass::output_iframe_bg_from_video_link( get_sub_field('video_url') );

		?></div><?php

	?></div><?php

?></header>

 

The CSS


header.video-header-with-type{
    display: block;
    width: 100%;
    max-width: 100%;
    position: relative;
    z-index: 2;
    overflow: hidden;

    >.background-video-wrapper{         
        display: block;
        width: 100%;
        max-width: 100%;
        height: 100%;
        position: absolute;
        top: 0;
        left: 0;
        right: 0;
        bottom: 0;
        z-index: 1;

        >.background-video-inset{
            position: absolute;
            top: 50%;
            left: 50%;
            width: 100%;                
            min-height: 100%;
            min-width: 1350px;
            transform: translate3d(-50%,-50%,0);

            &:before{
                content:'';
                display: block;
                z-index: -1;
                width:100%;
                height: 0;
                padding-top: 56.25%;

            }
            @media(max-width: 900px){
                min-width: 1200px;
            }
            @media(max-width: 600px){
                min-width:800px;
            }
            >iframe{
                position: absolute;
                top: -60px;
                left: 0;
                display: block;
                width: 100%;
                height: calc(100% + 120px);
            }
        }   
    }

    >.inset{
        position: relative;
        z-index: 2;
        display: block;
        width: 100%;
        max-width: 100%;
        background-color: transparentize($black,.55);           

            >.insert{
                height: 648px;
                text-align: center;
                color: $white;
                padding: 0 20px;

                @media(max-width: 1200px){
                    height: 0;
                    padding: 27vw 20px;
                }

                @media(max-width: 600px){
                    padding: calc(100px + 27vw) 20px;
                }
            }
        }
    }
}

Alternate Code Methods for Backgrounds using the Vimeo API

There are a few ways that you can go about adding the actual video code to your website. If you’re not a developer, we encourage consulting a custom WordPress developer, preferably the one built your current website.

There are many ways you can call Vimeo from the client side, below I list two.

This first one does it with a pre-existing iframe.


            
    <html>
        <head>
            <title>{page_title}</title>
        </head>

        <body>

        <iframe src="https://player.vimeo.com/video/{video_id}?background=1&muted=1&autoplay=1&dnt=1" 
    width="{video_width}" height="{video_height}" frameborder="0" allow="autoplay; encrypted- 
    media;"webkitallowfullscreen mozallowfullscreen allowfullscreen"></iframe>

        <script src="https://player.vimeo.com/api/player.js"></script>
        <script>
            <!- Your Vimeo SDK player script goes here ->
        </script>
        </body>
    </html>

        

I would recommend preloading player.js. This resource hint will make the script available to browsers earlier and will be less likely to block the page’s render, improving performance.


<link rel="preload" href="https://player.vimeo.com/api/player.js" as="script" crossorigin>

You can also do it with JavaScript if you’d like. However, HTMLLinkElement.crossOrigin is listed as experimental on MDN.


var preloadLink = document.createElement("link");
preloadLink.href = "myscript.js";
preloadLink.rel = "preload";
preloadLink.as = "script";
preloadLink.crossOrigin = "anonymous";
document.head.appendChild(preloadLink);

Here’s another example that would pass our embed options to Vimeo’s player constructor. In this case everything’s coming from Vimeo, so you don’t have to worry about the iframe on your end.

The HTML


  <html>
      <head>
      <title>Example</title>
      </head>

      <body>
          <div id="videoBackground"></div>

          <script src="https://player.vimeo.com/api/player.js">
          <!- JS goes here ->
          </script>

      </body>
  </html>

The JavaScript


  
        //Always set id or url properties first
	var options = {
	    url: "https://vimeo.com/{vimeo-video-id}",
	    background: true.
	    muted: true,
	    autoplay: true, //I believe background: true also sets autoplay but just in case
	    dnt: true
	};

	//You can also do it like this with the 'id' property of the video
	var options2 = {
	    id: "{vimeo-video-id}",
	    background: true.
	    muted: true,
	    autoplay: true,
	    dnt: true
	  };

	var videoPlayer = new Vimeo.Player('videoBackground', options);

	videoPlayer.on('play', function() {
	    console.log('Video background loaded');
	});

How to Optimize for Mobile Performance

So in my original post I mentioned that I had a ticket open with Vimeo’s technical support about further optimizations that can be made.

Yeah…they never got back to me.

Previously, I had noticed a handful of requests being made just before the DOM is fully complete for resources segment-1.m4s, segment-2.m4s, and so forth. The requests are made to https://180vod-adaptive.akamaized.net/, I still don’t fully understand what they do, but my guess right now is that they’re required for the looping functionality.

It also looks like YouTube delivers content via similar methods because I analyzed a site using it and observed the same effect.

For a month I had wrestled with this trying to figure a way to load the video background on mobile without abusing the browser’s main thread. Until 3g is gone and 4g/lte is supported worldwide, it’s just not going to happen.

If you want mobile performance, which I’m assuming you do if you’re reading this, we can’t show the video on mobile. I’ve come up with a crafty solution that solves for this with one snippet of JavaScript.

Basically, we’re just destroying the iFrames if the user is on a mobile device. If you have more than one iframe on the page that you have the video background, you’ll have to add specificity to your selector.

The way I chose to execute the code was by putting call at the end of the body. So just before the closing tag. This is faster to execute than an onload handler because this waits only for the DOM to be ready, not for all images to load. It also works in every browser.


(function() {      
    let isMobile = window.matchMedia("only screen and (max-width: 650px)" || "only screen and (max-width: 760px)").matches;
    if (isMobile) {
        var iframes = document.querySelectorAll('iframe');
        for (var i = 0; i < iframes.length; i++) {
        iframes[i].parentNode.removeChild(iframes[i]);
        }
    }
});

After implementing this, you’ll still see the Vimeo request show up in the network tab of dev tools but it will be red, as the request was cancelled. We want to use vanilla JS for this because it doesn’t require jQuery, so it’s one less script to call.

You could also do something like this:


document.addEventListener("DOMContentLoaded", function () {

    //verify it
   console.log("DOMContentLoaded");
  })
    

 

If you’re chasing absolute perfection and are looking to shave every millisecond possible, preloading critical js might be for you. This is done by adding a tag with rel=”preload” to the head of the document.


<link rel="preload" as="script" href="critical.js">

This should be done sparingly, you shouldn’t preload more than a few things.

Since the iframe is getting destroyed, you’ll need to need to serve a static thumbnail to replace the iframe.

This pen might be helpful, but I haven’t tested it. It uses YouTube so you’d have to work out the differences and tweak the functionality.

Hopefully this gives you at least a baseline understanding of what an implementation would look like. Check out their official docs for more examples – Link: Vimeo Player SDK Embed Options

I do still think updating to Vimeo Pro to use HTML 5 video instead of the standard iframe will perform the best. I just can’t justify the cost if I’m doing alright with it currently. If you have the budget for it though, or own/manage a site that uses a lot of video, I’d love to hear how it goes.

Feel free to reach me via Linkedin or Twitter with any questions, suggestions, or anything else!
Linkedin
Twitter

Additional Video Background Examples With Vimeo

Here are some additional examples/resources from around the internet that might help you with your own implementation.

Vimeo Full Screen Video Background – by Aaron Bennington
https://codepen.io/abennington/pen/ZONqqv

Here’s an example that styles the iframe using the border-box CSS property that some have found useful.


<style>
body { margin: 0; }
.vimeo-container {
  padding: 0;
  width: 100%;
  height: 100vh;
  overflow: hidden;
  position: relative;
}
iframe {
  box-sizing: border-box;
  width: 177.77777778vh;
  height: 56.25vw;
  min-width: 100%;
  min-height: 100%;
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
}
</style>
<div class="vimeo-container">
  <iframe src="https://player.vimeo.com/video/[videoId]?api=1&background=1&autoplay=1&loop=1" allowfullscreen="allowfullscreen" frameborder="0"></iframe>
</div>

Finally, theres this repo maintained by Pupunzi

https://github.com/pupunzi/jquery.mb.vimeo_player

It’s a jQuery component that’s apparently very simple to implement. It also gives you some versatility with the option to display the video as a background or within a custom player…so if your site also does a ton of video content in general it might be ideal! You’ll still have to optimize it though (the demo seemed very slow to load. There’s a WordPress plugin for it too, however, it hasn’t been updated in a couple years. So if you’re interested in it definitely reach out to Pupunzi and see if he’s still supporting it.