'how to catch scroll event caused by hash bang anchor link?

I am just wondering if there's a better way to approach this

So, say you have jump to link using anchor tag:

www.example.com/#about

opening that link will make browser natively auto-scroll to the section with

<div id="about"></div>

now, I want to catch this scroll event, so that I can add more offset on how much scroll the browser should use.

The reason for this is because I have a fixed navigation menu that consumes 120px of the browser.

Regards,



Solution 1:[1]

AFAIK there is no way to intercept this behaviour directly i.e. there is no user accessible event associated with it. Instead window.location.hash is made available to you. You can find the associated element and jump to it once the page has loaded.

e.g. something like:

function jumpToElement(element, offset) {
  if (!offset) offset = 0;
  var verticalPos = element.offsetHeight;
  window.scrollTo(0, verticalPos + offset);
}
function jumpToHash(offset) {
  var hash = window.location.hash;
  // Do nothing if no hash exists
  if (typeof hash !== 'string' || !hash.length) return;
  var targetElement = document.getElementById(hash);
  // Do nothing if targetElement doesn't exist
  if (!targetElement) return;
  jumpToHash(targetElement, offset);
});
if (document.readyState === "complete") {
  jumpToHash(-120); // with 120px
} else {
  document.addEventListener("DOMContentLoaded", jumpToHash);
}

Solution 2:[2]

You can use jQuery scroll() Method. The scroll event occurs when the user scrolls in the specified element and it works for all scrollable elements and the window object (browser window). The scroll() method triggers the scroll event, or attaches a function to run when a scroll event occurs.

Trigger the scroll event for the selected elements:

$(selector).scroll()

Attach a function to the scroll event:

$(selector).scroll(function)

Example:

var $titlebar = $( '.titlebar' ),
    fixedPosition = function() {
      var pos1 = $titlebar.offset().top,
          winTop = $( window ).scrollTop();
          $( window ).scrollTop( winTop + 1 );
          var pos2 = $titlebar.offset().top;
          $( window ).scrollTop( winTop );
          return ( pos1 != pos2 )
    }(),
    titlebarHeight = fixedPosition ? $titlebar.outerHeight() : 0,
    $menu = $( '.nav a' );
        
$( '.nav a' ).click( function( e ) {
  var $target = $( this.hash );

  e.preventDefault();

  if ( !$( this ).hasClass( 'active' ) ) {
            $( 'html, body' ).stop( true, false ).animate( {
                'scrollTop': $target.offset().top - titlebarHeight
            }, 800 );
        }
    } );

$( window ).on( 'scroll', function() {
  didScroll = true
} );

setInterval( function() {
  if ( didScroll ) {
    didScroll = false;

    var scrollPos = $( document ).scrollTop(),
        windowHeight = ( $( window ).height() - titlebarHeight ) / 2;

        if ( fixedPosition ) {
          $menu.each( function( index ) {
            var $page = $( this.hash );

            if ( $page.position().top <= scrollPos + titlebarHeight + windowHeight ) {
              $( '.nav a.active' ).removeClass( 'active' );
              $menu.eq( index ).addClass( 'active' )
            }
          });
        }
  }
}, 150 );
html,
body,
.contents,
.contents div {
  padding: 0;
  margin: 0;
  height: 100%
}
.titlebar {
  width: 100%;
  position: fixed;
  background-color: black
}
ul {
  padding: 0;
  margin: 0;
  list-style: none
}
.nav li {
  display: inline
}
.nav a {
  display: inline-block;
  padding: 1em;
  color: white;
  text-decoration: none;
  -webkit-transition-duration: .2s;
     -moz-transition-duration: .2s;
       -o-transition-duration: .2s;
          transition-duration: .2s
}
.nav a:hover {
  background-color: #555;
}
.nav a.active,
.nav a.active:hover{
    color: #69452d;
    background-color: #e1ba89;
    cursor: default
}
#home {
  padding: 4em 1em 1em;
  background-color: #b6946b
}
#features {
  padding: 1em;
  background-color: #e1ba89
}
#buy {
  padding: 1em;
  background-color: #ddd
}
#contact {
  padding: 1em;
  background-color: white
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div class="titlebar">
  <ul class="nav">
    <li><a href="#home" class="active">Home</a></li
    ><li><a href="#features">Features</a></li
    ><li><a href="#buy">Buy</a></li
    ><li><a href="#contact">Contact</a></li>
  </ul>
</div>
<div class="contents">
  <div id="home">Home</div>
  <div id="features">Features</div>
  <div id="buy">Buy</div>
  <div id="contact">Contact Us</div>
</div>

Solution 3:[3]

You don't need JS for that, you can just add scroll-margin-top: 120px to that element in CSS.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 danielgormly
Solution 2 Kavian K.
Solution 3 Andy Fazulus