Search code examples
javascriptjs-scrollintoview

JavaScript scrollIntoView smooth scroll and offset


I have this code for my website:

function clickMe() {
  var element = document.getElementById('about');
  element.scrollIntoView({
    block: 'start',
    behavior: 'smooth',
  });
}

This works pretty nice but I have a fixed header so when the code scrolls to the element the header is in the way.

Is there a way to have an offset and make it scroll smoothly?


Solution

  • Is there a way to have an offset and make it scroll smoothly?

    #Yes, but not with scrollIntoView()

    The scrollIntoViewOptions of Element.scrollIntoView() do not allow you to use an offset. It is solely useful when you want to scroll to the exact position of the element.

    You can however use Window.scrollTo() with options to both scroll to an offset position and to do so smoothly.

    If you have a header with a height of 30px for example you might do the following:

    function scrollToTargetAdjusted(){
        var element = document.getElementById('targetElement');
        var headerOffset = 45;
        var elementPosition = element.getBoundingClientRect().top;
        var offsetPosition = elementPosition + window.pageYOffset - headerOffset;
      
        window.scrollTo({
             top: offsetPosition,
             behavior: "smooth"
        });
    }
    

    This will smoothly scroll to your element just so that it is not blocked from view by your header.

    Note: You substract the offset because you want to stop before you scroll your header over your element.

    #See it in action

    You can compare both options in the snippet below.

    <script type="text/javascript">
      function scrollToTarget() {
    
        var element = document.getElementById('targetElement');
        element.scrollIntoView({
          block: "start",
          behavior: "smooth",
        });
      }
    
      function scrollToTargetAdjusted() {
            var element = document.getElementById('targetElement');
          var headerOffset = 45;
            var elementPosition = element.getBoundingClientRect().top;
          var offsetPosition = elementPosition + window.pageYOffset - headerOffset;
          
          window.scrollTo({
              top: offsetPosition,
              behavior: "smooth"
          });   
      }
    
      function backToTop() {
        window.scrollTo(0, 0);
      }
    </script>
    
    <div id="header" style="height:30px; width:100%; position:fixed; background-color:lightblue; text-align:center;"> <b>Fixed Header</b></div>
    
    <div id="mainContent" style="padding:30px 0px;">
    
      <button type="button" onclick="scrollToTarget();">element.scrollIntoView() smooth, header blocks view</button>
      <button type="button" onclick="scrollToTargetAdjusted();">window.scrollTo() smooth, with offset</button>
    
      <div style="height:1000px;"></div>
      <div id="targetElement" style="background-color:red;">Target</div>
      <br/>
      <button type="button" onclick="backToTop();">Back to top</button>
      <div style="height:1000px;"></div>
    </div>

    Edit

    window.pageYOffset have being added, to fix the problem related to @coreyward comments