内容简介:从效果上看,
Sticky
也不是新知识点了,写这篇文章的原因是由于最近在实现效果的过程中,发现我对 Sticky
的理解有偏差,代码执行结果不如预期。决定写篇文章重新学习一次。
什么是 Sticky
Sticky
(MDN 翻译成粘性效果)是 CSS
属性 position
中的一个可选值。跟我们用得比较多的 static
, fixed
, relative
, absolute
一样,用来描述元素的定位方式。
从效果上看, Sticky
像是混合体,页面滑动到“临界点”之前表现为 relative
, 到达“临界点”时表现为 fixed
。
如何使用
使用 CSS Sticky
只需要两个条件。
position: sticky; top: 0; // right/bottom/left 任一有效值,甚至可以为负像素值 复制代码
top:0
意思是当元素滑动到距离视口 0px 时再继续滑动,元素吸顶。可以在这里 看效果(试试看修改 top 值)
对比 JS 的实现方案
没有 CSS Sticky
之前,类似的效果都是使用 JS 实现。大致步骤如下:
fixed
window.addEventListener('scroll', () => { const rect = elem.getBoundingClientRect(); // 计算目标元素和视口的距离 }) 复制代码
在 npm 上搜 sticky 关键字,也有很多优秀的包可以使用。以react-sticky 为例,满足条件时会创建 placeholder
元素(防止页面抖动),同时让 header
定位为 fixed
。
右边是 Chrome Dev-Tools
的 layers
面板,蓝色部分为生成的 placeholder
。
两种方案的火焰图对比(为了放大效果,我把 cpu
调慢了 6 倍)
CSS 方案
使用 CSS Sticky
,工作都交给 GPU
了,不占用 JS
主线程的资源,在移动端上异常流畅。
React Sticky
由于需要在 scroll event
回调中不断调用 getBoundingClientRect
,而 getBoundingClientRect
又会触发页面重排重绘,稍不留神就掉帧卡顿。仅仅为了实现这个效果(页面上没有其他内容)大动干戈性价比很低。
结论是:实现 Sticky
效果,优先选择 CSS Sticky
理解上的偏差
1. 只在 Containing Block 内有效。
修改例子,用一个 div 把 Sticky Header
包裹起来,发现 Sticky
效果失效了!!!
... <div class="wrapper"> <header>Sticky Header</header> </div> ... 复制代码
根据文档, Sticky
效果只在Containing Block 内有效, Containing Block
滑出屏幕时, Stickey Element
也跟着滑走。
修改 wrapper
的高度,看效果。
.wrapper { height: 100px; background-color: #e6e6e6; } 复制代码
多个 Sticky Element
放在一块就有了前一个被后一个顶出去的特效,实际上并不是真的被顶出去,而是 Containing Block
把它拖走。
2. Overflow 会影响 Sticky
修改例子中的代码,给 #root
加上 overflow: auto
#root { overflow: auto; } 复制代码
Sticky
效果再次丢失( overflow
设置为其他非 visible
的有效值也是同样效果。)
看了很多相关的文档,我的出来的结论是:
Sticky Element
的 offset 值是依据 nearest scrolling ancestor
(距离最近的滚动祖先) 计算的,如果没有匹配上的祖先元素,则使用视口作为参照物。
问题就出在 overflow-x
或者 overflow-y
其中任一为非 visible
则认为是要找的目标元素,而在滚动窗口的过程中, Sticky Element
和 它找到的目标祖先元素的 offset
值一直没有改变,所以 Sticky
不起作用。
对症下药,让滚动发生在被“误匹配”上的祖先元素内即可恢复 Sticky Effect
。
#root { overflow: auto; height: 100vh; } 复制代码
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。