How to make sticky, floating videos on page scroll

Last Updated On
How to make sticky, floating videos on page scroll WordPress template

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 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!)

29 responses to “How to make sticky, floating videos on page scroll”

  1. Alexei says:

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

  2. Maurice says:

    Will this work with a vimeo video as well?

  3. hossein says:

    do we have to use your external js and css?
    how we can use just this js and css?

    • Vassilis Mastorostergios says:

      Heya, every theme should have its own style.css so the styles can go there. Also pretty much every theme has its own JavaScript code in a file somewhere, so we suggest the scripts go there :)

  4. danilo says:

    cant make it work on blogger, what do i do ???

  5. Fernando Flores says:

    It is really fantastic, thank you very much for the work. a queries please, if I have more than one video in a publication how to avoid overlapping one another when scrolling through the page. and another question how to put a button to close the floating video.

    • Nik says:

      Hello Fernando.
      Our simple tutorial here was not built with hosting multiple videos on one page I’m afraid and expanding it to do that would not properly fit in a comment reply. However if you are comfortable with reading some simple code I can point you to our Elements Plus! plugin’s code here. Specifically have a look at these three files 1, 2, 3 which essentially built an Elementor element which can in theory handle a case like the one you are describing. Please note that this also has not been extensively tested for such a scenario because we believe that multiple videos would add unneeded noise on a page, but all the parts are there, it should work.
      Best regards.

  6. Jay B says:

    Thank you for the tutorial, but how would you add a close button to the floating video that will reset the video?

  7. Julien says:

    Hi, thank for this trick. Is it possible to achieve same result using a local video file (stored on the web server) and the object, instead of a remote (YT-served) video in an iframe?

    • Vassilis Mastorostergios says:

      Yes absolutely, instead of targeting the iframe you just target the video element in the CSS/JS and you keep the code the same otherwise.

  8. Julien says:

    (I meant the VIDEO object within angle brackets, your comment system automatically removed what was inside the brackets from my previous comment)

  9. Nugetaa says:

    We tried to implement it on our WordPress site, but it doesn’t work. We created our own function, we also implemented css and it doesn’t work.

  10. Lin says:

    Thanks for such an informative post. Would you be able to post the vanilla javascript?

    • Nik says:

      Hello Lin.
      Glad to hear you like the tutorial. Unfortunately we don’t have vanilla JS at hand for this particular example, however you can take a look at this CodePen which offers the same functionality with vanilla JS.

  11. Marco says:

    Thank you for the script.

    Too bad my Html its a bit more complicated than this im not a pro with js

    But i will continue to try, before or after i will made it!

  12. Aldren says:

    what if is ajax loaded and if first video article is done and second article is loaded is this posible if floating video will remove and pause the current video playing? and when I play the second video article and scroll down it the floating video will be the second video article and so on

    • Nik says:

      Hello.
      While something like this is technically possible, I’m afraid such an implementation falls outside of the scope of this tutorial.

Leave a Reply

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

Get access to all WordPress themes & plugins

24/7 Support Included. Join 115,000+ satisfied customers.

Pricing & Sign Up

30-day money-back guarantee. Not satisfied? Your money back, no questions asked.

Back to top