skrollr 官方示例全解析:从经典视差到锚点、缓动与 SVG 路径绘制

原创2026-09-30 19:05:251,763 阅读
文章标签:前端

skrollr 官方示例全解析:从经典视差到锚点、缓动与 SVG 路径绘制

本篇指南以 skrollr 仓库 examples/README.md 中收录的官方示例清单为主线,逐个拆解其背后的 data-* 属性语法、锚点机制、自定义缓动函数与渲染回调等核心技术点,并结合 src/skrollr.js 源码说明底层实现。读完本文,你将掌握如何把 skrollr 的示例移植到自己的页面中,以及每个示例究竟演示了什么能力、改哪些参数可以控制效果。

示例目录与运行方式

examples/ 目录是 skrollr 官方效果的集中展示区,每个 HTML 文件都对应一个独立、可复制的技术场景。它们全部使用浏览器原生 JavaScript,不依赖 jQuery,仅引入构建产物 dist/skrollr.min.js(仓库内对应源码为 src/skrollr.js)。

本地查看这些示例时,需要在一个 HTTP 服务下运行(直接双击打开 file:// 协议在某些浏览器中可能受限)。最简单的方式是在仓库根目录启动静态服务器,例如:

python -m http.server 8000

然后访问 http://localhost:8000/examples/classic.html 即可。注意示例脚本路径为 ../dist/skrollr.min.js,必须保持 examples/ 与 dist/ 的相对目录结构才能正常加载。

examples/README.md 一共收录了 8 个示例,分别聚焦不同的能力,对应关系如下:

示例文件(仓库内路径) 演示主题
index.html 主示例:综合展示 skrollr 的绝大多数能力
examples/classic.html 经典视差:多个分区 + 分区之间穿插视差图片
examples/anchors.html 锚点:data-start/data-end 等不同锚点类型
examples/anchor_target.html 锚点目标:data-anchor-target 绑定其他元素
examples/pausing.html 暂停:滚动到某处暂停,穿插其他动画
examples/path.html 绘制 SVG 路径:stroke-dashoffset 动画
examples/circular_motion.html 圆周运动:两个自定义缓动函数驱动
examples/bg_constant_speed_less.html 恒定速度视差背景(内容较少版)
examples/gradientsmotherfucker.html 渐变:旋转的 CSS 线性渐变背景

其中 examples/bg_constant_speed_more.html 是恒定速度背景示例的"更多内容"对照版,与 bg_constant_speed_less.html 成对出现,用于演示相同动画效果与内容高度无关。

核心语法基础:一切从 data-* 属性开始

在深入每个示例前,先建立 skrollr 的语法心智模型。skrollr 不要求你写任何 JavaScript 动画代码,它扫描 DOM 中带 data-[数值] 或 data-[锚点] 形式的属性,把属性值当作关键帧,根据滚动位置在关键帧之间线性插值。属性值格式为 CSS 声明列表:

<div data-0="opacity:1;" data-500="opacity:0;"></div>

表示:滚动位置为 0 时透明度为 1,滚动到 500px 时透明度为 0,中间过程由 skrollr 自动插值。

这种设计在主示例 index.html 中体现得淋漓尽致。它把 background-position、width、top、transform、opacity、display 等大量属性串成一条滚动时间线,例如:

<div id="bg1" data-0="background-position:0px 0px;" data-end="background-position:-500px -10000px;"></div>
<div id="progress" data-0="width:0%;background:hsl(200, 100%, 50%);" data-end="width:100%;background:hsl(920, 100%, 50%);"></div>

data-end 是特殊锚点,代表"文档滚动到底部";data-0 则代表"文档顶部"(配合 forceHeight 默认开启时,页面高度会被撑高以容纳动画空间,见下文)。主示例还展示了动画的不仅仅是 transform 和 opacity,还包括 hsl() 颜色、width、border-radius、font-size、z-index 等数值属性,甚至是 display:none 这样的非数值切换。对应地,src/skrollr.js 在解析属性值时会区分可插值的数值/颜色与只能跳变的离散值,这正是 index.html 里 data-3000="display:block;" data-3700="top:-100%;display:none;" 能工作的原因。

示例一:经典分区视差(classic.html)

examples/classic.html 演示了最常见的商业站点视差布局:多个内容分区(header/content),分区之间夹着全屏图片"gap",图片以 position:fixed 固定在视口内,随滚动以不同速度移动。

其关键 HTML 结构(节选)为:

<div class="parallax-image-wrapper parallax-image-wrapper-100"
     data-anchor-target="#dragons + .gap"
     data-bottom-top="transform:translate3d(0px, 200%, 0px)"
     data-top-bottom="transform:translate3d(0px, 0%, 0px)">
  <div class="parallax-image parallax-image-100"
       style="background-image:url(images/kitteh1.jpg)"
       data-anchor-target="#dragons + .gap"
       data-bottom-top="transform: translate3d(0px, -80%, 0px);"
       data-top-bottom="transform: translate3d(0px, 80%, 0px);"></div>
</div>

这里有两个重要机制:

  1. data-anchor-target 重定向锚点:外层 wrapper 和内层图片的动画进度都不以自身位置为基准,而是以 #dragons + .gap 这个兄弟选择器匹配到的元素(即标题分区 #dragons 后面紧跟的 .gap 占位块)为基准。这是 skrollr 允许把动画绑定到页面任意元素的关键特性,源码解析见 src/skrollr.js:运行时读取元素的 data-anchor-target 属性,把该属性值作为 CSS 选择器去 querySelector,找不到时回退到元素自身。
  2. 双层反向位移制造视差深度:wrapper 从 200% 移到 0%,内层图片从 -80% 移到 +80%,两者速度差让图片看起来"穿行"在内容之间。注释也直接指出:"the +/-80% translation can be adjusted to control the speed difference of the image"——调大这组百分比就能增强视差速度差。

配套 CSS 中 .skrollr-desktop body { height:100% !important; }、.skrollr .gap { background:transparent !important; } 与 .parallax-image.skrollable-between { display:block; } 一起构成了"渐进增强"策略:无 JavaScript 时显示静态背景图,启用 skrollr 后隐藏 .gap 的真实背景、只显示固定定位的动画图片层。同时页面把固定定位的图片层放在 #skrollr-body 之外,这是 skrollr 使用 position:fixed 元素的硬性要求——#skrollr-body 内部的元素会被视为普通文档流,固定定位才不会被滚动容器干扰。

该示例的初始化参数也值得注意:

skrollr.init({
    smoothScrolling: false,
    mobileDeceleration: 0.004
});

smoothScrolling: false 关闭桌面端平滑滚动(直接跟随原生滚动),mobileDeceleration: 0.004 设置移动端惯性滚动减速系数,数值越小减速越慢、滑得越远。对应源码默认值见 src/skrollr.js:mobileDeceleration 默认 0.004,smoothScrolling 默认开启。

示例二:锚点类型大全(anchors.html)

examples/anchors.html 是一个纯粹的锚点语法教学页,页面中 7 个彩色方块分别演示 7 种锚点写法(节选):

<div class="box" data-start="background:hsl(0,50%,75%);" data-end="background:hsl(180,50%,75%);">start / end</div>
<div class="box" data-bottom-top="background:hsl(0,50%,75%);" data-top-bottom="background:hsl(180,50%,75%);">bottom-top / top-bottom</div>
<div class="box" data-top-top="background:hsl(0,50%,75%);" data-bottom-bottom="background:hsl(180,50%,75%);">top-top / bottom-bottom</div>
<div class="box" data-center-top="background:hsl(0,50%,75%);" data-center-bottom="background:hsl(180,50%,75%);">center-top / center-bottom</div>
<div id="bacon" class="box" data-center-center="background:hsl(0,50%,75%);" data-1-center-center="background:hsl(180,50%,75%);">center-center / 1-center-center</div>
<div class="box" data-50-bottom-bottom="background:hsl(0,50%,75%);" data--50-top-top="background:hsl(180,50%,75%);">50-bottom-bottom / -50-top-top</div>
<div class="box" data-300-end="background:hsl(0,50%,75%);" data-end="background:hsl(180,50%,75%);">300-end / end</div>

锚点名的通用格式为 [数字][视图位置]-[元素位置],语义是"元素的哪个边缘,与视口的哪个位置对齐时触发":

  • top/bottom/center 指元素自身的边缘或中心;
  • 前缀数字(如 1、50、300、-50)表示元素边缘越过视口对应位置 n 个自身高度(正数向下越、负数向上越),单位是元素高度倍数;
  • start/end 则分别对应文档顶部/底部,等价于全局滚动位置 0 与最大滚动位置,可省略数字前缀直接使用。

例如 data-50-bottom-bottom 表示"元素底部越过视口底部 50 个元素高度"时到达关键帧;data--50-top-top 表示"元素顶部在视口顶部上方 50 个元素高度"处。data-300-end 则把关键帧定在距文档底部 300px 处。

该页初始化时设置了 skrollr.init({ forceHeight: false }),因为示例需要大量真实文档流内容来产生滚动距离,不再需要 skrollr 自动撑高页面。forceHeight 默认为 true(见 src/skrollr.js),开启时 skrollr 会在文档末尾插入一个高度等于滚动最大位置的元素,确保 data-end 等锚点有足够的滚动空间;内容本身足够高时设为 false 可避免多余的空白。

示例三:把动画绑到别的元素上(anchor_target.html)

examples/anchor_target.html 是 data-anchor-target 的专项演示:页面右侧有一个 position:fixed 的蓝色方块,它的动画进度完全跟随左侧文档流中的红色方块 #red——红方块滚出视野时,蓝方块同步旋转并"振动"。

关键代码(节选):

<div id="red" data-bottom="transform:rotate(0deg);transform-origin:center;" data-top="transform:rotate(360deg);"></div>

<div id="blue_wrapper" data-smooth-scrolling="off">
  <div id="blue"
       data-anchor-target="#red"
       data-0="background-position:!0 bottom;"
       data-bottom-top="margin-right[vibrate]:0px;background-position:!0 0;"
       data-top-bottom="margin-right[vibrate]:20px;background-position:!0 bottom;"></div>
</div>

本示例带出三个进阶知识点:

  1. data-anchor-target 的值是选择器:#blue 的动画以 #red 的位置为基准。结合示例一可以总结出规则——想让某个元素(尤其是 position:fixed 元素)跟随其他元素的位置变化,就在它上面写 data-anchor-target="<选择器>"。
  2. data-smooth-scrolling="off" 元素级开关:在 #blue_wrapper 上关闭平滑滚动,让振动效果不被打散。源码在 src/skrollr.js 读取该属性,若为 "off" 则该 skrollable 不参与平滑滚动插值。
  3. [easing] 属性级缓动与 ! 强制值前缀:margin-right[vibrate] 表示该属性使用名为 vibrate 的自定义缓动;background-position:!0 0 中的 ! 前缀表示该属性的值不做插值、直接使用关键帧原值(用于避免 background-position 插值导致的非预期中间帧)。自定义缓动在初始化时注册:
skrollr.init({
    forceHeight: false,
    easing: {
        vibrate: function(p) {
            return Math.sin(p * 10 * Math.PI);
        }
    }
});

缓动函数接收归一化进度 p(0 到 1),返回变换后的进度值,vibrate 用 sin 在 0~1 区间内来回振荡 5 个周期,于是蓝方块在动画区间内快速抖动。主示例 index.html 中还演示了 linear、quadratic、cubic、swing、WTF(即 Math.random)、inverted(1-p)、bounce 等多种缓动,以及 color[swing] 这种"只给颜色属性套缓动"的写法。

示例四:用 constants 常量实现滚动暂停(pausing.html)

examples/pausing.html 演示如何在滚动途中"暂停":三张全屏图层依次切换,第二层滚动到一半时内部的蓝色进度条用 150% 视口高度的滚动距离慢慢填满,形成视觉上的停留。

HTML 关键结构(节选):

<div data-0="transform:translate(0,0%);" data-100p="transform:translate(0,-100%);"></div>

<div data-0="transform:translate(0,100%);" data-100p="transform:translate(0,0%)"
     data-_box-100p="" data-_box-200p="transform:translate(0,-100%)">
  <div class="box" data-100p="width:0%;" data-_box-100p="width:100%"></div>
</div>

<div data-_box-100p="transform:translate(0,100%);" data-_box-200p="transform:translate(0,0%);"></div>

初始化代码定义了常量:

skrollr.init({
    constants: {
        //fill the box for a "duration" of 150% of the viewport (pause for 150%)
        //adjust for shorter/longer pause
        box: '150p'
    }
});

这里的核心是 constants(常量)机制:

  • data-100p 中的 100p 是内建常量语法,p 后缀表示"视口高度的百分比",即滚动到 1 个视口高度处。
  • 自定义常量 box: '150p' 定义后,data-_box-100p 中的 _box 会被替换为 150p,于是该锚点实际等于 data-150p-100p——比 data-100p 再远 150% 视口高度。蓝色进度条就在这段"额外 150% 视口高度"的滚动中从 width:0% 填到 width:100%,第三张图也在这之后才开始入场,从而产生"暂停"错觉。

改注释中 box: '150p' 的数值即可加长/缩短暂停距离。源码层面,constants 在 src/skrollr.js 从 options.constants 读取,并在 src/skrollr.js 的求值函数中对所有 _xxx 形式的常量进行字符串替换(支持函数与字符串值),窗口 resize 时还会重新求值——因此常量可以安全地依赖视口尺寸(如 p 单位)。

示例五:滚动驱动 SVG 路径描边(path.html)

examples/path.html 展示了一个精巧的组合用法:不画任何 canvas,仅靠 skrollr 驱动 SVG 的 stroke-dashoffset 属性,让一条复杂贝塞尔路径在滚动时"被画出来"。

关键代码(节选):

<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="900px" height="1200px">
  <path
    style="fill:none;stroke:#333333;stroke-width:7;...;stroke-dasharray:6000;stroke-dashoffset:0"
    data-0="stroke-dashoffset:6000;" data-end="stroke-dashoffset:0;"
    d="m 199.16266,227.29566 c ..." />
</svg>

原理是:stroke-dasharray 设为路径总长(此处约 6000px),起始时 stroke-dashoffset: 6000 让整条虚线全部"偏移出"可视区域(看起来为空),滚动到文档末尾时 stroke-dashoffset: 0 让虚线完整呈现。由于 stroke-dashoffset 是数值属性,skrollr 可以逐像素插值,滚动过程就等价于路径描边动画。这个示例再次印证了 skrollr 的通用性:任何 CSS 数值属性都可以被滚动驱动,SVG 呈现属性也不例外。初始化同样使用 skrollr.init({ forceHeight: false }),因为 1200px 高的 SVG 加正文已经提供了足够的滚动距离。

示例六:两个缓动函数合成圆周运动(circular_motion.html)

examples/circular_motion.html 演示如何用缓动函数把一条直线滚动"翻译"成二维圆周运动:一个黑色圆点沿圆形轨迹绕圈,滚到底部后自动回到顶部继续循环。

HTML 与初始化代码:

<div id="thing" data-0="left[cos]:10%;top[sin]:10%;" data-10000="left:90%;top:90%;"></div>

<script>
skrollr.init({
    easing: {
        sin: function(p) {
            return (Math.sin(p * Math.PI * 2 - Math.PI/2) + 1) / 2;
        },
        cos: function(p) {
            return (Math.cos(p * Math.PI * 2 - Math.PI/2) + 1) / 2;
        },
    },
    render: function(data) {
        //Loop
        if(data.curTop === data.maxTop) {
            this.setScrollTop(0, true);
        }
    }
});
</script>

两个关键点:

  1. 属性级缓动 [sin] / [cos]:left[cos] 让水平位置按余弦曲线变化,top[sin] 让垂直位置按正弦曲线变化,两者相位相差 90°,叠加后元素轨迹即圆周。自定义函数把三角函数输出归一化到 0~1 区间,保证最终值落在两个关键帧(10% → 90%)的范围内。
  2. render 回调 + setScrollTop:render 在每次渲染时被调用,参数 data 携带 curTop/maxTop 等当前滚动信息;当滚动到达最大值时调用 this.setScrollTop(0, true) 强制跳回顶部(第二个参数 true 表示即时跳转、不做平滑动画),从而形成无限循环。这是 skrollr 官方示例中唯一使用 JavaScript 回调解耦动画循环的案例,也展示了 src/skrollr.js 对外暴露的 setScrollTop API 的典型用法。

示例七:与内容高度无关的恒定速度背景(bg_constant_speed_less / more)

examples/bg_constant_speed_less.html 与 examples/bg_constant_speed_more.html 是一对对照实验:页面标题明确写道 "Demo of background scrolling at constant speed independent of content height"——背景以恒定速度滚动,且不受内容高度影响。

两个文件的实现完全一致(节选):

<body data-0="background-position:0px 0px;" data-100000="background-position:0px -50000px;">

要点在于:

  • 关键帧用绝对像素 data-100000(滚动 100000px 处)而不是百分比锚点,因此背景位移 -50000px 与视口、内容高度都无关,只取决于全局滚动量——这就是"恒定速度"的来源。
  • 两个页面一个内容少、一个内容多,但同一个 body 关键帧让背景移动速度完全相同,直观证明速度与内容高度解耦。
  • 配合 CSS background:url(images/bubbles.png) repeat fixed; 使用 position:fixed 背景图,避免背景跟随文档滚动。
  • 两页初始化均为 skrollr.init({ forceHeight: false }),依赖真实内容高度产生滚动距离。

值得注意的是,这种写法会让 data-end 之外的剩余滚动继续无动画(滚动超过 100000px 后背景停在 -50000px),实际项目中应根据页面最大滚动高度估算合适的终值,或改用 data-end 配合百分比换算。

示例八:旋转渐变背景(gradientsmotherfucker.html)

examples/gradientsmotherfucker.html 展示了对 CSS 渐变的滚动驱动:页面背景从红/橙渐变旋转到 10 圈之后的多色渐变,底部还有一张图片随接近页尾而淡入。

关键代码(节选):

<body data-0="background-image:linear-gradient(0deg, hsl(0, 100%, 50%), hsl(40, 50%, 50%));"
      data-5000="background-image:linear-gradient(3600deg, hsl(360, 100%, 50%), hsl(400, 100%, 50%));">

<div id="bottom" data-500-end="opacity:0;" data-end="opacity:1;">
  <img src="images/slj.png" />
</div>

这里展示了 skrollr 对**非数值属性(background-image)**的处理:linear-gradient 本身无法插值,skrollr 会在关键帧之间直接切换(跳变),因此示例通过把角度参数从 0deg 一步改到 3600deg、配合渐变色相从 0 跳到 360,在到达 data-5000 的瞬间完成"旋转"——这是属性级离散值的标准用法。而 #bottom 的 opacity 则走正常的数值插值,在最后 500px 滚动中淡入。初始化直接 skrollr.init(),使用全部默认参数(forceHeight: true 会撑高页面以容纳 5000px 的动画空间)。

从示例反推:核心初始化参数速查

综合 8 个示例的初始化配置,可以整理出最常用的 skrollr.init(options) 参数及它们在 src/skrollr.js 中的默认值:

参数 默认值 作用 出现示例
forceHeight true 是否在文档末尾插入元素撑高页面,为 data-end 等锚点预留滚动空间 anchors.html、anchor_target.html、path.html 等设为 false
smoothScrolling true 桌面端是否用平滑滚动插值替代原生滚动 classic.html 设为 false
mobileDeceleration 0.004 移动端触摸惯性滚动的减速系数,越小滑行越远 classic.html 设为 0.004
easing 内置 linear 等 注册自定义缓动函数,可在 属性名[缓动名] 中按属性使用 anchor_target.html 的 vibrate、circular_motion.html 的 sin/cos、index.html 的多种内置缓动
constants 空对象 定义 _name 形式的常量,在锚点中替换,支持依赖视口尺寸的 p 单位 pausing.html 的 box: '150p'
render 无 每次渲染回调,接收含 curTop/maxTop 的数据对象,可用于循环、统计等 circular_motion.html 的滚动循环

对应的选项解析逻辑集中在 src/skrollr.js,forceHeight 的行为(是否在页面末尾追加占位元素)在 src/skrollr.js,移动端减速距离的计算在 src/skrollr.js。

小结:把官方示例变成你的工具箱

examples/ 目录的 8 个示例覆盖了 skrollr 的全部核心能力,可以当作一份"能力地图"来检索:

每个示例都只有不到 100 行、无任何构建依赖,直接复制 HTML 片段、替换选择器与关键帧数值即可快速落地。想进一步验证行为细节,可阅读测试目录 test/tests.js 中针对锚点解析、缓动与属性插值的断言,以及 README.md 顶部的快速上手说明。

登录后查看全文
skrollr