Javascript scrollintoview smooth scroll and offset

落爺英雄遲暮 提交于 2019-12-12 08:26:19

问题


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?


回答1:


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 - 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 - 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>



回答2:


Søren D. Ptæus's answer got me on the right track but I had issues with getBoundingClientRect() when not at the top of the window.

My solution adds a bit more to his to get getBoundingClientRect() working a bit more consistently with more versatility. I used the approach outlined here and implemented it to get this working as intended.

const element = document.getElementById('targetElement');
const offset = 45;
const bodyRect = document.body.getBoundingClientRect().top;
const elementRect = element.getBoundingClientRect().top;
const elementPosition = elementRect - bodyRect;
const offsetPosition = elementPosition - offset;

window.scrollTo({
  top: offsetPosition,
  behavior: 'smooth'
});

Codepen Example

Remember to include the polyfill when implementing this!




回答3:


I tried the other solutions, but I was getting some strange behavior. However, this worked for me.

function scrollTo(id) {
    var element = document.getElementById(id);
    var headerOffset = 60;
    var elementPosition = element.offsetTop;
    var offsetPosition = elementPosition - headerOffset;
    document.documentElement.scrollTop = offsetPosition;
    document.body.scrollTop = offsetPosition; // For Safari
}

and the style:

html {
    scroll-behavior: smooth;
}



回答4:


simple but elegent, if the element is with a small height:

element.scrollIntoView({ behavior: 'instant', block:'center' });

the block: center make the element in the vertical center of the page, so the top header will not cover it.



来源:https://stackoverflow.com/questions/49820013/javascript-scrollintoview-smooth-scroll-and-offset

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!