One of the most frequently seen patterns in web design is to hide the header on page load until the user scrolls and when the page hits a specific point.
You may choose to use jQuery or vanilla Javascript to implement this but whichever tool you use, you need to be able to obtain the top/bottom positon of the target element relative to the scroll position of the page.
In this tutorial, we'll get our hands dirty and build a simple page with a header and some content. The header is not shown at page load but when the user scrolls the page to a certain point, it appears. When he/she scrolls past a certain point, the header becomes invisible again.
Table of Contents
- An Overview of Our Example
- HTML & CSS
- Query and Store Elements
- Element.getBoundingClientRect()
- window.scrollY
- Event Listener
- Conclusion
An Overview of Our Example
This is what we'll build:
The header is only visible when the page is scrolled within a range.
HTML & CSS
Let's prepare our html code and give it some CSS first.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style>
section {
margin-bottom: 100px;
}
div {
background-color: black;
color: white;
display: flex;
justify-content: center;
padding: 300px 0;
}
ul {
list-style: none;
display: flex;
justify-content: flex-end;
margin: 0;
padding: 0;
}
li a {
display: block;
padding: 20px;
}
header {
width: 100%;
visibility: hidden;
opacity: 0;
position: fixed;
top: 0;
left: 0;
background-color: white;
transition: all 0.5s ease-in-out;
}
header.show {
visibility: visible;
opacity: 1;
}
</style>
</head>
<body>
<header>
<nav>
<ul>
<li>
<a href="#section1">Section1</a>
</li>
<li>
<a href="#section2">Section2</a>
</li>
<li>
<a href="#section3">Section3</a>
</li>
</ul>
</nav>
</header>
<main>
<section id="section1">
<div>Section 1</div>
</section>
<section id="section2">
<div>Section 2</div>
</section>
<section id="section3">
<div>Section 3</div>
</section>
<section id="section4">
<div>Section 4</div>
</section>
<section id="section5">
<div>Section 5</div>
</section>
</main>
<script>
// todo: implement header behavior.
</script>
</body>
</html>
At this point, nothing will happen when you scroll the page because we haven't implemented our Javascript code yet. We'll do this in the next steps.
Query and Store Elements
Let's start by querying and storing the relevant elements in variables as we'll need them later.
...
<script>
const section2 = document.querySelector('#section2')
const section3 = document.querySelector('#section3')
const header = document.querySelector('header')
</script>
Next comes one of the key steps in our implementation. We want to add the show
class name to our header when the top of section2 hits the top of the window as we scroll and remove the class name when the bottom of section3 reaches the top of the window. To achieve this, we need 3 values:
- The y position of the top of section2
- The y position of the bottom of section3
- How much the document is scrolled
To obtain value 1 and 2, I'm going to call the getBoundingClientRect()
method on section2 and section3 elements and to get value 3, I'll use scrollY
of the window
object.
Element.getBoundingClientRect()
This method returns an object containing the following properties:
- left: pixels from the left of the viewport to the left of the element
- top: pixels from the top of the viewport to the top of the element
- right: pixels from the left of the viewport to the right of the element
- bottom: pixels from the top of the viewport to the bottom of the element
- x: equal to the value of left
- y: equal to the value of top
- width: width of the element including padding and border
- height: height of the element including padding and border
You can see that this method is very powerful because we can get the position and size of an element in one shot. Check out MDN to learn more about it.
We'll need the top value of section2 and bottom value of section3. Add the following code:
...
<script>
...
// add these
const {top: top_} = section2.getBoundingClientRect()
const {bottom: bottom_} = section3.getBoundingClientRect()
</script>
window.scrollY
This property of the window
object gives us the number of pixels the document is scrolled vertically.
To achieve the expected behavior of our header, we'll check window.scrollY
against the top_
and bottom_
to decide whether to add or remove the show
class name in the next step.
Event Listener
Now it's time to wire up our scroll event listener.
...
<script>
...
// add these
window.addEventListener('scroll', function() {
if (window.scrollY >= top_ && window.scrollY <= bottom_) {
if (!header.classList.contains('show')) {
header.classList.add('show')
}
} else {
if (header.classList.contains('show')) {
header.classList.remove('show')
}
}
})
</script>
And the full Javascript code looks like this.
<script>
const section2 = document.querySelector('#section2')
const section3 = document.querySelector('#section3')
const header = document.querySelector('header')
const {top: top_} = section2.getBoundingClientRect()
const {bottom: bottom_} = section3.getBoundingClientRect()
window.addEventListener('scroll', function() {
if (window.scrollY >= top_ && window.scrollY <= bottom_) {
if (!header.classList.contains('show')) {
header.classList.add('show')
}
} else {
if (header.classList.contains('show')) {
header.classList.remove('show')
}
}
})
</script>
That's it. Open the page in your browser and make sure it works as expected. If anything goes wrong, double check your code.
Conclusion
In this tutorial, we built a simple page with a dynamic header that appears and disappears based on the scroll position of the document.
At the core of the implementation are the Element.getBoundingClientRect()
method and the window.scrollY
property. You can also make use of them to implement things like back-to-top button which only appears when user scrolls past a certain point.
Top comments (0)