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

时间:2017-06-15 12:08:58

标签: javascript html css navigation sticky

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

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

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

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

CSS sticky position height adjustment bug

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

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

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

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

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

4 个答案:

答案 0 :(得分:1)

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

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

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

答案 1 :(得分:0)

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);
&#13;
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;
}
&#13;
<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>
&#13;
&#13;
&#13;

答案 2 :(得分:0)

尝试相同的操作后,我可以确认这是一个问题。我在标头上使用了位置粘性,并通过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元素/类/伪

的情况下正确地对此进行编码

答案 3 :(得分:0)

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