资讯专栏INFORMATION COLUMN

CSS Sticky 其实很简单

davidac / 2434人阅读

摘要:大致步骤如下监听滚动事件,计算目标元素距离视口的距离。距离满足条件时,创建占位元素,修改目标元素定位方式为。仅仅为了实现这个效果页面上没有其他内容大动干戈性价比很低。对症下药,让滚动发生在被误匹配上的祖先元素内即可恢复。

为什么要写这篇文章

Sticky 也不是新知识点了,写这篇文章的原因是由于最近在实现效果的过程中,发现我对 Sticky 的理解有偏差,代码执行结果不如预期。决定写篇文章重新学习一次。

什么是 Sticky

Sticky (MDN 翻译成粘性效果)是 CSS 属性 position 中的一个可选值。跟我们用得比较多的 static, fixedrelativeabsolute 一样,用来描述元素的定位方式。

从效果上看,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-Toolslayers 面板,蓝色部分为生成的 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 Headerheader>
  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;
}
兼容性

算上 prefixed ,当前 css sticky 手机端兼容性达到 94.14%,如果你所做的业务需要照顾剩下 5.86% 的用户,也可以使用 polyfill 或者 position: fixed

相关链接

uxdesign.cc/position-st…

codyhouse.co/ds/componen…

medium.com/@elad/css-p…

developer.mozilla.org/zh-CN/docs/…

stackoverflow.com/questions/4…

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/6888.html

相关文章

  • CSS Sticky 其实简单

    摘要:大致步骤如下监听滚动事件,计算目标元素距离视口的距离。距离满足条件时,创建占位元素,修改目标元素定位方式为。仅仅为了实现这个效果页面上没有其他内容大动干戈性价比很低。对症下药,让滚动发生在被误匹配上的祖先元素内即可恢复。为什么要写这篇文章 Sticky 也不是新知识点了,写这篇文章的原因是由于最近在实现效果的过程中,发现我对 Sticky 的理解有偏差,代码执行结果不如预期。决定写篇文章重新...

    番茄西红柿 评论0 收藏0
  • css实现手机通讯录

    摘要:不过要是一个简单的小项目,没那么多要求的话,纯还是能很好的适用的,性能上绝对要比通过滚动监听强上好多倍,而且引用方便,只要数据生成了就可以直接使用 我们经常在手机上看到通讯录列表,这类布局一般有两个显著的效果 showImg(https://segmentfault.com/img/remote/1460000016709371?w=360&h=640); 首字母吸顶 快速定位 下...

    王晗 评论0 收藏0
  • css实现手机通讯录

    摘要:不过要是一个简单的小项目,没那么多要求的话,纯还是能很好的适用的,性能上绝对要比通过滚动监听强上好多倍,而且引用方便,只要数据生成了就可以直接使用 我们经常在手机上看到通讯录列表,这类布局一般有两个显著的效果 showImg(https://segmentfault.com/img/remote/1460000016709371?w=360&h=640); 首字母吸顶 快速定位 下...

    苏丹 评论0 收藏0
  • css实现手机通讯录

    摘要:不过要是一个简单的小项目,没那么多要求的话,纯还是能很好的适用的,性能上绝对要比通过滚动监听强上好多倍,而且引用方便,只要数据生成了就可以直接使用 我们经常在手机上看到通讯录列表,这类布局一般有两个显著的效果 showImg(https://segmentfault.com/img/remote/1460000016709371?w=360&h=640); 首字母吸顶 快速定位 下...

    leonardofed 评论0 收藏0
  • CSS粘性定位是怎样工作的

    摘要:怎样才能让粘性定位起作用粘性定位有两个主要部分,粘性元素和粘性容器。这是粘性元素可以浮动的最大区域。最好是在以粘性容器底部为自然位置的元素上使用它。 翻译:疯狂的技术宅原文:https://medium.com/@elad/css-... 本文首发微信公众号:jingchengyideng欢迎关注,每天都给你推送新鲜的前端技术文章 浏览器对 CSS粘性定位有着非常好的支持,但很多...

    Wildcard 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<