Sticky 定位无效的一些坑

position: stickycss中比较常见的吸顶定位方式,但使用不当很可能会导致该定位方式无效。本文记录自己在sticky定位中踩过的一些坑。
CC-BY-SA-4.0

场景

在开发这个网站时,我想让顶部的导航栏/搜索栏在滚动时固定在屏幕顶部,这样会更方便用户的操作。期望的效果如下:

sticky定位的效果

初步实现的代码 (无效代码😟)

HTML

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
<body>
<div class="container">
    <div class="header">
        <div class="wrapper">需要定位的元素</div>
    </div>
    <div class="content">
        <div class="box"></div>
        <div class="box"></div>
        <div class="box"></div>
        <div class="box"></div>
        <div class="box"></div>
        <div class="box"></div>
        <div class="box"></div>
    </div>
</div>
</body>

CSS

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
.header {
    padding-top: 200px;
}
.wrapper {
    height: 100px;
    background-color: red;
    position: sticky;
    top: 0;
}
.box {
    height: 200px;
    background-color: #6a737d;
    margin: 20px 0;
}

正如高亮部分的代码那样,我设置了.wrapper元素的sticky相关属性后并没有什么效果。

not working

求助 Google 😊

搜了一圈,网上关于sticky无效的几个原因大概如下:

  • 必须指定top/bottom/left/right这几个属性之一
  • 父容器的高度要大于sticky元素的高度
  • 任意父节点的overflow属性必须都是visible

在我们这个例子里,要定位的元素是.wrapper,父容器是.header。我们没有给.header显式设置高度,因此它的高度是由内容撑开的,也就是说,父容器 .header的高度等于子元素.wrapper的高度,不满足第2点,因此sticky定位无效。

但是这里我们又不能通过设置.header的高度来实现,而是要基于.container作为容器来设置sticky,要不然就会出现下面这种奇怪的行为:

not working

.wrapper元素虽然会吸顶,但是当滚动距离大于.header的高度后,会被后面的元素顶上去,也不是我们想要的。

变通办法

暂时没有找到比较好的解决方法,我们只能把.header元素设置为sticky定位,然后调整top值来达到我们想要的效果。

相关代码如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
.header {
    padding-top: 200px;
    position: sticky;
    top: -200px;
}
.wrapper {
    height: 100px;
    background-color: red;
}
.box {
    height: 200px;
    background-color: #6a737d;
    margin: 20px 0;
}

总结

要想实现元素吸顶效果,必须设置滚动容器内的直接子元素为sticky定位,不能是后代子元素。

参考

Comments