为什么要写这篇文章

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

右边是 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 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

相关链接

作者:HelKyle
链接:https://juejin.im/post/5cde75636fb9a07ef562048a
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

CSS Sticky 其实很简单的更多相关文章

  1. 一个神奇却很简单的css特效

    在网上看到一个前端大牛的主页,觉得他有一个特效特别酷,一开始还以为是要用什么javascript代码来实现,但仔细看一下,发觉只是用几行css代码就搞定了,我觉得挺好的. 他这个效果就是鼠标放在左半部 ...

  2. CSS Sticky Footer

    ----CSS Sticky Footer 当正文内容很少时,底部位于窗口最下面.当改变窗口高度时,不会出现重叠问题. ----另一个解决方法是使用:flexBox布局  http://www.w3c ...

  3. 手把手教你开发chrome扩展一:开发Chrome Extenstion其实很简单

    手把手教你开发chrome扩展一:开发Chrome Extenstion其实很简单   手把手教你开发chrome扩展一:开发Chrome Extenstion其实很简单 手把手教你开发Chrome扩 ...

  4. js便签笔记(13)——jsonp其实很简单【ajax跨域请求】

    前两天被问到ajax跨域如何解决,还真被问住了,光知道有个什么jsonp,迷迷糊糊的没有说上来.抱着有问题必须解决的态度,我看了许多资料,原来如此... 为何一直知道jsonp,但一直迷迷糊糊的不明白 ...

  5. jquery实现很简单的DIV拖动

    今天用jquery实现了一个很简单的拖动...实现思路很简单  如下: 在thickbox 弹出层内实现拖拽DIV,那么得进行一下相对宽高的运算:必须加上相对于可见窗口宽高和弹出层宽高之间的差:    ...

  6. jsonp其实很简单【ajax跨域请求】

    js便签笔记(13)——jsonp其实很简单[ajax跨域请求] 前两天被问到ajax跨域如何解决,还真被问住了,光知道有个什么jsonp,迷迷糊糊的没有说上来.抱着有问题必须解决的态度,我看了许多资 ...

  7. css中的em 简单教程 -- 转

    先附上原作的地址: https://www.w3cplus.com/css/px-to-em 习惯性的复制一遍~~~~ -------------------------------我是分界线---- ...

  8. 关于fullpage.js 和animate.css制作全屏简单大方的首页

    附上源码: html <!DOCTYPE html><html lang="en"><head> <meta charset=" ...

  9. 我在阿里这仨月 前端开发流程 前端进阶的思考 延伸学习的方式很简单:google 一个关键词你能看到十几篇优秀的博文,再这些博文中寻找新的关键字,直到整个大知识点得到突破

    我在阿里这仨月 Alibaba 试用期是三个月,转眼三个月过去了,也到了转正述职的时间.回想这三个月做过的事情,很多很杂,但还是有重点. 本文谈一谈工作中遇到的各种场景,需要用到的一些前端知识,以及我 ...

随机推荐

  1. 基于【 springBoot +springCloud+vue 项目】一 || 后端搭建

    缘起 本项目是基于之前学习的一个Dubbo+SSM分布式项目进行升级,基于此项目对前后端分离项目.微服务项目进一步深入学习.之前学习了vue.springBoot.springCloud后,没有进行更 ...

  2. jQuery动画(带参数)

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...

  3. 前端 JS 获取 Image 图像 宽高 尺寸

    前端 JS 获取 Image 图像 宽高 尺寸 简介 项目中用到获取图片的原始尺寸,然后适配宽高:网上的大部分前端解决方案,都是new Image()后,在onload事件中获取image的尺寸. 在 ...

  4. Referenced file contains errors (xml文件第一行小红叉错误)

    转自:http://www.manongjc.com/article/30401.html 在eclipse中开发网页时,经常会遇到写xml文件时第一行无缘无故报错.在最左面的行数上面报出一个小红叉, ...

  5. aapt&adb笔记

    aapt 查看安装包信息aapt list apk路径* aapt list xxx/app-debug.apk 查看apk文件信息并保存到本地(> 重定向符) * aapt list xx/a ...

  6. Java经典逻辑编程50题 (转)

    注: 转自https://blog.csdn.net/Alias_fa/article/details/52985112  (摘了题目部分和部分分析,想看原作代码的见原作链接) [程序1] 題目:古典 ...

  7. Ceph分布式存储部署过程

    前言: 环境介绍:此次部署系统为Cenots 7 MON.OSD 10.110.180.112 Admin MON.OSD 10.110.180.113 Node1 MON.OSD 10.110.18 ...

  8. 运维开发笔记整理-Django模型语法

    运维开发笔记整理-Django模型语法 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.模型基本概念 1>.什么是模型 模型是你的数据唯一的,权威的信息源.它包含你所存储数 ...

  9. HTML&CSS基础-CSS的语法

    HTML&CSS基础-CSS的语法 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.dome.html源代码 <!DOCTYPE html> <html ...

  10. Django之路——5 Django的模板层

    你肯能已经注意到我们在例子视图中返回文本的方式有点特别. 也就是说,HTML被直接硬编码在 Python代码之中. def current_datetime(request): now = datet ...