Today I created a menu that highlighted an item depending on the scroll position.
This was the starting point:
HTML<div class = 'Menu'> <div class = 'Item'>Section A</div> <div class = 'Item'>Section B</div> <div class = 'Item'>Section C</div> </div> <div class = 'Content'> <div id = 'A'>Bla bla bla</div> <div id = 'B'>Ble ble ble</div> <div id = 'C'>Bli bli bli</div> </div>
I wanted the menu to be sticky:
CSS.Menu{ display: flex; position: sticky; top: 0; } .Menu .Item.Highlight{ border-bottom: 3px solid black; }
The goal was that, if you scrolled into section A, B or C, the item on the menu highlights accordingly.
On every scroll, you need to calculate the content block which has a shortest and positive distance to the menu:
javascriptconst scrollHandler = () => { let menu = document.querySelector('.Menu') let A = document.getElementById('A') let B = document.getElementById('B') let C = document.getElementById('C') let pos_menu = window.pageYOffset + menu.offsetHeight let pos_A = A.offsetTop + A.offsetHeight let pos_B = B.offsetTop + B.offsetHeight let pos_C = C.offsetTop + C.offsetHeight let distance_A = pos_A - pos_menu let distance_B = pos_B - pos_menu let distance_C = pos_C - pos_menu let min = Math.min(...[distance_A, distance_B, distance_C].filter(num => num > 0)) document.querySelectorAll('.Menu .Item')[0].classList.remove('Highlight') document.querySelectorAll('.Menu .Item')[1].classList.remove('Highlight') document.querySelectorAll('.Menu .Item')[2].classList.remove('Highlight') if(min === distance_A) document.querySelectorAll('.Menu .Item')[0].classList.add('Highlight') if(min === distance_B) document.querySelectorAll('.Menu .Item')[1].classList.add('Highlight') if(min === distance_C) document.querySelectorAll('.Menu .Item')[2].classList.add('Highlight') }
Now attach the function to a scroll listener:
javascriptwindow.addEventListener('scroll', scrollHandler)
To add the smooth animation, use element.scroll()
:
javascript// You'll need to replace element with document.querySelectorAll('.Menu .Item')[n] element.scroll({left: element.offsetLeft, behavior: 'smooth'})
Hi, I'm Erik, an engineer from Barcelona. If you like the post or have any comments, say hi.