位置:粘性 - 结合 javascript 高度调整时滚动弹跳

blu*_*ail 13 html javascript css navigation sticky

position: sticky了一段时间后,我开始为粘性导航实现它,并遇到了这个有趣但令人沮丧的滚动弹跳问题。

这是许多网站上常见的导航行为类型,您通常会使用 javascript 来计算页面中相对元素的偏移量。当元素到达窗口顶部时,将添加一个“卡住”类,使用 将元素从文档流中取出position: fixed,并在其位置添加一个相同高度的虚拟元素以防止页面“跳转” '。此外,通常会看到 javascript 然后缩小该导航的高度以在滚动时节省空间。

position: sticky除了(据我所知)检测元素何时“卡住”之外,CSS 现在似乎处理了所有这些。相反,我使用了一些 javascript 来进行卡住检测,发现一切都很好,直到粘性元素高度需要改变

这很难解释,但它对生产造成了严重破坏 - 所以这是我制作的一个精简示例,以尽可能简单地说明这个问题。

CSS 粘滞位置高度调整bug

当页面的高度正好是合适的长度时,最好的说明是,所以我在元素上设置了一个固定的高度,以确保每个人都能看到相同的东西。您可以添加更多内容,但滚动过去时仍然存在问题。

结果是一些非常奇怪的行为。向下滚动时,导航会粘住,并且当它缩小导航栏时,浏览器自动创建的“虚拟元素”position: sticky似乎与其保持同步。这意味着,当添加卡住类时,整个页面变小,几分之一秒后,导航不再卡住,从而导致故障振动循环。

我测试过的每个浏览器的行为也完全不同。在 chrome 中,这种弹跳永远无法解决,它停留在无限循环中,不断添加/删除卡住的类。更有趣的是,在 Safari 中,滚动位置被“推回”到不会出错的状态。然后在 Firefox 中,它会同时执行这两种操作,在强制滚动位置再次返回之前,会出现一两秒钟的故障。

我想知道是否有人遇到过这种情况,并提出了任何解决方案?我想出的任何 js 解决方法都没有真正起作用或非常好!当然,随着人气的增长,更多的人会去打这个……

欢迎天才的解决方法、技巧、见解或完美的解决方案!

Dti*_*son 5

overflow-anchor: none;在应用会改变其大小(并可能影响窗口大小/元素定位)的更改时,尝试添加到粘性元素。

更新:最终,我找到的正确解决方案是:有一个永远不会改变大小的外部元素(在任何给定的断点处,它的全高始终相同)。那个是粘的。但它也应该没有背景/视觉样式,并且它的有效高度应该由高度 + 底部边距定义(这样它在文档中占用适量的初始空间,但一旦视觉导航实际上不会阻止点击缩小并提供更多空间。

然后有一个改变大小的内部元素,无论是在现实中还是在视觉上。

您还可以使用现代属性,例如包含:布局大小;在内部元素上


cjl*_*750 1

这是我想出的一种解决方法,它在视觉上给出了相同的效果。

看起来,将 a 转换transformheightwithposition: sticky效果很好。你不会得到持续的类切换。

因此,如果我们想将导航高度减半,我们可以通过将scaleY1 更改为 0.5将其压缩一半

这反过来会挤压我们的链接,因此我们将它们放大到原始大小的两倍以抵消挤压,scaleY从 1 调整到 2。

我们要做的最后一个修复是将导航平移到页面顶部以补偿较小的高度。

片段如下。这里的关键部分如下:

nav {
  transform: scaleY(1) translateY(0);
}
nav a {
  transform: scaleY(1);
}
nav.stuck {
  transform: scaleY(0.5) translateY(-50%);
}
nav.stuck a {
  transform: scaleY(2);
}
nav, nav a {
  transition: all 0.6 ease-in-out;
}
Run Code Online (Sandbox Code Playgroud)

前两条规则并不是严格必要的,但我喜欢添加之前和之后的规则,以使事情更加清晰。

nav {
  transform: scaleY(1) translateY(0);
}
nav a {
  transform: scaleY(1);
}
nav.stuck {
  transform: scaleY(0.5) translateY(-50%);
}
nav.stuck a {
  transform: scaleY(2);
}
nav, nav a {
  transition: all 0.6 ease-in-out;
}
Run Code Online (Sandbox Code Playgroud)
nav       = document.querySelector('nav');
section   = document.querySelector('section');

function supportSticky() {
  if(window.CSS && CSS.supports) {
    return CSS.supports("(position: sticky)") || CSS.supports("(position: -webkit-sticky)");
  } else {
    var el = document.createElement("div");
    el.style.position = "sticky";
    return el.style.position == "sticky";
  }
}

function handleScroll() {
  function isStuck(el) {
    return el.offsetTop - section.scrollTop <= 0 ? true : false;
  }

  isStuck(nav) ? nav.classList.add("stuck") : nav.classList.remove("stuck");
}

if (supportSticky()) section.addEventListener('scroll', handleScroll);
Run Code Online (Sandbox Code Playgroud)
html,
body,
h1 {
  margin: 0;
  font-family: arial;
}

section {
  width: 100%;
  max-width: 600px;
  margin: 0px auto;
  box-shadow: 0 1px 7px #ccc;
  height: 378px;
  overflow-y: scroll;
}

header {
  padding: 3em;
}

nav {
  display: flex;
  width: 100%;
  background-color: #ddd;
  justify-content: center;
  padding: 3em;
  box-sizing: border-box;
  position: sticky;
  top: 0;
  transition: all .6s ease-in-out;
  transform: scaleY(1) translateY(0);
}
nav.stuck {
  background-color: red;
  transform: scaleY(0.5) translateY(-50%);
}
nav.stuck a {
  transform: scaleY(2);
}
nav a {
  text-decoration: none;
  color: #fff;
  padding: 1ch 1em;
  background-color: #bbb;
  margin-right: 1em;
  border-radius: 3px;
  transition: all .6s ease-in-out;
}
nav a:hover {
  background-color: #aaa;
}

article {
  padding: 3em;
}
Run Code Online (Sandbox Code Playgroud)