详解position: sticky粘性定位
深入了解sticky属性值与粘性定位
- 1 前言
- 1 可滚动元素对粘性定位的影响
- 2 理解粘性定位的计算规则
- 3 理解粘性定位的堆叠规则
- 4 其他
1 前言
我们经常可以看到这样的效果,当导航元素在屏幕内的时候,可以跟随屏幕内容一起滚动,当导航元素到上边缘的距离为0的时候,就粘在了上边缘,如同固定定位的效果。
这样的效果实现只需要几行CSS代码:
position: -webkit-sticky;
position: sticky;
top: 0;
当粘性定位元素“粘住”的时候,看起来和效果和固定定位一样,但是它和固定定位并没有任何关系,粘性定位是相对定位的延伸。
粘性定位和相对定位有一些共同点:
- 元素发生偏移的时候,元素的原始位置是保留的
- 创建了新的绝对定位包含块,也就是粘性定位元素里面如果有绝对定位的子元素,那么这个子元素的
left
属性、top
属性、right
属性和bottom
属性时的偏移计算是相对于当前粘性定位元素的 - 支持设置
z-index
属性值来改变元素的层叠顺序
再说一下粘性定位和相对定位的不同点:
- 偏移计算元素不一样。相对定位偏移计算的容器是父元素,而粘性定位偏移计算的元素是层级最近的可滚动元素(
overflow
属性值不是visible
的元素)。如果一个可滚动元素都没有,则相对浏览器视窗进行位置偏移 - 偏移定位计算规则不一样。粘性定位的计算规则比较复杂,涉及多个粘性定位专有的概念
- 重叠表现不一样。相对定位元素彼此独立,重叠的时候表现为堆叠;但是粘性定位元素在特定布局下,元素重叠的时候表现为A粘性定位元素推开B粘性定位元素的视觉表现
接下来深入讲解一下上面提到的3点不同之处。
1 可滚动元素对粘性定位的影响
通常的Web页面都是窗体(body
)滚动的,而粘性定位偏移计算的元素是层级最近的那个滚动元素。因此如果粘性定位的某个祖先元素的overflow
的属性值不是visible
,那么窗体滚动的时候就不会有粘性定位的效果,例如:
<div class="hidden">
<nav class="nav">橘猫吃不胖</nav>
</div>
<div class="block" style="background-color: lightblue;">滚动块1</div>
<div class="block" style="background-color:cornflowerblue;">滚动块2</div>
<div class="block" style="background-color: darkblue;">滚动块3</div>
.hidden {
width: 200px;
height: 200px;
background-color: lemonchiffon;
overflow: hidden;
}
.nav {
position: sticky;
top: 0;
background-color: orange;
}
.block {
width: 150px;
height: 150px;
}
把浏览器窗口高度缩小,此时滚动页面,<nav>
元素是没有粘性效果的,因为<nav>
元素粘性定位的偏移计算是相对于父级<div>
元素计算的,粘性效果也只有在<div>
元素滚动的时候才能够体现。
如果我们将div
元素样式调整一下,让div
元素成为可滚动元素,如下所示:
<div class="hidden">
<nav class="nav">橘猫吃不胖</nav>
<div class="block" style="background-color: lightblue;">滚动块1</div>
<div class="block" style="background-color:cornflowerblue;">滚动块2</div>
<div class="block" style="background-color: darkblue;">滚动块3</div>
</div>
.scroll {
width: 300px;
height: 300px;
background-color: lemonchiffon;
overflow: auto;
}
.nav {
position: sticky;
top: 0;
background-color: orange;
}
.block {
width: 150px;
height: 150px;
}
此时滚动div
元素,就会发现nav
元素没有跟着滚动,有粘性定位的效果。
2 理解粘性定位的计算规则
粘性定位中有一个“流盒”(flow box
)的概念,指的是粘性定位元素最近的可滚动元素的尺寸盒子,如果没有可滚动的元素,则表示浏览器视窗盒子。
粘性定位中还有一个名为“粘性约束矩形”的概念,指的是粘性定位元素的包含块(通常是父元素)在文档流中呈现的矩形区域和流盒的4个边缘在应用黏性定位元素的left
、top
、right
和bottom
属性的偏移计算值后的新矩形的交集。
滚动的时候,流盒的位置是不变的,粘性定位元素的包含块跟着滚动,因此粘性约束矩形随着滚动是实时变化的。假设我们的粘性定位元素只设置了top
属性值,则粘性定位元素碰到粘性约束矩形的顶部时就开始向下移动,直到它完全被包含在粘性约束矩形中。
上面就是粘性定位计算和渲染的规则,下面通过一个例子来理解上面这段描述。
我们设计一个窗体滚动的页面,包含父子关系的div
和nav
元素,代码如下
<body>
<div class="container">
<nav class="nav">橘猫吃不胖</nav>
</div>
<div class="block" style="background-color: lightblue;">滚动块1</div>
<div class="block" style="background-color:cornflowerblue;">滚动块2</div>
</body>
.container {
height: 100px;
margin-top: 50px;
border: 3px solid orange;
}
.nav {
position: sticky;
top: 20px;
background-color: yellow;
}
.block {
width: 150px;
height: 150px;
}
上面这段代码实际效果如下所示,nav
这个粘性定位元素的top
偏移是20px,并且最近可滚动尺寸盒子是浏览器视窗盒子,那么流盒矩形就是浏览器滚动窗口矩形向下偏移20px的地方,也就是蓝色线往下的区域。粘性定位元素nav
的包含块是其父元素container
(设置了橘黄色边框),粘性约束矩形就是流盒矩形和包含块的重叠区域,也就是蓝色线下方和橘黄色方框区域重叠的矩形区域。
在初始状态下,由于container
元素设置了margin-top: 50px;
,所以nav
粘性定位元素的顶部到可以完全触碰到粘性约束矩形顶部(粘性约束矩形是要一起往上滚动的)有33px(流盒到粘性约束矩形顶部30px+粘性约束矩形的边框3px),这时滚动浏览器页面不会有粘性效果,如下图所示:
页面接着向上滚,nav
元素的顶部距离粘性约束矩形的顶部越来越小,直到距离为0,这时nav
元素开始下移,把自己约束在粘性约束矩形的范围里面,此时的粘性约束矩形为nav
元素的顶部到下方的橘黄色边框。
页面继续滚动,直到nav
元素的底部和粘性约束矩形范围的底部重合,页面再继续向上滚动时,粘性约束矩形会继续变小,由于粘性定位元素不能超过粘性约束矩形的范围,所以粘性效果失效了,nav
元素会跟着一起滚走。
了解了粘性定位的计算规则,那么我们就明白了,如果粘性定位元素的父元素的高度和粘性定位元素的高度相同,那么垂直滚动的时候,粘性定位的效果是不会出现的,因为这时粘性定位元素没有了实现粘性效果的空间。
3 理解粘性定位的堆叠规则
黏性定位元素的偏移由容器决定,如果多个黏性定位元素在同一容器中,则这几个黏性定位元素会产生元素重叠的情况;
如果黏性定位元素分布在不同的容器中,同时这些容器在布局上是上下紧密相连的,则视觉上会表现为新的黏性定位元素挤开原来的黏性定位元素,形成依次占位的效果。
例如,同一个容器中,包含了多个粘性定位元素,代码如下:
<body>
<div class="container">A</div>
<div class="block" style="background-color: lightblue;">滚动块1</div>
<div class="container">B</div>
<div class="block" style="background-color:cornflowerblue;">滚动块2</div>
<div class="container">C</div>
<div class="block" style="background-color: darkblue;">滚动块3</div>
</body>
.container {
position: sticky;
top: 0;
background-color: yellow;
}
.block {
width: 100%;
height: 150px;
}
上面这个示例中,在同一个容器body
中包含了许多个粘性定位元素container
,在滚动浏览器页面的时候,可以看到出现了元素重叠的现象。
再比如说粘性定位元素分布在不同的容器中,例如下面这段代码:
<body>
<div>
<div class="container">A</div>
<div class="block" style="background-color: lightblue;">滚动块1</div>
</div>
<div>
<div class="container">B</div>
<div class="block" style="background-color:cornflowerblue;">滚动块2</div>
</div>
<div>
<div class="container">C</div>
<div class="block" style="background-color: darkblue;">滚动块3</div>
</div>
</body>
.container {
position: sticky;
top: 0;
background-color: yellow;
}
.block {
width: 100%;
height: 150px;
}
上面这个示例中,粘性定位元素分布在了不同的元素中,滚动浏览器页面,可以看到下面的元素把上面的元素推开了。
这是因为当粘性定位元素分布在不同的容器时,就会有多个不同的粘性约束矩形,这些粘性约束矩形排列整齐,所以视觉表现出来就是上一个粘性定位元素被滚走。当粘性定位元素共用一个容器的时候,也就共用一个粘性约束矩形,这时滚动元素会一个一个重叠起来。
4 其他
在Safari
浏览器中,粘性定位元素需要添加-webkit-
私有前缀。