• CSS Sticky 其实很简单


    为什么要写这篇文章

    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 实现。大致步骤如下:

    1. 监听滚动事件,计算目标元素距离视口的距离。
    2. 距离不满足条件时,按兵不动。
    3. 距离满足条件时,创建占位元素,修改目标元素定位方式为 fixed
    window.addEventListener('scroll', () => {
        const rect = elem.getBoundingClientRect();
        // 计算目标元素和视口的距离
    })
    复制代码

    在 npm 上搜 sticky 关键字,也有很多优秀的包可以使用。以 react-sticky 为例,满足条件时会创建 placeholder 元素(防止页面抖动),同时让 header 定位为 fixed

    React Sticky

    右边是 Chrome Dev-Toolslayers 面板,蓝色部分为生成的 placeholder

    两种方案的火焰图对比(为了放大效果,我把 cpu 调慢了 6 倍)

    CSS 方案

    css 方案

    使用 CSS Sticky,工作都交给 GPU 了,不占用 JS 主线程的资源,在移动端上异常流畅。

    React Sticky

    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;
    }
    复制代码

    兼容性

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

    caniuse sticky

    相关链接


    作者:HelKyle
    链接:https://juejin.im/post/5cde75636fb9a07ef562048a
    来源:掘金
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
  • 相关阅读:
    SQL SERVER 错误:查询处理器用尽了内部资源,无法生成查询计划。这种情况很少出现,只有在查询极其复杂或引用了大量表或分区时才会出现。请简化查询。如果您认为该消息的出现纯属错误,请与客户支持服务部门联系,了解详细信息。
    大数据第十五周 Spark编程基础实例——wordCount编程
    Qt判断文件或文件夹是否存在
    windows解决访问Github慢
    朴素贝叶斯算法-非模型
    Qt自绘系列
    QStackedWidget动态多界面
    C++判断两个指针指向的对象是否相同
    Qt之自绘控件
    Python2.7安装OpenCV错误:TypeError: ‘NoneType’ object is not iterable
  • 原文地址:https://www.cnblogs.com/cangqinglang/p/11493555.html
Copyright © 2020-2023  润新知