Recently I am developing a simple one page website with 3 sections and I try to use Intersection Observer API to implement a function that allows me to scroll to a part of section and the correct li/link get highlighted on the nav, so for example if I scroll to about section, the about li/link on the nav gets highlighted and others don’t.
Is it doable using the Intersection Observer API cause my sections are all have different heights?
This is what I have now:
HTML
<body>
<header>
<ul>
<li class="li-one">One</li>
<li class="li-two">Two</li>
<li class="li-three">Three</li>
</ul>
</header>
<div class="main-container">
<div class="hero"></div>
<section class="section-one" data-li="li-one">
<h1>Section One</h1>
</section>
<section class="section-two" data-li="li-two">
<h1>Section Two</h1>
</section>
<section class="section-three" data-li="li-three">
<h1>Section Three</h1>
</section>
</div>
<script src="./script.js"></script>
</body>
CSS
*{
margin: 0;
padding:0;
box-sizing: border-box;
}
h1{
width:100%;
text-align: center;
border: 2px solid blue;
}
header{
position: fixed;
background-color: black;
color: white;
width: 100%;
height:70px;
}
header ul{
display: flex;
justify-content: center;
align-items: center;
height: 100%;;
}
header ul li{
padding: 2rem;
list-style: none;
font-size: 1.5rem;
cursor: pointer;
}
.active{
color: orange;
}
.hero{
height: 100vh;
border: 4px solid red;
}
.section-one{
display: flex;
justify-content: center;
align-items: center;
height:250px;
border: 4px solid purple;
}
.section-two{
display: flex;
justify-content: center;
align-items: center;
height:550px;
border: 4px solid green;
}
.section-three{
display: flex;
justify-content: center;
align-items: center;
height:1050px;
border: 4px solid orange;
}
Javascript
const sections = [...document.querySelectorAll('section')];
const observerOptions = {
root: null,
rootMargin: '0px',
threshold: 0.2,
}
const sectionObserver = new IntersectionObserver((entries) => {
entries.forEach((entry) => {
const getLiClass = entry.target.getAttribute('data-li');
const getLiElement = document.querySelector(`.${getLiClass}`);
if(window.innerHeight >= entry.intersectionRect.top / 2 && entry.isIntersecting){
getLiElement.classList.add('active');
}else{
getLiElement.classList.remove('active');
}
});
}, observerOptions);
sections.forEach((section) => {
sectionObserver.observe(section);
});
I have tried different approaches using the intersection observer API and above approaches is my latest but as you can see it doesn’t highlights li/link on the nav one at a time, I also tried an approach that it highlights one at a time but problem with that approach is if I didn’t fully scroll out of a section and just scroll back the highlights li/link on the nav doesn’t respond(for example, scroll past section one to section two(but section one is still in view), the section two li/link gets highlighted and I scroll back to the section one the section one li/link on the nav is not highlighted but section two li/link still highlighted).
Is it doable using the intersection observer API with sections that have different heights?
(The reason I use intersection observer API is because I did some researches and it seems to have better performance compare to using window.addEventListener(‘scroll’,callback).