tscanlin / tocbot

Build a table of contents from headings in an HTML document.
MIT License
1.37k stars 114 forks source link

is-active-li not set on scroll or click, only on page load #304

Closed kareem closed 1 year ago

kareem commented 1 year ago

Great plugin, thanks for all your hard work on it!

Like the title says: when I click or scroll to a header, the corresponding tocbot li doesn't have is-active-li added to it.

Couple interesting things:

  1. The page generates the TOC based on anchor IDs generated client-side by anchorify.js (see https://github.com/tscanlin/tocbot/issues/273#issuecomment-1048367551)
  2. If I load the page with an anchor in the URL, the related tocbot list item DOES have is-active-li added to it
  3. If I scroll to a header or click on a list, then call tocbot.refresh() from the console, the relevant tocbot li does get is-active-li added to it

Example page: https://www.savio.io/blog/examples-of-content-feedback/

Code:

      <!-- for auto-creating anchor link -->
      <script type="text/javascript" src="{% static 'jquery-anchorify/anchorify.js' %}"></script>

      <script src="https://cdnjs.cloudflare.com/ajax/libs/tocbot/4.18.2/tocbot.min.js"></script>
      <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/tocbot/4.18.2/tocbot.css">

      <script type="text/javascript">
          $(document).ready(function() {
            // This turd is here b/c we need to wait until anchorify is done
            // creating anchor links before we run tocbot to init the TOC.
            // but anchorify doesn't have a built-in callback option so we
            // need to create a manual one and pass it the initTocbot code
            // so tocbot is initialized after anchorify is done running.
            //
            // if we don't do this then clicking on a TOC link doesn't always
            // scroll to the right position.  See
            // https://github.com/tscanlin/tocbot/issues/273#issuecomment-1048367551

              function initAnchors(callback) {
                jQuery('.blog').anchorify();
                callback();
              }

              function initTocbot() {
                tocbot.init({
                  // Where to render the table of contents.
                  tocSelector: '.js-toc-list',

                  // Where to grab the headings to build the table of contents.
                  contentSelector: '.js-toc-content',

                  // Which headings to grab inside of the contentSelector element.
                  headingSelector: 'h2',

                  // For headings inside relative or absolute positioned containers within content.
                  ignoreSelector: '.js-no-anchor',

                  orderedList: false,

                  activeLinkClass: 'is-active-link',
                  activeListItemClass: 'is-active-li',
                  hasInnerContainers: true
                });
                tocbot.refresh();
              }

              initAnchors(initTocbot);
          });
      </script>
tscanlin commented 1 year ago

Hey, glad you like tocbot, thanks for the praise!

And thanks for your thorough example / explanation of the problem. Lol, this is very weird and at first I saw this and thought oh well you can't do overflow-y hidden on the root elements. But then I noticed you had overflow-x: hidden which seems like it should be fine because it keeps the main root element scrollable (y-axis) which is needed for the native browser handling of hash urls to work (which tocbot works with / uses too). Anyway, suffice to say I think if you can just change html, body { overflow-x:hidden } to body { overflow-x:hidden } that should work. Let me know if it does / doesn't work for you. This is a very weird issue and also weird that it happens in firefox too. Anyway, hope that fix works!

tscanlin commented 1 year ago

Hey, did this help resolve the issue?

kareem commented 1 year ago

sorry on vacation right now - emailed you on the plane over.  will take a look at it this week, really appreciate the quick reply, thanks! 🙏

kareem commented 1 year ago

change html, body { overflow-x:hidden } to body { overflow-x:hidden } that should work

This did indeed work! Thanks! I'm not sure I fully understand why it does, though. Are you able to share why that works?

Thank you so much @tscanlin!

tscanlin commented 1 year ago

Glad that worked!

I'm not really sure why exactly it works, but seems to be a weird browser issue, see here for more workarounds: https://stackoverflow.com/questions/47095596/body-overflow-x-hidden-breaks-position-sticky

also this has more info: https://stackoverflow.com/a/44929597/1655810