How to make sticky, floating videos on page scroll

A few days ago we released version 1.1 of our great new magazine theme for WordPress, Public Opinion, and I’m here to share with you the basics of how we added floating, sticky videos to the theme’s video post formats so that you can easily add it on your own website if you wish!

Here’s what we’ll be making (scroll up and down to see it in action, also start playing the video, it won’t stop while repositioning!):

0

This kind of functionality is surprisingly easy to implement, and it applies to any kind of embedded iframe video, without the need of the video provider’s API or cloning the video element. It merely needs a few lines of CSS and some basic JavaScript (we’ll be using Sass and jQuery for this tutorial).

High level overview

For our floating video we’ll be using simple iframe embeds (the example contains a video from YouTube), and our whole approach will be to check whether the user has scrolled past the video’s bottom. When that happens, we’ll add a class on an element that wraps the iframe (with JavaScript), and we’ll force that element into a fixed position, on the bottom right of the viewport (with CSS). When the user scrolls back up, we’ll be removing that class so that the video gets back into its initial place. Simple enough! Let’s get started!

The code

<div class="video-wrap">
  <div class="video">
    <iframe width="600" height="340" src="https://www.youtube.com/embed/pfqkRYSs4Rg" frameborder="0" gesture="media" allowfullscreen></iframe>
  </div>
</div>
HTML

The HTML we’ll be using is pretty simple, but we need to wrap the iframe with two div elements. The .video</code. element is what we'll actually position on the bottom right, and we'll keep its parent (.video-wrap) in place, as a reference of the video's initial position. It'll soon become much clearer why.

@keyframes fade-in-up {
  0% { opacity: 0; }
  100% { transform: translateY(0); opacity: 1; }
}

.video {
  iframe {
    max-width: 100%;
    max-height: 100%;
  }

  &.stuck {
    position: fixed;
    bottom: 20px;
    right: 20px;
    width: 260px;
    height: 145px;
    transform: translateY(100%);
    animation: fade-in-up .25s ease forwards;
  }
}
CSS

That’s pretty much every style we need including the slide up animation.

Notice that we pretty much only provide styles for when the video is stuck (i.e. when it has the .stuck class), and just force the underlying iframe to take up its dimensions. As you can see, what we’re doing here is placing it on the bottom right of the viewport, and reducing its size (width and height). For the added effect, we also sprinkle a fancy sliding up CSS animation.

Making it all work with JavaScript

We’ll just need a mere seventeen lines of jQuery to make everything work:

var $window = $(window);
var $videoWrap = $('.video-wrap');
var $video = $('.video');
var videoHeight = $video.outerHeight();

$window.on('scroll',  function() {
  var windowScrollTop = $window.scrollTop();
  var videoBottom = videoHeight + $videoWrap.offset().top;
  
  if (windowScrollTop > videoBottom) {
    $videoWrap.height(videoHeight);
    $video.addClass('stuck');
  } else {
    $videoWrap.height('auto');
    $video.removeClass('stuck');
  }
});
Making the video float on scroll

Let’s break it down.

On the first few lines we cache the required elements into variables, as a good practice. This avoids needless allocations every time we scroll in the page.

Notice that on line 4 we also store the original video’s height:

...
var videoHeight = $video.outerHeight();
...
Storing the video wrapper's height for later use

The reason we do this is to keep the content below the video from jumping around when we apply position: fixed to the video element. Remember that fixed position elements (like absolutely positioned ones) escape the page’s flow and leave “empty space” behind. When the video floats, we’ll apply this height to its parent wrapper making the content below completely oblivious to the video’s absence. That’s one of the reasons why we needed an extra parent element.

After this basic set up, we’re attaching a scroll event listener to the window element. While we scroll, we keep checking whether the total amount of the window’s vertical scroll is bigger than the distance from the bottom of the video element to the top of the document.

To get the total amount the page is scrolled at any point we use jQuery’s handy .scrollTop method on the window object which gives us exactly that.

To get the bottom vertical position of an element, we only need to calculate its top offset (which is the distance from the top of the element to the top of the document) plus the element’s height. Here’s a small diagram to help you visualize it:

So all we need to check is if the window’s scrollTop amount is greater than the video bottom’s distance from the top, and when it’s true, make the video float by simply applying the .stuck class we coded earlier with CSS.

At the same time, we also apply the initial height to the video’s outermost parent to prevent the content from jumping. When the scroll is back up and the video gets into view (i.e. when windowScrollTop is less than videoBottom) we remove the stuck CSS class and reset the parent’s height to auto!

...

$window.on('scroll',  function() {
  var windowScrollTop = $window.scrollTop();
  var videoBottom = videoHeight + $videoWrap.offset().top;
  
  if (windowScrollTop > videoBottom) {
    $videoWrap.height(videoHeight);
    $video.addClass('stuck');
  } else {
    $videoWrap.height('auto');
    $video.removeClass('stuck');
  }
});
Making the video float

And that’s it! Keep in mind that this technique will work with any kind of video provider, YouTube, Vimeo (pretty much with all of WordPress’s supported video providers), and also any kind of element (doesn’t have to be a video!).

Here’s the final result again:

0

What do you think of floating videos? Helpful or distracting? Let us know in the comments! (Thankfully, our themes include an on/off setting, like with most features!)

3 comments

  1. Alexei says:

    Hello! I really liked it, but it’s impossible to make the video adaptive, help?

    1. Vassilis Mastorostergios says:

      Hello, can you let me know exactly what you mean adaptive?

Leave a Reply

Your email address will not be published. Required fields are marked *