如何在滚动时固定页面头部

62

我正在创建一个标题,一旦滚动到一定数量的像素后将固定在原位。

我能否仅使用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的帮助下完成这个任务。 - Anon
这种方法及其后续答案的问题在于,你最终会依赖于容器不超过你指定的2000像素。这在生产中会失败,因为你要么需要不断调整,要么就要求撰写人员永远不要超出一定的字数限制。无论哪种方式,这种方法都无法扩展。 - JGallardo
使用jQuery和CSS可以帮助您实现滚动时的固定页眉 - http://www.kvcodes.com/2017/03/jquery-simple-sticky-header-on-scroll/ - Kvvaradha
请查看我的关于粘性标头的中等文章,这应该会有所帮助:D - Jose Greinch
16个回答

141

你需要一些JavaScript来处理滚动事件。最好的方法是设置一个新的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');
});

扩展示例 fiddle:http://jsfiddle.net/gxRC9/502/


谢谢你的帮助。你能把黄色框固定而不是红色的吗? - Paul Designer
当然,现在你已经有了那段代码,你可以在其中替换任何类。我已经更新了我的答案。 - CaribouCode
@Coop是的,即使我的答案也很完美,但仍然有两个负面投票.. 哼,如果有人给负面投票,他/她必须解释原因。 - Vikas Ghodke
你能指定用户在页面滚动多少像素后,页眉固定在原位吗? - Paul Designer
1
@CraigJacobs,你的问题可以通过几行CSS轻松解决。只需确保粘性元素始终不在站点流程中(position: absolute),并在主体中添加相关填充以为其腾出空间即可。 - CaribouCode
显示剩余8条评论

15

我修改了Coop的答案。请查看示例FIDDLE 以下是我的编辑:

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

1
到目前为止最好的答案,因为当您滚动过该元素时,它实际上更干净地工作。 - JGallardo
这个能否像固定页眉一样实现,在滚动着陆页div后将其置于顶部? - Shahil M

13

Coop 的回答很好。
但是它依赖于 jQuery,这里有一个不依赖任何库的版本:

HTML

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

CSS

的翻译是:

CSS

.sticky {
  width: 100%
}

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

JS
(这里使用 eyelidlessness的答案 来在纯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

Rich 的回答 的基础上进行补充,使用了 offset。

我作出的修改如下:

  • There was no need for the var sticky in Rich's example, it wasn't doing anything

  • I've moved the offset check into a separate function, and called it on document ready as well as on scroll so if the page refreshes with the scroll half-way down the page, it resizes straight-away without having to wait for a scroll trigger

     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');
             } 
         }
    
     });
    

10

我知道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;
}

Yeh offset.top 不错。这实际上是我在响应式设计中使用的更完整的方法,其中 div 的高度可能会发生变化。 - CaribouCode
是的。不仅仅是响应式,它可以是任何东西,比如图像改变高度,或者在粘性元素上方的div中有更多或更少的文本。 - Rich
1
我在思考Paul Designer如何根据文档大小手动设置静态滚动量。但是你做得很好,@Rich。 - sun
你能指定用户滚动多少像素后标题栏才会吸附在原位吗? - Paul Designer
很酷,试试这里:jsfiddle.net/gxRC9/18 - 只需更改additionalPixels的值。 - Rich
显示剩余2条评论

9

闪耀的纯HTML/CSS解决方案

在2019年,你可以完全不需要JavaScript就能实现这个效果,只要使用CSS3。我经常会制作像这样的固定头部:

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 */ - iorgv
当您决定是否可以使用此解决方案时,这可能会很方便:https://caniuse.com/#feat=css-sticky - Honza Javorek

8

可以仅使用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>


6
Coops的答案是一个好的、简单的解决方案,但是一旦应用了fixed类,页面就会变得更短,内容会"跳"起来,如果页面长度小于头部元素的高度,则会出现跳跃现象,不会让您看到页面底部。
我发现的答案是在将要固定的元素(在我的例子中是nav元素)上面添加一个间隔div,并将其设置为与nav元素相同的高度,并将其设置为不显示。
当向nav添加.fixed类时,显示.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);
    }
});

3
或者只需添加一个`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);
});

2
所选解决方案不适合我的页面。因此,这是一个更高级的版本,适用于bootstrap。 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
        });
    }
});

The 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>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接