position:sticky 的 polyfill——stickyfill 源码浅析

本人最近在修改 blogsue 中的样式时,使用到了 position: sticky。话不多说,开始主要内容。

定义

position: sticky 是 CSS position 属性的一个新值。正如它的名字那样,它会“黏在”你的浏览器窗口中。这个展示方式有很多的应用场景。例如知乎的右侧就是这样一个场景:当用户一直往下翻的时候右侧的专栏(广告)固定住,不会消失在用户界面。又例如手机端的美团,上面的筛选框也需要保持左边固定。

正如之前的瀑布流与 colum-count 一样,这类应用广泛的排版格式最终都会有原生的实现。 具体使用方式此处就不展开了,可以参照MDN:https://developer.mozilla.org/zh-CN/docs/Web/CSS/position

Polyfill——stickyfill

position: sticky 作为新特性,兼容问题一直是一个迈不过去的坎。可以看到整个 IE 系列都不支持:

此处,如果我们希望兼容旧版本的浏览器,我们就需要借助 polyfill 的力量了。这就是 stickyfill(https://github.com/wilddeer/stickyfill)。 在我们进行接下来的探索前,要说明的是**stickyfill 并不是 position: sticky 的完全实现。**他们的最终效果有些许差异:

  • stickyfill 不支持x轴
  • stickyfill 会将元素限制在父元素内,即父元素离开屏幕后该元素也会离开(贴着父元素的边)

stickyfill 用法介绍

在 stickyfill repo 中,作者介绍了该 polyfill 的使用方式:

<div class="sticky">
    ...
</div>
复制代码
.sticky {
    position: -webkit-sticky;
    position: sticky;
    top: 0;
}
复制代码

Then apply the polyfill:

var elements = document.querySelectorAll('.sticky');
Stickyfill.add(elements);
复制代码

pollyfill 作为“补丁”,最理想的状态下是只需要将其代码引入到项目中,之后不需要做任何事情。例如 Promise 的 polyfill,就是直接在 global 下创建了 promise 类,我们只需引入,其会自动帮我们做好准备工作。但 stickyfill能否这样做呢? 理论上是可以的。因为 stickyfill 只需要遍历 DOM 树找出所有 position attribute 为 sticky 的 DOM 节点,然后对其添加规则即可。但在实际中,由于遍历 DOM 树性能消耗太高,stickyfill 退而求其次,让我们来选择需要遍历的节点。

源码简析

刚刚我们知道了 stickyfill 的用法,可以知道,stickyfill 是将我们所需要处理的元素进行了托管,利用 javascript 的能力来模拟实现 position: sticky 的功能。 接下来我们一起去看一下 stickyfill 是如何管理、处理元素的。基于文章长度限制,本文只讲解核心的几个方法。下面的源码为了条理清晰,经过精简:

包内预设变量 && 托管元素自定义类

stickyfill 模块内预设了一些类以及变量:

// 此处 stickies 是该库存放所有托管节点的数组
const stickies = [];

// 用来存放最新状态的top和left值
const scroll = {
    top: null,
    left: null
};

// Sticky类
// 所有确认需要维护的节点都会被这个类wrap
class Sticky {
    constructor (node) {
        // 差错检测
        if (!(node instanceof HTMLElement))
            throw new Error('First argument must be HTMLElement');
        // 防止重复出现相同的DOM节点
        if (stickies.some(sticky => sticky._node === node))
            throw new Error('Stickyfill is already applied to this node');
        
        // wrap的DOM节点
        this._node = node;
        // 存放DOM节点当前的状态,有三个值:
        
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值