December 11, 2017

The first time I saw a video background on a website, I became obsessed. I thought parallax backgrounds were cool, but this was on a different level! Most video backgrounds use the video tag, paired with a small video file that's optimized for the web. With some CSS, you can set the looping video as a background. There are some sites that offer free video backgrounds for download, such as https://coverr.co/.

Eventually, I stumbled upon a jQuery plugin that converts a YouTube video into a background. The plugin takes in a YouTube video id and sets the background for you, using an <iframe> instead of the <video> tag. I had experimented with this plugin on previous sites, but was curious if it can be re-created using Gatsby.js and React.

For this demo, I'm going to be using Gatsby.js and a starter that I've created. In reality, you can do this with any React app, you don't have to use Gatsby if you don't want to. The starter just gives us some content and a layout to work with.

gatsby new gatsby-videobg https://github.com/codebushi/gatsby-starter-dimension cd gatsby-videobg gatsby develop

If you go to http://localhost:8000/ you'll see something like this: http://gatsby-dimension.surge.sh/

Time to kick it up a notch! We'll be installing a React component that plays YouTube videos. There are several to choose from, but I ended up using https://github.com/troybetz/react-youtube

yarn add react-youtube gatsby develop

Open up the main component at /src/layouts/index.js and import the new React component up at the top:

import React from 'react' import '../assets/scss/main.scss' import Helmet from 'react-helmet' import YouTube from 'react-youtube' ;

For the most part, we can leave everything as is. We just need to comment out the existing <div id="bg"></div> and add in the <YouTube /> component and some options. We'll also add some additional HTML structure around the component for styling purposes. The render method should look something like this:

_onReady ( event ) { } _onEnd ( event ) { event . target . playVideo ( ) ; } render ( ) { const siteTitle = this . props . data . site . siteMetadata . title const siteDescription = this . props . data . site . siteMetadata . description const videoOptions = { playerVars : { autoplay : 1 , controls : 0 , rel : 0 , showinfo : 0 } } ; return ( < div className = { ` body ${ this . state . loading } ${ this . state . isArticleVisible ? 'is-article-visible' : '' } ` } > < Helmet > < title > { siteTitle } </ title > < meta name = " description " content = { siteDescription } /> </ Helmet > < div id = " wrapper " > < Header onOpenArticle = { this . handleOpenArticle } timeout = { this . state . timeout } /> < Main isArticleVisible = { this . state . isArticleVisible } timeout = { this . state . timeout } articleTimeout = { this . state . articleTimeout } article = { this . state . article } onCloseArticle = { this . handleCloseArticle } /> < Footer timeout = { this . state . timeout } /> </ div > { } < div className = " video-background " > < div className = " video-foreground " > < YouTube videoId = " Z6FPJOgfCkc " opts = { videoOptions } className = " video-iframe " onReady = { this . _onReady } onEnd = { this . _onEnd } /> </ div > </ div > </ div > ) }

The <YouTube> component needs a videoId and a set of options, which I've defined as videoOptions . We've also added two methods to execute when the player starts and ends. _onReady() is where you can mute the video if needed, or adjust other parameters such as video quality. _onEnd() fires when the video ends, and here we do a playVideo() to do a loop. Check out the react-youtube docs for more uses and options.

That's pretty much it! We'll need to add some CSS to make the resulting <iframe> cover the entire background.

Create a new Sass file at /src/assets/scss/_video.scss with the following:

.video-background { background : #000 ; position : fixed ; top : 0 ; bottom : 0 ; right : 0 ; left : 0 ; z-index : -99 ; & ::after { display : block ; content : '' ; position : absolute ; top : 0 ; left : 0 ; width : 100% ; height : 100% ; z-index : 1 ; background : rgba ( 0 , 0 , 0 , 0.75 ) } } .video-foreground, .video-background iframe { position : absolute ; top : 0 ; left : 0 ; width : 100% ; height : 100% ; pointer-events : none ; } @media ( min-aspect-ratio : 16/9 ) { .video-foreground { height : 300% ; top : -100% ; } } @media ( max-aspect-ratio : 16/9 ) { .video-foreground { width : 300% ; left : -100% ; } }