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

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了位置:粘性 - 与javascript高度调整结合使用时滚动弹跳相关的知识,希望对你有一定的参考价值。

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

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

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

这很难解释,但它会对生产造成严重破坏 - 所以这里有一个简单的例子,我已经尽可能简单地说明了这个问题。

CSS sticky position height adjustment bug

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

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

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

我想知道是否有人经历过这个,并想出任何解决方案?我提出的任何js解决方法都没有真正起作用或者非常好!当人气越来越高时,会有更多的人打到这个......

天才的解决方案,黑客,见解或完美的解决方案都欢迎!

答案

(显然你需要更多的声誉来评论而不是答案......)

这似乎是一个合法的布局错误,所以我很好奇浏览器贡献者的意见可能是什么。提出了Chromium和Firefox bug跟踪器中的问题,看看会发生什么:

https://bugs.chromium.org/p/chromium/issues/detail?id=734461 https://bugzilla.mozilla.org/show_bug.cgi?id=1374171

另一答案

I forked your pen

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

似乎将transform而不是heightposition: sticky一起过渡工作得很好。你没有得到常数类切换。

因此,如果我们想要将导航的高度减半,我们可以通过将scaleY从1更改为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;
}

前两条规则并不是绝对必要的,但我希望包括一个前后只是为了使事情更清楚。

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);
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;
}
<section>
  <header>
    <h1>CSS sticky position height adjustment bug</h1>
  </header>
  <nav>
    <a href="">Item 1</a>
    <a href="">Item 2</a>
    <a href="">Item 3</a>
    <a href="">Item 4</a>
  </nav>
  <article>
    <h1>Sticky navigation</h1>
    <p>The navigation above should shrink when it gets to the top.</p>
    
    <h1>There is no 'stuck feature' in CSS</h1>
    <p>So we need javascript to work that out, and set a stuck class.</p>
        
    <h1>But it bounces!</h1>
    <p>Because the dummy element is kept in sync with the nav height...</p>
  </article>
</section>
另一答案

尝试同样的事情后,我可以确认这是一个问题。我在我的标题上使用position sticky并通过JS同时添加一个类(触发一些动画,这些动画改变了高度,如上面描述的CodePen)

var header = document.getElementById("header");
var sticky = header.offsetTop;

window.onscroll = function () {
    if (window.scrollY > sticky) {
        header.classList.add("stuck");
    } else {
        header.classList.remove("stuck");
    }
};

事实上,高度变化会使窗口高度变得混乱,并且当它变小1px时会触发删除动画的else。删除动画会将高度更改回原始大小,然后循环重新开始。

我想知道如何在没有原生stuck元素/ class / pseudo的情况下正确编码

以上是关于位置:粘性 - 与javascript高度调整结合使用时滚动弹跳的主要内容,如果未能解决你的问题,请参考以下文章

Bootstrap 4 - 粘性页脚 - 动态页脚高度

不使用 CSS 位置的 Javascript / jQuery 粘性:已修复

使用“位置:粘性”将元素始终显示在屏幕上

具有不同内容高度的粘性页脚,无需页面刷新

javascript element-ui@1.x版本的动态调整表底部滚动条位置,引用在表格行数超过屏幕高度,并且列较多的情况

在 Mat 表格中无法指定表格的高度并使页眉和页脚具有粘性