Javascript scrollintoview平滑滚动和偏移

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/49820013/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 04:29:38  来源:igfitidea点击:

Javascript scrollintoview smooth scroll and offset

javascript

提问by Tim Wijma

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?

有没有办法有一个偏移量并使它平滑滚动?

回答by ekfuhrmann

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

S?ren D. Pt?us 的回答让我走上了正确的道路,但我getBoundingClientRect()在没有处于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 hereand implemented it to get this working as intended.

我的解决方案为他的解决方案添加了更多功能,以便getBoundingClientRect()更一致地工作,并具有更多功能。我使用了此处概述的方法并实施了它以使其按预期工作。

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 polyfillwhen implementing this!

记住在实现时包含polyfill

回答by S?ren D. Pt?us

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

有没有办法有一个偏移量并使它平滑滚动?

Yes, but not with scrollIntoView()

是的,但不适用于 scrollIntoView()

The scrollIntoViewOptionsof Element.scrollIntoView()do notallow you to use an offset. It is solely useful when you want to scroll to the exactposition of the element.

scrollIntoViewOptionsElement.scrollIntoView()不会允许你使用的偏移量。当您想要滚动到元素的确切位置时,它仅有用。

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

但是,您可以使用Window.scrollTo()和选项来滚动到偏移位置并平滑地滚动。

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

例如,如果您有一个高度为 的标题,30px您可以执行以下操作:

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>

回答by Moshe L

Simple but elegant solution if the element has a small height(shorter than the viewport):

如果元素的高度很小(比视口短),简单而优雅的解决方案:

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

The block: centerwill scroll the element so the center of the element is at the vertical center of the viewport, so the top header will not cover it.

block: center将滚动元件,因此元件的中心是在视口的垂直中心,所以顶部集流管将不包括它。

回答by Felipe Cupido I?iguez

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

回答by Yulian

I know this is a hack and definitely is something that you should use with caution, but you can actually add a paddingand a negative marginto the element. I cannot guarantee that it would work for you as I don't have your markup and code, but I had a similar issue and used this workaround to solve it.

我知道这是一个 hack 并且绝对是您应该谨慎使用的东西,但您实际上可以在元素中添加一个padding和一个否定margin。我不能保证它对你有用,因为我没有你的标记和代码,但我有一个类似的问题并使用这个解决方法来解决它。

Say your header is 30pxand you want an offset of 15px, then:

假设您的标头是30px并且您想要一个偏移量15px,然后:

  #about {
     padding-top: 45px; // this will allow you to scroll 15px below your 30px header
     margin-top: -45px; // and this will make sure that you don't change your layout because of it
  }