【前端】sticky粘性定位

·  阅读 503

详细说明:【前端】position:sticky解析 这次应该大结局了 ,补充说明并修正若干概念。

基本效果

来自mdn的例子:position: sticky;top: 20px;

特性描述

看了下MDN和大佬们的讲解,通俗的总结如下:

  • 常规情况下同position:static;
  • 显示不超出其父元素的前提条件下,尽可能与 最近滚动祖先 保持指定的最小距离
  • 使用了 position:sticky; 的元素会为其子元素创建新的层叠上下文(stacking context)

最近滚动祖先 :以position:sticky;元素为起点往上找,遇到的第一个overflow-xoverflow-y不为visible的祖先节点。如果不存在,那么直接取 viewport (即浏览器视窗)。一个简略的查找算法如下:

function getStickyParent(node) {
  const parent = node.parentElement;
  if (!parent) return null;
  const style = window.getComputedStyle(parent);
  const overflows = style.overflow.split(" ");
  if (overflows.some((o) => o !== "visible")) {
    return parent;
  }
  return getStickyParent(parent);
}
复制代码

常见误区

后面可看可不看,个人踩坑经验。

对“最近滚动祖先”理解有误

学习的时候有看到说sticky元素的任意祖先元素都不要设置overflow:hidden;,实际上应该是表述有误。

详细描述应该为:如果你想让一个元素sticky到一个祖先元素,那么这个祖先元素要设置overflow为非visible的值,而且要保证它们之间的任意元素都不能有overflow为非visible的值,否则这个元素就会成为你意料之外的“最近滚动祖先”。仅当你需要对 viewport 进行sticky,才需要确保任意祖先元素都没有该值。

没有触发效果

先来搞个demo:

<div style={{ width: 400, height: 400, overflow: "auto" }}>
  <div style={{ height: 400, background: "green" }}>
    <div style={{ height: 20, width: 20, background: "pink", position: "sticky", top: 0 }} />
  </div>
  <div style={{ height: 400, background: "red" }} />
</div>
复制代码

这个很合理,一开始粉色块在没有超出绿色块的前提下,与最外面的“最近滚动祖先”尽可能保持顶部0px。但滚到最后时红色块就把绿色块完全顶开了,此时粉色块就不满足“在显示不超出其父元素的前提条件下”了,所以粉色块只能贴着绿色块的底部被一起往上顶了。

我们给粉色块再套个div#1:

<div style={{ width: 400, height: 400, overflow: "auto" }}>
  <div style={{ height: 400, background: "green" }}>
    <div id="1">
      <div style={{ height: 20, width: 20, background: "pink", position: "sticky", top: 0 }} />
    </div>
  </div>
  <div style={{ height: 400, background: "red" }} />
</div>
复制代码

这个就是常见的无效了。因为粉色块的父元素变成了div#1,而div#1的高度默认就是粉色块的高度,所以粉色块没啥操作空间,只能从头到尾跟着它的父元素div#1一起被滚动

关于这个条件的原理部分:深入理解position sticky粘性定位的计算规则

分类:
前端
标签: