【问题标题】:How to get the height of an element after you scroll past it?滚动过去后如何获取元素的高度?
【发布时间】:2020-04-23 12:27:14
【问题描述】:

在下面的代码 sn-p 中,当您单击标题上的 This is four 文本时,它将向下滚动到第 4 部分。在它向下滚动之前,标题有一定的高度x,在你滚动之后,标题变得粘滞并增加高度。

标题变粘后如何获取标题的高度?我想这样做的原因是滚动并不完全位于每个部分的顶部。该部分一直被切断我认为这是由于粘性标题高度不断变化。所以我想将窗口滚动到粘性标题的高度,以便各部分正确排列。

body {
  margin: 0;
  font-size: 28px;
}

#navbar {
  overflow: hidden;
  background-color: #333;
  padding: 25px 16px;
}

#navbar a {
  float: left;
  display: block;
  color: #f2f2f2;
  text-align: center;
  text-decoration: none;
  font-size: 17px;
  margin-right: 15px;
}

.content {
  padding: 16px;
}

.sticky {
  position: fixed;
  top: 0;
  width: 100%;
  z-index: 100;
  box-shadow: 2px 2px 0 rgba(0, 0, 0, 0.16);
}

.common {
  border: 1px solid black;
  padding: 200px 10px;
  margin-bottom: 20px;
}
<body>
  <div class="header">
    <p>Scroll down to see the sticky effect.</p>
  </div>

  <div id="navbar">
    <a onclick="headerClick(this); return false;" href="#">This is One</a>
    <a onclick="headerClick(this); return false;" href="#">This is Two</a>
    <a onclick="headerClick(this); return false;" href="#">This is Three</a>
    <a onclick="headerClick(this); return false;" href="#">This is Four</a>
  </div>

  <div class="content">
    <div class="common" id="One">This is the first</div>
    <div class="common" id="Two">Two</div>
    <div class="common" id="Three">Three</div>
    <div class="common" id="Four">Four</div>
    <div class="common" id="Five">Five</div>
    <div class="common">Filler div to make scrolling longer</div>
    <div class="common">Filler div to make scrolling longer</div>
    <div class="common">Filler div to make scrolling longer</div>
  </div>

  <script>
    window.onscroll = function() {
      myFunction()
    };

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

    function myFunction() {
      if (window.pageYOffset >= sticky) {
        navbar.classList.add("sticky")
        document.getElementById("navbar").style.padding = "40px 16px";
      } else {
        navbar.classList.remove("sticky");
        document.getElementById("navbar").style.padding = "25px 16px";
      }
    }

    function headerClick(elem) {
      if (elem.innerHTML === 'This is One') {
        document.getElementById("One").scrollIntoView();
      }
      if (elem.innerHTML === 'This is Two') {
        document.getElementById("Two").scrollIntoView();
      }
      if (elem.innerHTML === 'This is Three') {
        document.getElementById("Three").scrollIntoView();
      }
      if (elem.innerHTML === 'This is Four') {
        document.getElementById("Four").scrollIntoView();
      }
    }
  </script>

</body>

【问题讨论】:

    标签: javascript html css


    【解决方案1】:

    问题

    您正在使用的scrollIntoView 函数正在按预期工作。但是,因为您只滚动到元素的 top,所以顶部被 position: fixed 粘性导航栏隐藏。我们能做些什么来解决这个问题?使用scrollIntoView后调整滚动位置。


    解决方法

    您询问了如何在滚动过去后获取元素的高度。您想获取元素的高度,以便在使用scrollIntoView 后调整滚动位置。但是,这不是必需的。只需添加增加navbar 高度的类(或内联样式),然后测量其高度,然后恢复您所做的更改(我在var stickyHeight = ... 上做了此操作)。

    在获得了粘滞元素的高度后,您可以在使用scrollIntoView 后重新调整滚动的位置(通过从scrollIntoView 发生后的位置减去导航栏粘滞高度)。但是,仍然存在问题:当您单击标题时,导航栏尚未修复第一个元素。

    为什么在导航栏尚未修复时单击标题是个问题?这是因为在将导航栏调整为position: fixed 之前,它仍然处于文档的正常流程中,并且它的高度会改变文档的高度。当它被修复时,它会从正常的文档流中取出,并且它的高度会从文档的高度中移除。这意味着当发生这种情况时,我们必须重新调整减法公式。我已经在以下解决方案中做到了。

    为什么第一个元素有问题?嗯,这主要是由于你想要的设计。当条被粘贴时,您根本无法显示元素的最顶部。尝试手动缓慢滚动以了解我的意思。


    解决方案

    这是一个可行的解决方案。请尝试运行它。

    window.onscroll = function() {
      myFunction()
    };
    
    var navbar = document.getElementById("navbar");
    var sticky = navbar.offsetTop;
    // Getting sticky and nonStickyHeight for scroll readjustments
    var nonStickyHeight = navbar.scrollHeight
    var stickyHeight = (() => {
      navbar.style.padding = "40px 16px" // Or add the class that adds padding
      let result = navbar.scrollHeight
      navbar.style.padding = '' // Or remove the class that adds padding
      return result
    })()
    
    function myFunction() {
      if (window.pageYOffset >= sticky) {
        navbar.classList.add("sticky")
        document.getElementById("navbar").style.padding = "40px 16px";
      } else {
        navbar.classList.remove("sticky");
        document.getElementById("navbar").style.padding = "25px 16px";
      }
    }
    
    function headerClick(elem) {
      let firstElementClicked = false
      let navbarIsSticky = false
      
      // Check if navbar is stickied when the headings are clicked
      if (navbar.scrollHeight === stickyHeight) navbarIsSticky = true
      
      if (elem.innerHTML === 'This is One') {
        document.getElementById("One").scrollIntoView();
        firstElementClicked = true
      }
      if (elem.innerHTML === 'This is Two') {
        document.getElementById("Two").scrollIntoView();
      }
      if (elem.innerHTML === 'This is Three') {
        document.getElementById("Three").scrollIntoView();
      }
      if (elem.innerHTML === 'This is Four') {
        document.getElementById("Four").scrollIntoView();
      }
      
      // If the navbar is stickied and it's not the first element, just subtract the stickyHeight from the scroll position
      if (!firstElementClicked && navbarIsSticky) window.scroll(window.pageXOffset, window.pageYOffset - stickyHeight - 5)
      
      else if (firstElementClicked && !navbarIsSticky)
        window.scroll(window.pageXOffset, window.pageYOffset - nonStickyHeight)
      
      // If the navbar is not stickied, you have to take account the nonStickyHeight that will be removed from the document's height when the navbar is stickied
      else if (!navbarIsSticky) window.scroll(window.pageXOffset, window.pageYOffset - nonStickyHeight - stickyHeight - 5)
    }
    * {
      /*scroll-behavior: smooth;*/
    }
    
    body {
      margin: 0;
      font-size: 28px;
    }
    
    #navbar {
      overflow: hidden;
      background-color: #333;
      padding: 25px 16px;
    }
    
    #navbar a {
      float: left;
      display: block;
      color: #f2f2f2;
      text-align: center;
      text-decoration: none;
      font-size: 17px;
      margin-right: 15px;
    }
    
    .content {
      padding: 16px;
    }
    
    .sticky {
      position: fixed;
      top: 0;
      width: 100%;
      z-index: 100;
      box-shadow: 2px 2px 0 rgba(0, 0, 0, 0.16);
    }
    
    .common {
      border: 1px solid black;
      padding: 200px 10px;
      margin-bottom: 20px;
    }
    <body>
      <div class="header">
        <p>Scroll down to see the sticky effect.</p>
      </div>
    
      <div id="navbar">
        <a onclick="headerClick(this); return false;" href="#">This is One</a>
        <a onclick="headerClick(this); return false;" href="#">This is Two</a>
        <a onclick="headerClick(this); return false;" href="#">This is Three</a>
        <a onclick="headerClick(this); return false;" href="#">This is Four</a>
      </div>
    
      <div class="content">
        <div class="common" id="One">This is the first</div>
        <div class="common" id="Two">Two</div>
        <div class="common" id="Three">Three</div>
        <div class="common" id="Four">Four</div>
        <div class="common" id="Five">Five</div>
        <div class="common">Filler div to make scrolling longer</div>
        <div class="common">Filler div to make scrolling longer</div>
        <div class="common">Filler div to make scrolling longer</div>
      </div>
    </body>

    【讨论】:

    • 这太完美了!这正是我接下来要根据该布尔值确定它是否具有粘性。非常感谢!
    • 快速提问firstElementClicked 变量的用途是什么?当我单击标题中的第四个选项卡时,它会向下滚动到第四部分。然后,当您单击第一个选项卡时,它会稍微切断第一部分。
    • @CapturedTree 我已经更新了关于firstElementClicked 变量的代码。该变量用于确定它是否是被单击的第一个元素。为什么我们需要检测这个?因为您的设计不允许第一个框完全显示要粘贴的导航栏。因此,我选择粘贴导航栏,但代价是第一个框的一小部分被覆盖。
    【解决方案2】:

    内容会被剪切,因为它最终位于导航栏后面,因此您可以在 .content 的顶部添加额外的填充,这样当它到达导航栏后面时,它只会展开。

    随意更改值,因为它可能有点紧张,但似乎有你正在寻找的效果。

    window.onscroll = function() {
      myFunction();
    };
    
    var navbar = document.getElementById("navbar");
    var sticky = navbar.offsetTop;
    
    function myFunction() {
      if (window.pageYOffset >= sticky) {
        navbar.classList.add("sticky");
        document.getElementById("navbar").style.padding = "40px 16px";
        document.querySelector(".content").style.paddingTop = "116px";
      } else {
        navbar.classList.remove("sticky");
        document.querySelector(".content").style.paddingTop = "16px";
        document.getElementById("navbar").style.padding = "25px 16px";
      }
    }
    
    function headerClick(elem) {
      if (elem.innerHTML === "This is One") {
        document.getElementById("One").scrollIntoView();
      }
      if (elem.innerHTML === "This is Two") {
        document.getElementById("Two").scrollIntoView();
      }
      if (elem.innerHTML === "This is Three") {
        document.getElementById("Three").scrollIntoView();
      }
      if (elem.innerHTML === "This is Four") {
        document.getElementById("Four").scrollIntoView();
      }
    }
    body {
      margin: 0;
      font-size: 28px;
    }
    
    #navbar {
      overflow: hidden;
      background-color: #333;
      padding: 25px 16px;
    }
    
    #navbar a {
      float: left;
      display: block;
      color: #f2f2f2;
      text-align: center;
      text-decoration: none;
      font-size: 17px;
      margin-right: 15px;
    }
    
    .content {
      padding: 16px;
    }
    
    .sticky {
      position: fixed;
      top: 0;
      width: 100%;
      z-index: 100;
      box-shadow: 2px 2px 0 rgba(0, 0, 0, 0.16);
    }
    
    .common {
      border: 1px solid black;
      padding: 200px 10px;
      margin-bottom: 20px;
    }
    <div class="header">
      <p>Scroll down to see the sticky effect.</p>
    </div>
    
    <div id="navbar">
      <a onclick="headerClick(this); return false;" href="#">This is One</a>
      <a onclick="headerClick(this); return false;" href="#">This is Two</a>
      <a onclick="headerClick(this); return false;" href="#">This is Three</a>
      <a onclick="headerClick(this); return false;" href="#">This is Four</a>
    </div>
    
    <div class="content">
      <div class="common" id="One">This is the first</div>
      <div class="common" id="Two">Two</div>
      <div class="common" id="Three">Three</div>
      <div class="common" id="Four">Four</div>
      <div class="common" id="Five">Five</div>
      <div class="common">Filler div to make scrolling longer</div>
      <div class="common">Filler div to make scrolling longer</div>
      <div class="common">Filler div to make scrolling longer</div>
    </div>

    【讨论】:

      猜你喜欢
      • 2021-12-09
      • 2021-10-15
      • 2020-09-09
      • 2011-08-05
      • 1970-01-01
      • 2012-06-22
      • 2020-04-28
      • 2017-04-29
      • 1970-01-01
      相关资源
      最近更新 更多