I want to make left side navigation showing the current visible section. But my sections have different height and I can't figure out how to properly track them.
It would be better if my callback function every time it is invoked could see all entries and their state, but it gets entries that matches threshold values.
I probably missing something out. There should be a way to make this working.
Here is my jsBin https://jsbin.com/homibef/edit?html,css,js,output
stickybits('#sticky', { stickyBitStickyOffset: 0 });
if (window.IntersectionObserver) {
const callback = function(entries) {
// Find all visible and then with biggest intersectionRatio
let currentNav = null;
const visibleEntries = entries.filter(entry => entry.isIntersecting);
if ( Array.isArray(visibleEntries) && visibleEntries.length > 0 ) {
currentNav = visibleEntries.reduce((prev, current) => {
return (prev.intersectionRatio > current.intersectionRatio) ? prev : current;
});
} else {
currentNav = visibleEntries;
}
if (currentNav.target) {
// Handle navigation change
const wasCurrent = document.querySelector('.navItem.isCurrent');
if ( wasCurrent ) {
wasCurrent.classList.remove('isCurrent');
}
const currentName = currentNav.target.getAttribute('name');
const current =
document.querySelector(`.navItem[data-link='${currentName}']`);
current.classList.add('isCurrent');
}
};
const observer = new IntersectionObserver(callback, {
root: null,
rootMargin: '0px',
threshold: [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1],
});
const section = document.querySelectorAll('section');
section.forEach(item => observer.observe(item));
}
* {
margin: 0;
padding: 0;
}
.row {
width: 100%;
display: flex;
flex-wrap: nowrap;
}
.navigation {
margin-right: 50px;
}
.navItem {
color: #666;
}
.navItem.isCurrent {
font-weight: bold;
color: #000;
}
.content {
width: 100%;
flex: 1;
}
section {
padding: 10px;
width: 200px;
border-radius: 10px;
margin-bottom: 30px;
}
.section1 {
height: 800px;
background: #90ee90;
}
.section2 {
height: 200px;
background: #add8e6;
}
.section3 {
height: 150px;
background: #808080;
}
.section4 {
height: 400px;
background: #800080;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/stickybits/3.7.3/stickybits.min.js"></script>
</head>
<body>
<div class="row">
<!-- Navigation -->
<div class="navigation">
<div id="sticky" class="sticky">
<ul class="nav">
<li data-link="section1" class="navItem">Section 1</li>
<li data-link="section2" class="navItem">Section 2</li>
<li data-link="section3" class="navItem">Section 3</li>
<li data-link="section4" class="navItem">Section 4</li>
</ul>
</div>
</div>
<!-- Content -->
<div class="content">
<section name="section1" class="section1"></section>
<section name="section2" class="section2"></section>
<section name="section3" class="section3"></section>
<section name="section4" class="section4"></section>
</div>
</div>
</body>
</html>