对子 Flex 元素使用位置粘性会导致闪烁,因此使用位置固定和 Javascript 滚动条位置代替

cts*_*cts 6 html javascript css scroll

我有一个导航组件,由一个细长的横幅(应该隐藏在滚动方向上)和一个主导航组成,然后应该粘在顶部并缩小。

我遵循了有关使用 Intersection Observer: Event to detector whenposition:sticky is触发的流行答案

但该解决方案的问题是,我的子元素(flex)在隐藏和显示的粘性横幅之间移动时会导致闪烁。由于明显的原因,我无法删除这些子元素,因此我选择使用 a 来删除这些position: fixedmain-nav元素top: 40px。这意味着瘦横幅会根据需要滚动,但我需要帮助使用 Javascript 获取滚动条位置,然后添加一个类似的类(.isSticky当瘦横幅不再存在时,以确保主导航粘在顶部)。

.isSticky {
 top: 0;
 height: 66px;
}
Run Code Online (Sandbox Code Playgroud)

.isSticky {
 top: 0;
 height: 66px;
}
Run Code Online (Sandbox Code Playgroud)
body { 
 margin: 0;
 height: 200vh;  
}

.skinny-banner{
  background: lightblue;
  height: 40px;
  display: flex;
}

.nav-menu {
  display: flex;
}

.sticky-nav{
  position: fixed;
  top: 40px;                    


  background: salmon;
  transition: .1s;
}

/* styles for when the header is in sticky mode */
.sticky-nav.isSticky{
  top: 0;
  height: 66px;
}
Run Code Online (Sandbox Code Playgroud)

我希望使用普通的 JS、HTML 和 CSS 解决方案,并希望使用包装容器来维护 HTML 结构,并将 slimy-banner 和 nav-menu 作为子项。

Von*_*onC 0

设置一个 JavaScript 来监听窗口上的滚动事件并isSticky根据滚动位置相应地更新类似乎更容易。

我还删除了过渡,以防它参与您看到的闪烁。

body {
  margin: 0;
  height: 200vh;
}

.skinny-banner {
  background: lightblue;
  height: 40px;
  display: flex;
}

.nav-menu {
  display: flex;
}

.sticky-nav {
  background: salmon;
  padding: 0 16px;
}


/* styles for when the header is in sticky mode */

.wrapper.isSticky .sticky-nav {
  position: fixed;
  top: 0;
  height: 66px;
  width: 100%;
}

.wrapper.isSticky .skinny-banner {
  display: none;
}
Run Code Online (Sandbox Code Playgroud)
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>

<body>
  <header>
    <div class="wrapper">
      <div class="skinny-banner">Skinny banner that on scroll down disappears.</div>
      <div class="sticky-nav">Sticky Header that on scroll down sticks to top and shrinks in height when stuck</div>
      <div>Test content 1</div>
      <div>Test content 2</div>
      <div>Test content 3</div>
    </div>
  </header>
  <script>
    document.addEventListener('DOMContentLoaded', function() {
      const wrapper = document.querySelector('.wrapper');
      const skinnyBanner = document.querySelector('.skinny-banner');
      let previousScrollY = window.scrollY;

      function updateSticky() {
        const currentScrollY = window.scrollY;

        if (currentScrollY > skinnyBanner.offsetHeight) {
          wrapper.classList.add('isSticky');
        } else {
          wrapper.classList.remove('isSticky');
        }

        previousScrollY = currentScrollY;
      }

      window.addEventListener('scroll', updateSticky);
    });
  </script>
</body>

</html>
Run Code Online (Sandbox Code Playgroud)

为了确保红色横幅sticky-nav即使在向上滚动时也应该粘在顶部,isSticky一旦用户滚动超过 slimy 的高度-banner,该类就会添加到包装元素中,从而sticky-nav无论滚动方向如何,红色横幅都会粘在顶部。