Search code examples
skrollr

Update browser's URL hash id/anchor on scrolling with Skrollr


So your page consists of sections, each section has a unique id or anchor and you would like browser's URL update with current section's id/anchor as you scroll.

PS I'm not asking a question but rather sharing a recipe. All relevant code examples and demo are in the answer, so please don't vote against this question.


Solution

  • This is possible with Skrollr! But you'll need to help him.

    First, create a menu with links to page sections: >

    <nav><ul>
      <li><a href='#home'>Home</a></li>
      <li><a href='#about'>About</a></li>
      <li><a href='#goods'>Goods</a></li>
      <li><a href='#services'>Services</a></li>
    </ul></nav>
    

    Tie each <li> to corresponding page section with Skrollr's data-anchor-target (read this for info). Then add some Skrollr transitions:

    <li
      data-anchor-target="#about"
      data--200-center-bottom="opacity: 0.2;"
      data--200-center-top="opacity: 1;"
      data-200-center-bottom="opacity: 1;"
      data-200-center-top="opacity: 0.2;"
    >
    

    From now on, Skrollr will apply the skrollable-between classname to those <li> elements, whose corresponding page sections are currently visible on the page. And we're gonna exploit that feature! :D

    When initializing Skrollr, you can assign a callback to the render parameter. This callback will fire during scrolling. In that callback, you need to:

    1. Retrieve the list of currently active menu items (those who have the skrollable-between classname).
    2. Decide which of the active menu items to consider current. If there's only one active item, the choice is obvious. If there's more than one, i suggest you pick the second one.
    3. Retrieve the value of the href attribute of the link of the current menu item.
    4. Update browser URL with that value.

    Note that Skrollr hijacks vanilla browser behavior of scrolling the page to the current item on page load. So we have to work around that. Even worse, Skrollr executes the render callback multiple times on page load, resetting the browser's URL hash to that of the first page section. To work around this issue:

    1. Before initializing Skrollr, read the hash from browser's URL.
    2. Set a timer for 500-1000 ms that would reset the hash scroll the page to the beginning of the corresponding section. The simpliest way to do this is to use the click method of the skrollr-menu plugin.

    The timer approach is kinda ugly. If you have a better idea, please leave a comment here.

    Another issue you'll have to work around is the fact that Skrollr executes render callback hundreds of times per second during scrolling. You definitely don't want your callback to run that much: that's completely unnecessary and will slow down the browser.

    So you need to throttle your callback. If you happen to use a standard library extension plugin like Lo-Dash in your project, use it's throttle method. If you don't, you can use the tiny jquery.timer-tools plugin.

    Here's a demo that embraces all of the above, written in comfy CoffeeScript: