Alrighty, looks like I found a working solution to sidebar nav highlighting on Webflow.
The solution is to add your own jQuery and bypass the default Webflow functionality. This solution assumes you have basic coding knowledge.
First, update the ‘current’ class on your nav items (using the Designer) so that they match the default color of your links. You essentially want to disable Webflow’s current state since it fires at the wrong time.
Next, add the jQuery snippet and CSS below into the Custom Code sections of your page. The jQuery will go before the closing BODY and the CSS will go before the closing HEAD.
You’ll need to update the classes in the jQuery to match your specific use case or follow the same naming convention.
In my case, I added a class name of “side-nav” to the containing DIV within my NavBar element. Then, each of the scroll-to content sections is wrapped in a DIV with the class name “content-block”. These are the same DIVs you’ll add your IDs to for linking.
Reach out if any issues. Good luck.
Thanks to David on this Stackoverflow solution.
CSS for Custom Code HEAD section:
<style>
.nav-active {
color: #bc3f2f !important;
}
</style>
jQuery for Custom Code BODY section:
<script>
// cache the navigation links
var jQuerynavigationLinks = jQuery('.side-nav a');
// cache (in reversed order) the sections
var jQuerysections = jQuery(jQuery(".content-block").get().reverse());
// map each section id to their corresponding navigation link
var sectionIdTonavigationLink = {};
jQuerysections.each(function() {
var id = jQuery(this).attr('id');
sectionIdTonavigationLink[id] = jQuery('.side-nav a[href=\\#' + id + ']');
});
// throttle function, enforces a minimum time interval
function throttle(fn, interval) {
var lastCall, timeoutId;
return function () {
var now = new Date().getTime();
if (lastCall && now < (lastCall + interval) ) {
// if we are inside the interval we wait
clearTimeout(timeoutId);
timeoutId = setTimeout(function () {
lastCall = now;
fn.call();
}, interval - (now - lastCall) );
} else {
// otherwise, we directly call the function
lastCall = now;
fn.call();
}
};
}
function highlightNavigation() {
// get the current vertical position of the scroll bar
var scrollPosition = jQuery(window).scrollTop()+1;
// iterate the sections
jQuerysections.each(function() {
var currentSection = jQuery(this);
// get the position of the section
var sectionTop = currentSection.offset().top;
// if the user has scrolled over the top of the section
if (scrollPosition >= sectionTop) {
// get the section id
var id = currentSection.attr('id');
// get the corresponding navigation link
var jQuerynavigationLink = sectionIdTonavigationLink[id];
// if the link is not active
if (!jQuerynavigationLink.hasClass('nav-active')) {
// remove .active class from all the links
jQuerynavigationLinks.removeClass('nav-active');
// add .active class to the current link
jQuerynavigationLink.addClass('nav-active');
}
// we have found our section, so we return false to exit the each loop
return false;
}
});
}
jQuery(window).scroll( throttle(highlightNavigation,100) );
// if you don't want to throttle the function use this instead:
//jQuery(window).scroll( highlightNavigation );
</script>