Keeping items on the page when scrolling downwards can be a beneficial feature when you have elements that ideally land somewhere near the top of the page but that you want your users to see once they reach the bottom.
If done well, this can also be very aesthetically pleasing.
There are 3 key things to making this work:
1. Detecting the scroll action
2. Tracking the top coordinate of the element you wish to snap
3. Updating the position property of that element to stay fixed
Each of those steps is broken down further below.
Scroll event
JavaScript gives us access to the 'scroll' event which we can attach to the document or window itself, or any individual element as well as long as it includes a scroll bar.
window.addEventListener('scroll', function(e){
console.log(window.scrollY);
});
As you scroll through this page, your scroll location will be visible in the label below:
window.scrollY:
3
Menu top:
A note on performance down below.
Scrolling performance
Note that the scroll event fires at a very fast rate. This is depenant upon the browser, but a good rule of thumb is to avoid doing any type of DOM manipulation in this event as it can cause your webpage to underperform and lag.
We won't have to worry about that in this particular implementation as we are mainly just going to be using the event to monitor the 'y' coordinates of an element and not directly interacting with the DOM.
Tracking the element
Ideally you want to wait until a certain moment in the pages scroll cycle in order to stick any element to the page. Down below I have created a sample menu that you would typically see at the top of any webpage.
If you scroll up to this point, the menu should remain in its default relative position. However, let's assume that we actually want the menu to stick to the top of the page when it reaches that point.
We will be able to do that by tracking the menu's 'top' position. When looking to retrieve an element's absolute position on the page, you should avoid using the CSS properties. If the CSS 'top' property for example has not been set directly, retrieving it in JavaScript will return a blank value.
let top = document.getElementById('menu).style.top; // avoid this
Use the following instead.
element.getBoundingClientRect
If you think that is a poorly named method, then you are right. But it is incredibly useul. Every element on the DOM carries with it this particular function and it essentially returns back the dimensions and position of the element without relying on CSS to do so.
let menu = document.getElementById('menu');
let rect = menu.getBoundingClientRect();
The particular property that we will need for this implementation is the 'top' property. When the top of the menu hits the top of visible page, then we will trigger the style change for it to remain fixed in its place.
And this is where the scrolling event comes into play. The scroll event will continously monitor the position of your elements top property until it reaches that trigger point.
Let's start to put that together.
window.addEventListener('scroll', function(e){
let menu = document.getElementById('sample_menu');
let rect = menu.getBounddingClientRect();
console.log(rect.top);
console.log(rect.left);
console.log(rect.right);
console.log(rect.below);
});
Fixed element
The last step in this implementation is to make the element actually stick to the page. And we can do that with the following CSS:
.menu{
background:#f3f3f3;
box-shadow: 2px 2px 9px #aaa;
position: relative;
}
.menu > div{
display:inline-block;
border-right:solid 1px;
padding: 10px;
}
.menu.stick{
positin:fixed;
top: 0px;
left: 0px;
width: 100%;
z-index: 2000;
}
The last style rule is the one to pay attention to. When the element in question hits the appropriate 'stick' point, we will simply add the 'stick' class which will set the new fixed position.
Note that for this example, I am choosing to set the menu at the very top of the page to the far left and taking up the entire width. That is a design choice and really you can set the element wherever you'd like on the page to achieve the desired effect.
The following code will break down the process of adding/removing the class, because there is a subtle nuance to the whole thing.
window.addEventListener('scroll', function(e){
let menu = document.getElementById('menu');
let rect = menu.getBoundingClientRect();
if (rect.top <= 0){
if (menu.classList.contains('stick') == false)
menu.classList.add('stick');
}
if (window.scrollY < 1900)
{
menu.classList.remove('stick');
}
});
In this case when the menu's top location reaches 0 (or negative), essentially it has hit the top of the page, then we will add the 'stick' class to that element.
Note the check to see if the element already has the class 'stick' added to it. Without the check, JavaScript won't necessarily add the class again to the element, but I have found that there is a slight hit to performance when doing so.
And there you have it. A quick snap on scroll implementation with just a few lines of JavaScript. Note that if you have multiple elements that you'd like to stick to the page, you'll need to perform the same action on each one.
In that case, creating a generalized function will be a more scalable solution to take. I will cover that in a future post.