Side nav Current state not reflecting current section

I want to set up a simple fixed side nav for in-page sections, and am having trouble with the Current state highlight. If you play with this: https://navtester.webflow.io/ you can see that after jumping back and forth in the nav a couple of times, the Current state in the nav isn’t reflecting the clicked section.

Here’s a screencast: Sidenav2.mp4 - Droplr

Here is my site Read-Only: https://preview.webflow.com/preview/navtester?utm_source=navtester&preview=2d5bd24aed7fa30b85fc3dad50e5fac6

Notes:

  1. The behavior is very dependent on the height of the window; the taller the browser window the easier to trigger and more extreme the effect.

  2. I’ve played with aspects like the height of sections (Auto vs 100%); sticky vs. non-sticky top nav; height of Body, etc., and this issue seems to persist uneffected.

I was surprised that I couldn’t find a tutorial or simple recipe for sticky side navs for page content like this; If there is one and it’s marked up completely differently from my test page, I’d be happy to start fresh from that!

Thanks for any help you can offer!

@garymichael1313 - At the risk of pigeonholing you as “the side nav guy,” I see you were very helpful with some others on similar issues, and wondered if you would mind giving this one a look. I’ve tried to strip it down to it’s simplest form and am stumped as to why it doesn’t work.

It’s been up for a couple of days with no replies, so any thoughts are appreciated greatly!

Your read-only link is down unfortunately. Please share it again.

@dram Thanks, not sure what happened to it! I’ve updated it above in the original post.

OK, so the thing doesn’t work properly since current state is being enabled when the content that is “current” reaches exactly center of the screen (vertically of course), try it and see that it is indeed the case and sometimes our expectations are not what we see. To fix this make sure to give id’s to the headings (not whole sections with headings and content), and then target these headings in the navigation. I cannot check this solution right now but can you please try this?

edit: ok, checked it myself, my ‘solution’ is even worse than it was in terms of showing the section you are at. Gotta think about this

So after pondering on this here is what I think: if your content is going to be long in each section then your nav will work as intended. If your content is short… then you don’t really need that nav at all :smiley:

Thanks for looking into it @dram, if you’re right, it’s pretty typical for me:

  1. I set out to do something that seems like it’s standard (side nav)
  2. It turns out that some factor that seems like it should be irrelevant and a common use case (linked sections with different lengths) breaks it.

Argh. It seems like back when I hand-coded a few simple sites in the '90s that anchor tags always came to the top. I assumed the Webflow/jquery that does the extra stuff like light up the current section in the nav might be breaking that but that there would be a workaround.

Anyway, I appreciate the time you took to look into it. Back to the drawing board, this was just supposed to be the quickest way to do a long page with TOC style persistently visible nav. Since it’s not simple, I guess I’ll look for a simple nav that at least works. Ugh.

Ha, a few days away from this to wait for replies and I forgot the nature of the issue. The sections do scroll properly, it’s just the highlight that’s off. That really is something in the Webflow/jquery code, I wish one of the Webflow folks would weigh in on this. I miss the days when @thesergie was around for troubleshooting…

Well, as I said there is not much you can do from a logical perspective. Currently for the nav to be highlighted something has to happen that would be reflected on the nav, right? So this something is an element’s edge crossing exactly vertical half of the screen. This makes nav to highlight the corresponding link for the crossing section (that is why small first sections will never be highlighted - they never cross the center of the screen).

How do you want it to work differently? So that the highlight happen when an element’s edge crosses some line at the top of the page? In this case sometimes you may end up with most of the text on the page being from the next section but a tiny bit of previous section will juuuust crawl through this upper line and your nav will tell you that you are on the previous section even if it is barely visible.

I guess that seems like it would be preferable as a user experience… It’s possible that there may be some scrolling/use scenario where the way that makes sense to me would be as bad or worse, and I’m just not able to visualize the interaction though.

I suppose there must be some reason they went out of their way to make the action/state indicator inconsistently based on top/middle instead of top/top. Top/top would avoid things like having section 2 highlighted in the landing state on a vertical monitor with tall windows, so it must create some reaallly bad experiences to be worse than that. (I’m seeing that in some one-page templates in the Webflow library).

Meanwhile, looking over some one-page templates here it seems like the current way approach is just to have all the sections be really long (including forcing blank space with vh), as you note would take care of it. I guess for my content, I just have to find a different nav technique. Thanks again for your help.

It is of course possible to make highlight act differently with the help of, say, interactions. Just propose a ux that you think will work the best in most use cases, and we will think of setting the ix in a right way. No worries, I am here to help.

Hi, sorry for late response, did you resolve the menu?

Thanks @dram! I explored interactions for this quickly but didn’t go in deep after my initial idea didn’t look doable. But I think I might be ok simply using the Pressed and Focused states, except for some reason, I can’t get rid of the blue highlight for Current:

…which feels like a Webflow bug, but either way kind of messes up the workaround. Here’s a copy of the test site, that uses Pressed and Focused formatting, but is complicated by that erroneous Current state highlight:

Site: https://navtester-test.webflow.io/

Read-only: https://preview.webflow.com/preview/navtester-test?utm_source=navtester-test&preview=306cf4ee645fbd2f7f68600898c614a8

So, I might be ready to accept what I get from the Pressed and Focused formatting (which sacrifices the auto-highlight on the current section when the user scrolls), but my new problem is getting the Current state formatting to stop auto-highlighting!

Thanks @garymichael1313! I guess the answer is “sort of.”

  • I think I’ve concluded that for my content, which includes some very short sections and some very long ones, the Current state formatting of the nav object simply can’t be made to work, due to the highlight being triggered by the middle of the section instead of the top. (Not sure that if it was triggered by the top instead that the experience would be good, but would love to test it if there was an easy way to change it with a little custom code to modify the Webflow jquery.)

  • As noted to dram here, I think that I would be satisfied just using the Pressed and Focused state formatting because the shortcomings of that are far less egregious with my content than the shortcomings of the Current state auto-highlight.

  • However, as also noted in the screenshot to dram and demonstrated in the copy of the test site, I can’t seem to get the Current state auto-highlight to not activate!

Thanks for any thoughts you have on this seemingly simple issue.

(PS - Neither the Current auto-highlight or the Pressed/Focused highlight approach work perfectly for this content structure, so if I could get rid of the persistent Current state formatting, I might decide that just having a nav with no state highlighting would be the lesser of all the evils…)

Running into the exact same situation here. Very frustrating!
I don’t understand why the Current State triggers the Middle of a section instead of it’s Top.
And worse, why that can’t be changed with a Custom Attribute??

2 Likes

Hi There,

I’m running into the same issue. This is a poor user experience, in my opinion. The ‘current’ state should only be activated when the desired section is at the top of the viewport–the same place it stops after being scrolled to.

The functionality works fine for content sections that take up the whole viewport; otherwise, it’s entirely unusable. I will keep you posted if I discover a solution…

1 Like

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>

Thank you for the solution, I will try it out as soon as i find some time.
@webflow no-code? :upside_down_face:

To anyone needing this. Here’s the code that I built to take care of the need to customize the ‘active section detection’.

I used the code that webflow uses in webflow.js as a starting point, so the final ‘functionality’ will be very close to what you get from Webflow, but you will have better control over the entire ‘thing’ and the code itself will be a bit better to navigate IMO

window.Webflow = window.Webflow || [];

window.Webflow.push(() => {
  function customHandlingOfScroll() {
    const CLASS_FOR_CURRENT_LINKS = "link--points-to-active-section";

    const $win = $(window);
    const $anchors = $('a[href^="#"]');
    const $navbar = $(".w-nav");
    const $secondaryNav = $(".secondary-navbar");

    const viewTop = $win.scrollTop();
    const viewHeight = $win.height();

    /*
     * The lower this number, the closer to the top of the page the
     * 'line' will be to determine if a section is in view or not.
     */
    // const offsetForDeterminingCurrent = viewHeight * 0.5;
    const offsetForDeterminingCurrent =
      ($navbar.height() || 0) + ($secondaryNav.height() || 0);

    $anchors.each((_, anchor) => {
      const $anchor = $(anchor);
      const $sectionThatAnchorPointsTo = $(anchor.hash);

      const sectionTop = $sectionThatAnchorPointsTo.offset().top;
      const sectionHeight = $sectionThatAnchorPointsTo.outerHeight();

      const sectionIsActive =
        $sectionThatAnchorPointsTo.is(":visible") &&
        sectionTop + sectionHeight - offsetForDeterminingCurrent >= viewTop &&
        sectionTop + offsetForDeterminingCurrent <= viewTop + viewHeight;

      /**
       * This will assure that only one element per 'wrapper' is active at a time.
       */
      const prevSiblingAlreadyActive = $anchor
        .prevAll()
        .filter(`.${CLASS_FOR_CURRENT_LINKS}`).length;

      $anchor.toggleClass(
        CLASS_FOR_CURRENT_LINKS,
        sectionIsActive && !prevSiblingAlreadyActive
      );
    });
  }

  customHandlingOfScroll();
  $(window).on("scroll", customHandlingOfScroll);
});

Here’s how Webflow implements things on their side:

@Jeandcc Thanks for this answer (several years ago). I’m having trouble deciphering what I’m meant to swap out of your code to make it apply to mine. Thanks.