Context
I am making a blog website and I would like to have one sticky element that would be updated which each new year and month as the user scrolls. So that the header would show the current month and year of the listed blog articles.
When coding, I try to achieve an effect with HTML, then CSS if it doesn't work, then JS if it still doesn't. I believe this is good practice as it uses built in features and reduces the needed computing resources but let me know if you do not share this opinion.
Problem
Ideally, the style of the elements would be changed when 'stuck'. For this, I took a look at David Walsh's solution that uses IntersectionObserver
but it glitches when adding more than one element.
The main issue I face is that when having several entries, the script detects an element as 'pinned' when it is at the bottom border of the window.
Code
Here is a snippet. I also have made a jsfiddle with the same code.
//Essentially putting David Walsh's code in a loop
document.querySelectorAll(".myElement").forEach((i) => {
const observer = new IntersectionObserver(([i]) => i.target.classList.toggle("is-pinned", i.intersectionRatio < 1),
{threshold: [1]});
observer.observe(i);
})
#parent {
height: 2000px;
}
.myElement {
position: sticky;
top: -1px;
}
/* styles for when the header is in sticky mode. The transition times accentuate the undesired effect */
.myElement.is-pinned {
color: red;
transition: color 0.3s, background-color 0.3s;
background-color: orange;
}
<div id="parent">
<!-- Adding more than one 'hello' element. The br's are here to add vertical space and be longer than the viewport height -->
<br><br><br><br>
<div class="myElement">Hello!</div>
<br><br><br><br>
<div class="myElement">Hello 2!</div>
<br><br><br><br>
<div class="myElement">Hello 3!</div>
<br><br><br><br>
<div class="myElement">Hello 4!</div>
<br><br><br><br>
<div class="myElement">Hello 5!</div>
<br><br><br><br>
<div class="myElement">Hello 6!</div>
<br><br><br><br>
<div class="myElement">Hello 7!</div>
<br><br><br><br>
<div class="myElement">Hello 8!</div>
</div>