Position:sticky详解
我也不知道要怎么开场,我就强调一下我理解的sticky中最重要的一句话吧:sticky元素永远不会超出其父级的内容区(父级宽高大于sticky元素宽高) 。然后我们就直奔主题吧!
先看下面简单的几段代码:
<div class="father">
<div class="sticky"></div>
</div>
.father{
padding: 100px;
margin: 100px;
margin-bottom: 1000px;
width: 150px;
height: 1000px;
background: #000;
/* overflow: hidden; */
}
.sticky{
position: sticky;
width: 50px;
height: 50px;
top: 0;
left: 0;
background: #f0f;
}
这是我们常规使用的sticky布局,运行结果是这样的
非常正常
但是如果我们改一下left和top的值:
.sticky{
position: sticky;
width: 50px;
height: 50px;
top: 20px;
left: 20px;
background: #f0f;
}
哦豁,为啥没有效果呢?那我们再来改一下left和top的值:
.sticky{
position: sticky;
width: 50px;
height: 50px;
top: 220px;
left: 220px;
background: #f0f;
}
诶嘿,这就显而易见了, 我们父级的内容区距离可视区的上边和左边分别是200px和208px(多出来的8px是因为我没有去掉body默认的margin:8px),所以这里我们的sticky元素相对于父级的内容区的左上角偏离了20px和12px,这说明什么,说明常规情况下sticky元素是跟fixed一样的相对于可视区进行定位的只是不会脱离文档流,那为什么我们之前设置的20px的没有效果呢,这就是我开头说的那句强调的话:sticky元素永远不会超出其父级的内容区 ,因为有这个特点,所以他只能服服帖帖的靠在他老爸的左上角。
然后我们来康康如果父级设置了overflow:hidden / auto / overlay / scroll; 的情况下会发生什么(我这里只演示hidden的情况,感兴趣的朋友之后可以自己去试一试)。
.father{
padding: 100px;
margin: 100px;
margin-bottom: 1000px;
width: 150px;
height: 1000px;
background: #000;
overflow: hidden;
}
.sticky{
position: sticky;
width: 50px;
height: 50px;
top: 20px;
left: 20px;
background: #f0f;
}
注意哦我们这里吧left和top该为了20px
你会发现当父级设置了overflow不为visible的属性值的时候,sticky元素开始相对于父级进行定位了,并且不会有fixed的效果,当可视区超过sticky元素时它不会再相对于可视区进行定位了。
然后我们给父级father再加一层父级:
<div class="grand">
<div class="father">
<div class="sticky"></div>
</div>
</div>
然后去掉之前father的overflow,给这个grand加上一个overflow
.grand{
overflow: hidden;
}
.father{
padding: 100px;
margin: 100px;
margin-bottom: 1000px;
width: 150px;
height: 1000px;
background: #000;
}
.sticky{
position: sticky;
width: 50px;
height: 50px;
top: 20px;
left: 20px;
background: #f0f;
}
你会发现这种情况下sticky元素还是一样没有fixed的效果,也就是说不只是sticky元素的直接父级而是他的父级链上只要有一个设施了overflow不为visible的那么该sticky元素就不会有fixed的效果,所以之后在使用sticky元素发现效果不是我们想象中的一样的时候,就有可能是忽略了这个因素。
然后我们再来看看sticky有兄弟的情况:
<div class="father">
<div class="son"></div>
<div class="sticky"></div>
</div>
.father{
padding: 100px;
margin: 100px;
margin-bottom: 1000px;
width: 150px;
height: 1000px;
background: #000;
overflow: hidden;
}
.sticky{
position: sticky;
width: 50px;
height: 50px;
top: 0px;
left: 70px;
background: #f0f;
display: inline-block;
}
.son1{
display: inline-block;
width: 50px;
height: 50px;
background: #0ff;
}
这里父级依然是overflow:hidden;sticky元素left还是20px
诶嘿,这里不应该是相对于父级进行定位吗,这是怎么肥四呢,因为我在之前说过,sticky是不会脱离文档流的,所以他永远不会跟同级的常规流兄弟重叠,所以我觉得官方说的sticky是综合了relative和fixed中relative相似的部分就是不会脱离文档流,也就是不会影响其他元素的正常排列。
最后再做一个总结:
在父级链不设置overflow:hidden / auto / scroll / overlay;等属性时,sticky布局类似于fixed布局(官方说是relative和fixed的结合,个人认为与relative相似说的就是sticky不会脱离文档流,它不会导致后续元素排列发生变化),但是sticky的元素始终无法超出其直接父级的内容区且不会跟同级的常规流布局元素重叠,所以当left和top值设置的小于父级内容区距离可视区左边和上边的距离时最终的视觉效果就是sticky元素顶着父级的左上角,也就是说当sticky元素左边上面都没有常规流布局的兄弟元素时:sticky元素相对于父级内容区的定位距离 = 设置的left / top - 父级内容区距离可视区左边 / 上边的距离;但是如果父级链上有任意一个元素设置了上述overflow的属性,则sticky元素直接相对于父级进行定位,但是不会有fixed相应的效果(也就是sticky元素不再相对内容区定位),并且我发现sticky元素好像并不支持设置bottom和right属性。(这一条我是自己测试过的,无论是父级有没有设置overflow:hidden等值,right和bottom都是没有效果的)
如果有小伙伴测试了发现我讲的有问题欢迎指出,共同讨论。