【问题标题】:How to fix a header on scroll如何在滚动上修复标题
【发布时间】:2013-10-10 02:44:19
【问题描述】:

我正在创建一个标题,一旦滚动到一定数量的像素,它就会修复并保持在原位。

我可以只使用 css 和 html 来做到这一点,还是我也需要 jquery?

我创建了一个演示,以便您理解。任何帮助都会很棒!

http://jsfiddle.net/gxRC9/4/

body{
     margin:0px;
     padding:0px;
}
 .clear{
     clear:both;
}
 .container{
     height:2000px;
}
 .cover-photo-container{
     width:700px;
     height: 348px;
     margin-bottom: 20px;
     background-color:red;
}
 .small-box{
     width:163px;
     height:100px;
     border:1px solid blue;
     float:left;
}
 .sticky-header{
     width:700px;
     height:50px;
     background:orange;
     postion:fixed;
}


【问题讨论】:

  • 如果没有 JS 的帮助,你不会这样做
  • 这种方法和后续答案的问题是您最终依赖的容器不超过您指定的 2000px。这将在生产中失败,因为您需要不断调整。或者您会要求文案撰写者不要添加超出特定字数的更多内容。无论哪种方式,这种方法都无法扩展。
  • 带有 jquery 和 CSS 的东西可以帮助您在滚动时实现粘性标题 - kvcodes.com/2017/03/jquery-simple-sticky-header-on-scroll
  • 检查我的medium article here about sticky headers 应该会有所帮助:D

标签: jquery css header fixed


【解决方案1】:

仅使用 CSS 即可完成

.sticky-header {
  position: sticky;
  top: 0;
  background: orange;
}

body {
  margin: 0px;
  padding: 0px;
}

.clear {
  clear: both;
}

.container {
  height: 2000px;
}

.cover-photo-container {
  width: 700px;
  height: 100px;
  margin-bottom: 20px;
  background-color: red;
}

.small-box {
  width: 163px;
  height: 100px;
  border: 1px solid blue;
  float: left;
}

.sticky-header {
  position: sticky;
  top: 0;
  background: orange;
}
<div class="container">
  <div class="cover-photo-container">
    Please scroll
  </div>
  <div class="small-box"></div>
  <div class="small-box"></div>
  <div class="small-box"></div>
  <div class="small-box"></div>
  <div class="clear"></div>
  <div class="sticky-header">
    This needs to be fixed when hits top of screen
  </div>
</div>

【讨论】:

    【解决方案2】:

    如果用户从下到上滚动文档,我的显示标题的解决方案。

    JS:

    const isMobile = window.innerWidth < 768
    const $header = $('#header')
    let lastScrollTop = 0
    if ( isMobile ) {
        $(window).scroll(function () {
            const scrollTop = window.pageYOffset || document.documentElement.scrollTop
    
            if ( scrollTop < lastScrollTop ) {
                $header.removeClass('header_top')
            } else {
                $header.addClass( 'header_top' )    
            }
    
            lastScrollTop = scrollTop <= 0 ? 0 : scrollTop
        })
    }
    

    CSS

    .header {
        position: fixed;
        top: 0;
        z-index: 70;
        width: 100vw;
        transition: top .5s;
        height: 62px;
    }
    .header_top {
        top: -62px;
    }
    

    【讨论】:

      【解决方案3】:
      custom scroll Header Fixed in shopify:
      
      $(window).scroll(function(){
        var sticky = $('.site-header'),
            scroll = $(window).scrollTop();
      
        if (scroll >= 100) sticky.addClass('fixed');
        else sticky.removeClass('fixed');
      })
      
      
      css:
      
      
      header.site-header.border-bottom.logo--left.fixed {
          position: fixed;
          top: 0;
          left: 0;
          right: 0;
          z-index: 9;
      }
      

      【讨论】:

      • 你应该努力在这里解释你的答案。
      【解决方案4】:

      如果你正在使用 React,我最近发布了 a custom hook,它使你能够做到这一点。您需要为粘性元素提供 ref 以及您希望它粘贴到顶部的元素的 ref。它也会为您处理屏幕“跳转”(如其他回复中所述)。

      const sticky = useRef<HTMLDivElement>(null)
      const container = useRef<HTMLDivElement>(null)
      
      useStickyScroll({
          element: sticky,
          container: container
      })
      

      【讨论】:

        【解决方案5】:

        最简单的方法是: HTML:

        <header>
                <h1>Website</h1>
        </header>
        

        CSS:

        header{
            position: sticky;
            top: 0;
        }
        

        【讨论】:

          【解决方案6】:

          出色的纯 HTML/CSS 解决方案

          在 2019 年使用 CSS3,您完全可以在没有 Javascript 的情况下做到这一点。我经常制作这样的粘性标题:

          body {
            overflow-y: auto;
            margin: 0;
          }
          
          header {
            position: sticky; /* Allocates space for the element, but moves it with you when you scroll */
            top: 0; /* specifies the start position for the sticky behavior - 0 is pretty common */
            width: 100%;
            padding: 5px 0 5px 15px;
            color: white;
            background-color: #337AB7;
            margin: 0;
          }
          
          h1 {
            margin: 0;
          }
          
          div.big {
            width: 100%;
            min-height: 150vh;
            background-color: #1ABB9C;
            padding: 10px;
          }
          <body>
          <header><h1>Testquest</h1></header>
          <div class="big">Just something big enough to scroll on</div>
          </body>

          【讨论】:

          • position: -webkit-sticky; /* Safari */
          • 这在决定您是否可以使用此解决方案时可能会派上用场:caniuse.com/#feat=css-sticky
          【解决方案7】:

          只是在 Rich's answer 上构建,它使用偏移量。

          我修改如下:

          • 在 Rich 的示例中不需要 var $sticky,它什么也没做
          • 我已将偏移检查移至一个单独的函数中,并调用它 在文档准备好以及滚动时,如果页面刷新 向下滚动页面的一半,它会立即调整大小而无需等待滚动触发

            jQuery(document).ready(function($){
                var offset = $( "#header" ).offset();
                checkOffset();
            
                $(window).scroll(function() {
                    checkOffset();
                });
            
                function checkOffset() {
                    if ( $(document).scrollTop() > offset.top){
                        $('#header').addClass('fixed');
                    } else {
                        $('#header').removeClass('fixed');
                    } 
                }
            
            });
            

          【讨论】:

            【解决方案8】:

            希望这一替代解决方案对其他人和我一样有价值。

            情况
            在 HTML5 页面中,我有一个菜单,它是标题内的导航元素(不是标题,而是另一个元素中的标题)。
            一旦用户滚动到它,我希望导航保持在顶部,但在此之前,标题是绝对定位的(所以我可以让它稍微覆盖其他东西)。
            上述解决方案从未触发更改,因为 .offsetTop 不会更改,因为这是一个绝对定位元素。此外,.scrollTop 属性只是最顶部元素的顶部......也就是说 0 并且始终为 0。
            我使用这两个执行的任何测试(与 getBoundingClientRect 结果相同)都不会告诉我导航栏的顶部是否曾经滚动到可查看页面的顶部(再次,如控制台中报告的那样,它们在滚动时只是保持相同的数字发生了)。

            解决方案
            我的解决方案是利用

            window.visualViewport.pageTop
            

            pageTop 属性的值反映了屏幕的可视部分,因此我可以跟踪元素相对于可视区域边界的位置。
            这允许分配给窗口滚动事件的简单函数来检测导航栏顶部何时与可视区域顶部相交并应用样式以使其粘在顶部。

            可能没有必要说,每当我处理滚动时,我都希望使用此解决方案以编程方式响应被滚动元素的移动。
            希望对其他人有所帮助。

            【讨论】:

              【解决方案9】:

              Coops 的答案是一个很好、简单的解决方案,但是,一旦应用了固定类,页面就会变得更短,内容会“跳跃”起来,并且如果页面的长度是滚动距离小于高度的 header 元素,它会出现跳跃,而不是让你看到页面的底部。

              我找到的答案是在将固定的元素(在我的例子中是导航元素)上方添加一个分隔符 div,并将其设置为与导航元素相同的高度,并将其设置为不显示。

              将 .fixed 类添加到 nav 时,显示 .nav-spacer div,删除时将其隐藏。由于页面高度会立即改变,因此我将持续时间设置为 0。

              HTML

              <header>the element above the element that will become fixed</header>
              <div class="nav-spacer"></div>
              <nav></nav>
              

              CSS

              nav {
                  position: relative;    
                  height: 100px;
              }
              .nav-spacer{
                  position: relative;
                  height: 100px;
                  display: none;
              }
              .fixed {
                  position: fixed;
                  top:0;
                  left:0;
                  width: 100%;
                  /* I like to add a shadow on to the fixed element */
                  -webkit-box-shadow: 0px 5px 10px 1px rgba(0,0,0,0.25);
                  -moz-box-shadow: 0px 5px 10px 1px rgba(0,0,0,0.25);
                  box-shadow: 0px 5px 10px 1px rgba(0,0,0,0.25);
              }
              

              JavaScript

              var stickyOffset = $('nav').offset().top;
              
              $(window).scroll(function(){
                  if ($(window).scrollTop() >= stickyOffset){
                      $('nav').addClass('fixed');
                      //this makes the page length equal to what it was before fixing nav
                      $('.nav-spacer').show(0); 
                  }
                  else {
                      $('nav').removeClass('fixed');
                      $('.nav-spacer').hide(0);
                  }
              });
              

              【讨论】:

                【解决方案10】:

                Coop 的回答非常好。
                但是它依赖于 jQuery,这是一个没有依赖关系的版本:

                HTML

                <div id="sticky" class="sticky"></div>
                

                CSS

                .sticky {
                  width: 100%
                }
                
                .fixed {
                  position: fixed;
                  top:0;
                }
                

                JS
                (这使用 eyelidlessness's answer 在 Vanilla JS 中查找偏移量。)

                function findOffset(element) {
                  var top = 0, left = 0;
                
                  do {
                    top += element.offsetTop  || 0;
                    left += element.offsetLeft || 0;
                    element = element.offsetParent;
                  } while(element);
                
                  return {
                    top: top,
                    left: left
                  };
                }
                
                window.onload = function () {
                  var stickyHeader = document.getElementById('sticky');
                  var headerOffset = findOffset(stickyHeader);
                
                  window.onscroll = function() {
                    // body.scrollTop is deprecated and no longer available on Firefox
                    var bodyScrollTop = document.documentElement.scrollTop || document.body.scrollTop;
                
                    if (bodyScrollTop > headerOffset.top) {
                      stickyHeader.classList.add('fixed');
                    } else {
                      stickyHeader.classList.remove('fixed');
                    }
                  };
                };
                

                示例

                https://jsbin.com/walabebita/edit?html,css,js,output

                【讨论】:

                  【解决方案11】:

                  或者只是简单地添加一个span标签,将固定标题的高度设置为其高度,然后将其插入到粘性标题旁边:

                  $(function() {
                    var $span_height = $('.fixed-header').height;
                    var $span_tag = '<span style="display:block; height:' + $span_height + 'px"></span>';
                  
                    $('.fixed-header').after($span_tag);
                  });
                  

                  【讨论】:

                    【解决方案12】:

                    选择的解决方案不适合我的页面。所以这是一个更高级的版本,可以与引导程序一起使用。

                    javascript

                    var stickyOffset = $('.sticky-header').offset().top;
                    
                    $(window).scroll(function () {
                        var sticky = $('.sticky-header'),
                            scroll = $(window).scrollTop(),
                            header = $('.fixed-header-background');
                        sticky.each(function() {
                            var left = $(this).offset().left;
                            $(this).data('left', left);//I store the left offset
                        });
                    
                        if (scroll >= stickyOffset) {
                            sticky.addClass('fixed');
                            header.css('display', 'block');
                            sticky.each(function() {
                                $(this).css('left', $(this).data('left'));//I set the left offset
                            });
                        } else {
                            sticky.removeClass('fixed');
                            header.css('display', 'none');
                            sticky.each(function () {
                                $(this).css('left', '');//I remove the left offset
                            });
                        }
                    });
                    

                    CSS

                    .fixed-header-background {
                        display: none;
                         position: fixed;
                        top: 50px;
                        width: 100%;
                        height: 30px;
                        background-color: #fff;
                        z-index: 5;
                        border-bottom-style: solid;
                        border-bottom-color: #dedede;
                        border-bottom-width: 2px;
                    }
                    
                    .fixed{
                         position: fixed;
                        top: 52px;
                        z-index: 6;
                    }
                    

                    还有 HTML

                        <div class="fixed-header-background"></div>
                    <table class="table table-hover table-condensed">
                            <thead>
                                <tr>
                                    <th></th>
                                    <th><span class="sticky-header">My header 1</span></th>
                                    <th><span class="sticky-header">My header 2</span></th>
                                </tr>
                            </thead>
                            <tbody>
                    [....]
                    
                            </tbody>
                        </table>
                    

                    【讨论】:

                      【解决方案13】:
                       $(document).ready(function(){
                      
                          var div=$('#header');
                          var start=$(div).offset().top;
                      
                          $.event.add(window,'scroll',function(){
                              var p=$(window).scrollTop();
                              $(div).css('position',(p>start)?'fixed':'static');
                              $(div).css('top',(p>start)?'0px':'');
                      
                          }); 
                      });
                      

                      效果很好。

                      【讨论】:

                        【解决方案14】:

                        你需要一些 JS 来做滚动事件。最好的方法是为固定位置设置一个新的 CSS 类,当滚动超过某个点时,该类将分配给相关的 div。

                        HTML

                        <div class="sticky"></div>
                        

                        CSS

                        .fixed {
                            position: fixed;
                            top:0; left:0;
                            width: 100%; }
                        

                        jQuery

                        $(window).scroll(function(){
                          var sticky = $('.sticky'),
                              scroll = $(window).scrollTop();
                        
                          if (scroll >= 100) sticky.addClass('fixed');
                          else sticky.removeClass('fixed');
                        });
                        

                        小提琴示例:http://jsfiddle.net/gxRC9/501/


                        编辑:扩展示例

                        如果触发点未知但应该是当粘性元素到达屏幕顶部时,可以使用offset().top

                        var stickyOffset = $('.sticky').offset().top;
                        
                        $(window).scroll(function(){
                          var sticky = $('.sticky'),
                              scroll = $(window).scrollTop();
                        
                          if (scroll >= stickyOffset) sticky.addClass('fixed');
                          else sticky.removeClass('fixed');
                        });
                        

                        扩展示例小提琴:http://jsfiddle.net/gxRC9/502/

                        【讨论】:

                        • 感谢您的帮助。你能把黄色的盒子固定在红色的盒子上吗?
                        • 当然,现在您已经有了可以替换其中任何类的代码。我已经更新了我的答案。
                        • 你做得很好,我不知道为什么有人投了反对票。无论如何我要 +1 .. 干杯:)
                        • @Coop 是的,即使我的回答也很完美,但仍然有两个反对票.. 呵呵,如果有人投反对票,他/她必须解释原因哈
                        • @CraigJacobs 您的问题可以通过几行 CSS 轻松解决。通过确保粘性元素始终不在站点的流动(位置:绝对)和主体中的相关填充以为其腾出空间。
                        【解决方案15】:

                        我已经修改了合作社的答案。请查看示例FIDDLE 这是我的编辑:

                        $(window).scroll(function(){
                          if ($(window).scrollTop() >= 330) {
                            $('.sticky-header').addClass('fixed');
                           }
                           else {
                            $('.sticky-header').removeClass('fixed');
                           }
                        });
                        

                        【讨论】:

                        • 目前为止的最佳答案,因为当您滚动元素时,这实际上工作得更干净。
                        • 这可以像在滚动着陆页 div 后将标题固定到顶部一样实现吗?
                        【解决方案16】:

                        我知道 Coop 已经回答了这个问题,但这里有一个版本,它还跟踪 div 在文档中的位置,而不是依赖于静态值:

                        http://jsfiddle.net/gxRC9/16/

                        Javascript

                        var offset = $( ".sticky-header" ).offset();
                        var sticky = document.getElementById("sticky-header")
                        
                        $(window).scroll(function() {
                        
                            if ( $('body').scrollTop() > offset.top){
                                $('.sticky-header').addClass('fixed');
                            } else {
                                 $('.sticky-header').removeClass('fixed');
                            } 
                        
                        });
                        

                        CSS

                        .fixed{
                             position: fixed;
                            top: 0px;
                        }
                        

                        【讨论】:

                        • 是的 offset.top 很好。这实际上是我在 div 高度可能发生变化的响应式设计中使用的更完整的方法。
                        • 是的。不仅仅是响应式的,它可以是任何东西,比如改变高度的图像,或者粘性元素上方 div 中或多或少的文本。
                        • 我在考虑 Paul Designer 如何每次根据文档大小手动设置静态滚动量。但你做得很好@Rich
                        • 你能指定在标题卡到位之前你希望用户滚动多少像素吗???
                        • 你的意思是,有多少像素超过了粘性元素?试试这个:jsfiddle.net/gxRC9/18
                        猜你喜欢
                        • 2020-08-31
                        • 1970-01-01
                        • 2018-08-15
                        • 2013-08-02
                        • 2018-01-10
                        • 1970-01-01
                        • 1970-01-01
                        • 2018-10-12
                        • 2013-06-18
                        相关资源
                        最近更新 更多