Staying Fixed on Scroll
An introductory article to how to make things stay in position while you scroll and my first entry in my developer journal.
Forward
This is my first post in a series of new articles I am writing as I brush up on web development skills for a new opportunity. It is my intention to share my findings as well as some opinion on each topic. I hope you are able to get something out of these or at least offer a place for conversation. I’m happy to take recommendations or critiques as long as they are constructive and present a good argument for everyone to gain from.
For my first topic, I wanted to get a better understanding of the technique of sticking elements to a fixed position on the screen as the user scrolls down the page. I have seen this technique being used more lately and have not used it as much in my own work.
Sometimes things just need to stay put on the page.
Background
As browsers have advanced more and more in what they have been able to support, so have the front-end patterns. One such pattern is the scrolling element or “sticky” element. This technique is applied when an element of a web page is fixed or stuck in position as the user is scrolling down the page. Right now, the Medium site uses this for its top-level navigation. Go ahead try to scroll down and notice the navigation bar continues to be at the top. By doing this, it adds the convenience of not having to scroll back up the page to click on a main link such as Login. Before learning this technique, I felt this was achieved through lots of JavaScript code to handle the re-positioning of the element. What I have come to find out is that it’s actually a pretty simple solution that involves CSS and a little bit of JavaScript.
The Technique
Thanks to the CSS property position
and a value of fixed
, you can literally stick something on the screen and it will not move on scroll. Think of it as absolute positioning but it does not scroll away when the page scrolls. I think once front-end engineers saw this, they immediately felt relief after of all those years of using frames to keep elements fixed on the screen.
To set an element as fixed, all that is required is a position value of fixed:
.fixed {
position: fixed;
}
I have used the class .fixed
to explicitly state that any element that needs to be fixed should use this class. You can use whatever selector you would like inside your work, it does not matter! By doing this it offers the flexibility of adding this class to any element when needed.
From here, the element’s physical position on the screen can be set by using traditional position properties such as top, right, bottom, left when fixed.
One important note about using position:fixed on an element, it will pop out of the default flow of the layout.
Any elements after the fixed element will flow underneath it if they are not offset accordingly. Think of when you set an element to position: absolute and the flow is interrupted. This can be a gotcha for some layouts as elements declared after the fixed element will shift around due to the position change.
Now that we know how to make an element fixed, it’s only the beginning. The real fun part comes from setting up the response of window scrolling. Unfortunately, CSS does not give us a threshold property and value to state when the element should be fixed on the screen. This task is more of a logic decision and needs to be done in JavaScript.
The setup for when the element should be fixed is actually very simple when broken down into three phases:
- Check when page is scrolling.
- Test if the page has scrolled over a threshold amount.
- Add the .fixed class to the element to make it sticky/fixed.
Each one of these phases we can handle in JavaScript with very little code. I’m sure there are many plugins and frameworks that can do this easily, but understanding the technique requires knowing how to write it from scratch.
Let’s begin with each phase. First, we need to handle when the page is scrolled. Easy, there’s a “scroll” event we can use from the window element. Let’s set that up in a<script>
<script>
window.addEventListener("scroll", function(){
}
</script>
Perfect, now we have a callback function being run each time the page is being scrolled. Let me stress this up-front, what you place inside this event callback, the function(){ }
, will be run each time you scroll so do not place code that takes a long time to execute.
Having lots of code running inside the scroll callback can lead to sluggish performance on your web page.
Moving on to our next phase, we need to know how much the page has scrolled and compare that value to our threshold. To do that, we can use the scrollTop
attribute on the document’s body element (see note at end of this paragraph.) The scrollTop value is updated as the whole page scrolls and is critical for this technique. Also during this phase, a threshold number is needed to determine when the fixed property is added. For this example, let’s use 25
as our threshold. This means that after the page has scrolled 25 pixels down or more, we can make our decision to add the position: fixed;
property.
Before we get into the code, browsers handle the scrollTop property differently on the document body element. This StackOverflow post got me going in the right direction as it describes the various quirks and background information that need to be taken into account.
<script>
window.addEventListener("scroll", function(){
if ( document.body.scrollTop >= 25 || document.scrollingElement.scrollTop >= 25 || document.documentElement.scrollTop >= 25 ){
// do something!
}
}
</script>
The final phase here is the best part of the technique. The .fixed
class that was created earlier with the position: fixed;
inside, can now be applied using our threshold if-statement. I chose applying a class to an element as I believe it is more flexible if you want to re-use this technique or test it using developer tools. You could apply the styles directly to the element, but then your style code is inside your JavaScript and is less maintainable.
Here’s the final update of the JavaScript with this taken into consideration. I also added an else statement to remove the class if the scrollTop is less than our threshold.
<script>
var sticky_el = document.querySelector('.sticky');
window.addEventListener("scroll", function(){
if ( document.body.scrollTop >= 25 || document.scrollingElement.scrollTop >= 25 || document.documentElement.scrollTop >= 25 ){
sticky_el.classList.add('fixed');
} else {
sticky_el.classList.remove('fixed')
}
}
</script>
Notice here I added a variable to store the HTML element we are going to be adding/removing the class from. I felt it was important to only make the call to get the element once and store it as a variable. That variable could then be used each time the scroll event fires as opposed to looking for it each time, therefore increasing performance. I also want to point out that I’m using the classList
Web API to quickly add or remove the class from the element. This has good support on modern browsers so you shouldn’t have too much trouble.
With all of these phases now complete, we should have a working example of a fixed element on our web page that responds to scroll. Obviously, there would be more content inside the HTML and styles inside the CSS, but the overall concept is here for you to use. In preparing to write this article, I setup an example Codepen to illustrate a real example of how this could be used. Please feel free to fork it or use it for your own code if you would like.
Conclusion
Thank you for joining me on this first article and I hope to publish many more in the future regarding web development. I’m interested in your thoughts below if you have any and if you got something out of this, share the love by clicking on the recommendation icon below.