这篇文章发布于 2020年03月7日,星期六,21:16,归类于 CSS相关。 阅读 49751 次, 今日 9 次 24 条评论
by zhangxinxu from https://www.zhangxinxu.com/wordpress/?p=9291
本文欢迎分享与聚合,全文转载就不必了,尊重版权,圈子就这么大,若急用可以联系授权。
本文内容接自之前一篇关于sticky粘性定位文章:“杀了个回马枪,还是说说position:sticky吧”。
因此,如果上面一篇文章还没阅读过,先读一读上面文章。
一、从一个现象说起
设置了position:sticky
粘性定位的元素的父元素如果高度计算值和粘性定位元素一样高,则垂直滚动的时候,粘性定位效果是不会出现的。
很多人不理解为什么会这样?
要讲清楚这个问题,就必须深入理解粘性定位的计算规则。
二、深入理解粘性定位的计算规则
粘性定位中有一个“流盒”(flow box)的概念,指的是粘性定位元素最近的可滚动元素(overflow
属性值不是visible
的元素)的尺寸盒子,如果没有可滚动元素,则表示浏览器视窗盒子。
粘性定位中还有一个名叫“粘性约束矩形”的概念,表示的是粘性定位元素的包含块在文档流中呈现的矩形区域和流盒的四个边缘在应用粘性定位元素的left
、top
、right
、bottom
属性的偏移计算值后的新矩形的交集。
由于滚动的时候,流盒不变,而粘性定位元素的包含块跟着滚动,因此粘性约束矩形随着滚动的进行是实时变化的。
假设我们的粘性定位元素只设置了top
属性值,则粘贴定位元素碰到粘性约束矩形的顶部的时候开始向下移动,直到它完全包含在粘贴约束矩形中。
下面我们根据一个简单的例子来进一步理解上面的规则,例如,有一个页面是窗体滚动,包含<div>
元素和<nav>
元素,这两个元素是父子关系,HTML代码如下:
<div> <nav>导航</nav> </div>
其中:
div { height: 100px; margin-top: 50px; border: solid deepskyblue; } nav { position: sticky; top: 20px; background: lightskyblue; }
则随着滚动的进行,<nav>
元素的粘性约束矩形范围和实际的渲染表现如图1所示:
图1 top方位的粘性定位原理示意图
详细的计算规则如下:
由于<nav>
这个粘性定位元素的top
偏移是20px
,因此,流盒矩形就是滚动窗口矩形再往下偏移20px
,就是图中的红色色块区域。而<nav>
这个粘性定位元素的包含块就是其父元素<div>
元素(设置了边框),粘性约束矩形指的是流盒矩形和包含块的重叠区域,因此,图所示的粘性约束矩形就是红色色块区域和方框区域重叠的矩形区域。
然后:
-
在默认状态下(图1左一),由于
<div>
元素设置了margin-top:50px
,因此,<nav>
这个粘性定位元素的顶部距离粘性约束矩形的顶部还有33px
的大小,不会有粘性效果。 -
随着浏览器滚动,
<nav>
元素和粘性约束矩形的顶部距离越来越小,直到为0
。此时<nav>
元素开始下移,使自己约束在粘性约束矩形范围内,如图1左二所示。 -
浏览器继续滚动,
<nav>
元素的底部也快要超出粘性约束矩形范围的限制了,如图1右二所示。 -
最终,
<nav>
元素的底部和粘性约束矩形范围的底部重合,由于粘性定位元素不能超出粘性约束矩形的范围限制,因此此时粘性效果失效,<nav>
元素被跟着一起滚走了,如图1右一所示。
如果还不是很理解,您可以狠狠地点击这里:帮助理解粘性定位的学习页面
right
、left
以及bottom
方向的定位与top方向类似。
明白了粘性定位的计算规则,也就明白为什么粘性定位元素父元素和自身高度计算值一样的时候没有粘性效果了。因为此时包含块高度和粘性定位元素一样,导致粘性约束矩形的高度最大也就是和粘性定位元素一样高,粘性定位元素的已经完全没有了实现粘性效果的空间。
三、粘性定位其他特征
本文一开始那篇sticky文章还提到了粘性定位其他两个特征:
- 如果我们的粘性定位元素的某个祖先元素的
overflow
属性值不是visible
,那么页面滚动的时候就不会有粘性定位效果。 - 同一容器中多个粘贴定位元素独立偏移,因此可能重叠;位置上下靠在一起的不同容器中的粘贴定位元素则会鸠占鹊巢,挤开原来的元素,形成依次占位的效果。
第一个特性源自粘性定位的定义,这么设计主要是为了避免当多个滚动互相嵌套的时候,粘性定位混乱。
第二个特性原因就是本文提到的粘性定位的计算规则,具体解释:
当我们的粘性定位元素都在一个容器的时候,大家都公用一个巨大的粘性约束矩形,因此,滚动的时候会一个一个往上重叠。
当我们的粘性定位元素属于不同容器的时候,就会有多个不同的粘性约束矩形,这些粘性约束矩形正好一个一个排列得很整齐,于是视觉上达成一个巧合一般的约定,即上一个粘性定位元素被滚走,下一个粘性定位元素正好开始有粘性效果。
以上~
感谢阅读,感谢分享!
本文为原创文章,欢迎分享,勿全文转载,如果实在喜欢,可收藏,永不过期,且会及时更新知识点及修正错误,阅读体验也更好。
本文地址:https://www.zhangxinxu.com/wordpress/?p=9291
(本篇完)
- 纯CSS实现标题栏、表格头水平滚动垂直不滚动 (0.756)
- CSS实现滚动高度自动变小的粘滞效果 (0.701)
- CSS fixed固定定位transofrm失效及居中小技巧 (0.701)
- 杀了个回马枪,还是说说position:sticky吧 (0.443)
- CSS <position>值简介理解background百分比定位 (0.396)
- 大侠,请留步,要不过来了解下CSS Scroll Snap? (0.299)
- 我熟知的三种三栏网页宽度自适应布局方法 (0.252)
- 文章文档标题自动生成导航jQuery小插件titleNav.js (0.244)
- IE6下z-index犯癫不起作用bug的初步研究 (0.161)
- 快速了解CSS display:flow-root声明 (0.161)
- CSS backdrop-filter简介与苹果iOS毛玻璃效果 (RANDOM - 0.008)
1. 在默认状态下(图1左一),由于元素设置了margin-top:50px,因此,这个粘性定位元素的顶部距离粘性约束矩形的顶部还有33px的大小,不会有粘性效果。
上面原文中,此时图1的粘性约束矩形不就是div吗?粘性定位元素nav的顶部距离粘性约束矩形div的顶部不是为0吗?
这里是不是有问题:
如果我们的粘性定位元素的某个祖先元素的overflow属性值不是visible,那么页面滚动的时候就不会有粘性定位效果。
事实上scroll 也是可以的,也必须可以。
确实有问题,下面有个评论,作者回复了
我搞懂了,弹性布局水平排列时,align-items 默认值是 stretch,子项高度是跟其包含块高度容器一致的,没有背景填充颜色还真的不容易看出来,这就导致如你所说的”粘性定位元素的已经完全没有了实现粘性效果的空间”。
我看见网上解释 position: sticky 失效都是基于流模型。弹性盒模型对象主轴为水平方向的子元素失效,需设为 align-self: flex-start; 小白求教,能解释下吗。
楼主 这个功能有没有办法在ie上实现 我们现在有需求
有Polyfill,相关文章中那篇sticky有提及。
td粘性定位position: sticky不会对border起作用,border还是留在原来位置(背景会跟随td一起定位),我测试过div,div的border会跟随div一起定位,应该是和td的border特殊性有关,麻烦看到信息可以对这个问题进行讨论,并且给出一个可靠的解决方案,蟹蟹
“粘性约束矩形”能不能注明英文
大神,第二点中的demo 如果把 top: 20px 改为 bottom:20px ,就没有效果了,这是为什么呢?
因为随着它的父元素一起被移动出去了
流盒的定义有点 没看懂,,,能否具体解释下?
如何定义流盒的区域?
真棒
红色区域给了一个 .flow-box,指红色区域是流盒
但按照流盒的定义,离粘性元素最近的最近的可滚动元素(overflow属性值不是visible的元素),在这个例子里,流盒不该是body吗?
红色区域没有设置overflow,默认值应该是visible;fixed 在页面中,也不能滚动的样子,疑惑这个流盒是怎么判定的
没太懂这个”流盒“的作用,去掉这个流盒,效果好像也一样。sticky元素的top值设置到底是相对于谁的
多谢分享,很实用。
“这个粘性定位元素的顶部和粘性约束矩形的顶部还有33px的距离”,这句话有歧义,容易理解成“这个粘性定位元素的顶部与粘性约束矩形的顶部还有33px的距离”,让人分不清粘性约束矩形指的时div还是红色区域,应该是:这个粘性定位元素和粘性约束矩形的顶部距离流盒还有33px的距离
好的,感谢反馈。
然后当你想用在thead时发现不行,以为踩到小坑或者自己姿势不对。
然后你就会发现一个大坑
非常有趣
想知道是什么大坑
多谢分享,困扰了好久,今天才发现是因为祖父元素有overflow不可见导致的
这期太粗糙了,连兼容性都懒得写
简单的特性介绍之前文章写过了,那我提示下吧。