scrollIntoView滚动太远了

Mat*_*son 70 javascript dom scroll

我有一个页面,其中包含其中包含div的表行的滚动条是从数据库动态生成的.每个表格行都像一个链接,有点像你在视频播放器旁边的YouTube播放列表中看到的那样.

当用户访问该页面时,他们所在的选项应该转到滚动div的顶部.此功能正常运行.问题是,它太过分了.就像他们选择的选项大约10px太高.因此,访问该页面,该URL用于标识选择了哪个选项,然后将该选项滚动到滚动div的顶部.注意:这不是窗口的滚动条,它是带滚动条的div.

我使用此代码使其将选定的选项移动到div的顶部:

var pathArray = window.location.pathname.split( '/' );

var el = document.getElementById(pathArray[5]);

el.scrollIntoView(true);
Run Code Online (Sandbox Code Playgroud)

它将它移动到div的顶部,但是大约10个像素太远了.有谁知道如何解决这个问题?

fre*_*727 62

您可以分两步完成:

el.scrollIntoView(true);
window.scrollBy(0, -10); // Adjust scrolling with a negative value here
Run Code Online (Sandbox Code Playgroud)

  • 如果`scrollIntoView()`在`scrollBy()`运行之前尚未完成滚动,则后者滚动将取消前者。至少在Chrome 71上。 (15认同)
  • 有没有办法直接将像素的校正器注入到scrollIntoView中,以便使应用程序直接移动到相关位置?就像 `scrollIntoView({ adjustment:y})` 一样,我认为最后应该可以使用自定义代码 (3认同)

Imt*_*que 51

我通过使用解决了这个问题,

element.scrollIntoView({ behavior: 'smooth', block: 'center' });
Run Code Online (Sandbox Code Playgroud)

这使得元素出现在center滚动后,所以我不必计算yOffset.

希望能帮助到你...

  • 很好,这应该是最高评论! (3认同)

Ste*_*ton 49

绝对方法定位锚点

另一种方法是将您的锚点准确定位在页面上您想要的位置,而不是依赖于按偏移量滚动.我发现它允许更好地控制每个元素(例如,如果你想要某些元素的不同偏移量),并且可能更能抵抗浏览器API的变化/差异.

<div id="title-element" style="position: relative;">
  <div id="anchor-name" style="position: absolute; top: -100px; left: 0"></div>
</div>
Run Code Online (Sandbox Code Playgroud)

现在,偏移量被指定为相对于元素的-100px.创建一个函数来创建这个锚用于代码重用,或者如果你使用现代JS框架如React通过创建一个渲染你的锚的组件来做这个,并传入每个元素的锚名称和对齐方式,这可能会或者可能会不一样.

然后使用:

const element = document.getElementById('anchor-name')
element.scrollIntoView({ behavior: 'smooth', block: 'start' });
Run Code Online (Sandbox Code Playgroud)

用于平滑滚动,偏移量为100px.

  • 这是迄今为止顺利和简单地实现这一目标的最佳方式. (7认同)
  • 当“页面顶部”类型链接位于导航栏下方,并且您想要显示导航,但不希望任何其他链接偏移时,这特别有用 (3认同)
  • 我认为最好和最原生的方法。 (2认同)

Ars*_*-II 44

平滑滚动到正确的位置

获取正确的 y坐标并使用window.scrollTo({top: y, behavior: 'smooth'})

const id = 'profilePhoto';
const yOffset = -10; 
const element = document.getElementById(id);
const y = element.getBoundingClientRect().top + window.pageYOffset + yOffset;

window.scrollTo({top: y, behavior: 'smooth'});
Run Code Online (Sandbox Code Playgroud)

  • 这是最正确的答案 - 我们可以使用 `jQuery('#el').offset().top` 轻松找到滚动位置,然后使用 `window.scrollTo` (4认同)
  • 可能是此页面上最简单,最优雅的解决方案。我希望我可以将其进一步提高。 (3认同)
  • 内联 HTML 的单行:`window.scrollTo({top: document.getElementById("yourElem").getBoundingClientRect().top + window.scrollY - 50, 行为: "smooth"});` (3认同)
  • 此解决方案+1。当我的容器相对于顶部偏移定位时,它帮助我正确滚动到元素。 (2认同)
  • 任何使用 HashLink 和 React Router 来到这里的人,这对我来说都是有用的。在 HashLink 上的滚动属性中,`scroll={el =&gt; { const yCooperative = el.getBoundingClientRect().top + window.pageYOffset; 常量 yOffset = -80; window.scrollTo({ 顶部: y坐标 + yOffset, 行为: '平滑' }); }}` -- 偏移量比标题大小多 10-15 像素,只是为了更好的间距 (2认同)
  • 只有“getBoundingClientRect”的问题才会触发强制布局/回流,这是性能瓶颈。话虽这么说,如果用得省钱的话,那是完全没问题的! (2认同)

Luc*_*ski 38

如果它大约10px,那么我想你可以简单地手动调整包含div的滚动偏移量:

el.scrollIntoView(true);
document.getElementById("containingDiv").scrollTop += 10;
Run Code Online (Sandbox Code Playgroud)

  • 它可以动画,只需添加`el.scrollIntoView({behavior:'smooth'});`.虽然支持不是很好! (10认同)
  • 这会具有与 `scrollIntoView` 相同的动画效果吗? (2认同)
  • 这很有效,只是方向错误,所以我所要做的就是将其从 += 10 更改为 -= 10,现在它加载得恰到好处,非常感谢您的帮助! (2认同)

Pos*_*hin 17

在 20 秒内修复它:

该解决方案属于@Arseniy-II,我只是将其简化为一个函数。

function _scrollTo(selector, yOffset = 0){
  const el = document.querySelector(selector);
  const y = el.getBoundingClientRect().top + window.pageYOffset + yOffset;

  window.scrollTo({top: y, behavior: 'smooth'});
}
Run Code Online (Sandbox Code Playgroud)

用法(您可以直接在 StackOverflow 中打开控制台并进行测试):

_scrollTo('#question-header', 0);
Run Code Online (Sandbox Code Playgroud)

我目前正在生产中使用它,它工作得很好。

  • 这对我来说是一种享受,我还添加了一行来动态确定所需的偏移量。我的内容位于导航下方,因此我获取了要作为 yOffset 传入的导航高度 ```const yOffset = document.getElementById('nav_id').getBoundingClientRect().height``` 我还必须稍微修改为`-` 是 `yOffset` 而不是 `+`,因为我的内容在页面上滚动得太远(在导航下方) (3认同)

Mal*_*hid 11

最简单的方法是,

html, body {
    scroll-behavior: smooth;
}

    html [id], body [id] {
        scroll-margin: 50px !important;
    }
Run Code Online (Sandbox Code Playgroud)

用您提供的代码

var pathArray = window.location.pathname.split( '/' );
var el = document.getElementById(pathArray[5]);
el.style.scrollMargin = '50px';
el.scrollIntoView(true);
Run Code Online (Sandbox Code Playgroud)

  • 这是正确的解决方案。它是通用的,因此适用于页面上的所有内容,但它是正确的概念。谢谢@马利克·扎希德 (2认同)

Rya*_*How 8

这对我在Chrome中有效(滚动流畅且无计时漏洞)

它只是移动元素,启动滚动,然后将其移回。

如果元素已经在屏幕上,则没有可见的“弹出”。

pos = targetEle.style.position;
top = targetEle.style.top;
targetEle.style.position = 'relative';
targetEle.style.top = '-20px';
targetEle.scrollIntoView({behavior: 'smooth', block: 'start');
targetEle.style.top = top;
targetEle.style.position = pos;
Run Code Online (Sandbox Code Playgroud)

  • 这是最好的解决方案...希望它被标记为答案。本来可以节省几个小时。 (4认同)
  • 对其进行了测试,它开箱即用。不是黑客,而且效果很好!给这个投一票吧! (2认同)

Nic*_*ray 6

您也可以使用这些element.scrollIntoView() 选项

el.scrollIntoView(
  { 
    behavior: 'smooth', 
    block: 'start' 
  },
);
Run Code Online (Sandbox Code Playgroud)

大多数浏览器都支持

  • 但是,这不支持任何偏移选项. (28认同)

小智 6

基于先前的答案,我正在Angular5项目中进行此操作。

开始于:

// el.scrollIntoView(true);
el.scrollIntoView({
   behavior: 'smooth',
   block: 'start'
});
window.scrollBy(0, -10); 
Run Code Online (Sandbox Code Playgroud)

但这带来了一些问题,需要为scrollBy()设置setTimeout,如下所示:

//window.scrollBy(0,-10);
setTimeout(() => {
  window.scrollBy(0,-10)
  }, 500);
Run Code Online (Sandbox Code Playgroud)

它在MSIE11和Chrome 68+中完美运行。我没有在FF中测试过。500ms是我冒险的最短延迟。降低滚动有时会失败,因为平滑滚动尚未完成。根据您自己的项目进行调整。

对于这个简单但有效的解决方案,请向Fred727 +1 。

  • 平滑滚动到一个元素然后向上滚动一点感觉有点笨拙。 (8认同)

小智 6

假设您要滚动到DOM中所有处于相同级别并且具有类名“ scroll-with-offset”的div,那么此CSS将解决此问题:

.scroll-with-offset {    
  padding-top: 100px;
  margin-bottom: -100px;
}
Run Code Online (Sandbox Code Playgroud)

与页面顶部的偏移量为100px。它将仅按预期与块:“开始”一起工作:

element.scrollIntoView({ behavior: 'smooth', block: 'start' });
Run Code Online (Sandbox Code Playgroud)

发生的情况是div的最高点在正常位置,但其内部内容在正常位置下方100px开始。这就是padding-top:100px的用途。margin-bottom:-100px用于抵消以下div的额外利润。为了使解决方案完整,还添加以下CSS以抵消最顶部和最底部div的边距/填充:

.top-div {
  padding-top: 0;
}
.bottom-div {
  margin-bottom: 0;
}
Run Code Online (Sandbox Code Playgroud)


Fer*_*dao 5

我已经得到了这个,它对我来说非常有效:

// add a smooth scroll to element
scroll(el) {
el.scrollIntoView({
  behavior: 'smooth',
  block: 'start'});

setTimeout(() => {
window.scrollBy(0, -40);
}, 500);}
Run Code Online (Sandbox Code Playgroud)

希望能帮助到你。


小智 5

另一种解决方案是使用“offsetTop”,如下所示:

var elementPosition = document.getElementById('id').offsetTop;

window.scrollTo({
  top: elementPosition - 10, //add your necessary value
  behavior: "smooth"  //Smooth transition to roll
});
Run Code Online (Sandbox Code Playgroud)


Fli*_*imm 5

CSSscroll-marginscroll-padding

您可能想看看新的 CSS 属性scroll-paddingscroll-margin. 您可以scroll-padding用于滚动容器(html在本例中)和scroll-margin容器内的元素。

对于您的示例,您需要为scroll-margin-top要滚动到视图中的元素添加,如下所示:

.example {
  scroll-margin-top: 10px;
}
Run Code Online (Sandbox Code Playgroud)

这会影响scrollIntoView代码,例如以下代码:

const el = document.querySelector(".example");
el.scrollIntoView({block: "start", behavior: "smooth"});
Run Code Online (Sandbox Code Playgroud)

这将导致视口滚动以将视口的顶部边框与元素的顶部边框对齐,但有 10px 的额外空间。换句话说,元素的这些属性被考虑在内:

  • padding-top
  • border-top
  • scroll-margin-top
  • (而不是 margin-top

此外,如果html元素已scroll-padding-top设置,则也将其考虑在内。

  • 如果您使用的是 Vue 这样的框架,您可能需要确保在运行“scrollIntoView”之前完成对 DOM 的所有更改,方法是使用“Vue.nextTick(() =&gt; el.scrollIntoView())”之类的内容 (8认同)
  • 推广您的答案,因为我认为出于性能原因它更好。希望它很快就会更高:) (3认同)