在 v3.10.0 中新增
ScrollSmoother
快速入门
CDN 链接
gsap.registerPlugin(ScrollSmoother)
最简用法
ScrollSmoother.create({
smooth: 1,
effects: true,
});
ScrollSmoother 为基于 ScrollTrigger 的页面添加垂直平滑滚动效果。与大多数平滑滚动库不同,ScrollSmoother 利用NATIVE滚动 — 它不会添加“虚假”的滚动条,也不干扰触摸/指针功能。这意味着它不会出现许多常见于平滑滚动网站上的可访问性问题。
特性亮点
- 使用浏览器的原生滚动;没有“虚假”滚动条。
- 添加一个视差效果通过定义任意元素上的
data-speed
属性实现,例如data-speed="0.5"
这会使该元素在视口内时以半速“滚动”。当它位于垂直居中时达到其文档流中的正常位置。 - 将较大的图片 / 元素放在具有
overflow: hidden
样式的容器内,然后设置子元素的data-speed="auto"
样式,它将自动计算出该元素可以在容器内移动的确切距离(实现视差)。 - 让一个元素看起来像是落后,需要一定时间才能“追上”平滑滚动的位置。这是一种非常有趣的效果!只需定义一个
data-lag
属性,例如data-lag="0.5"
表示需要 0.5 秒来“追上”。
阅读更多...
- ScrollSmoother 是无缝集成与ScrollTrigger和 GSAP 实现超强健壮的动画功能。
- 设置paused(true)可完全停止滚动(用户甚至无法拖动滚动条)- 非常适合模态框使用。
- 这个
normalizeScroll: true
特性可以防止 [大部分] 移动浏览器地址栏的隐藏 / 显示(调整视口大小),阻止过度滚动行为,并解决多线程同步难题! - 使用 ScrollSmoother 的一个附带好处是它可以避免由浏览器多线程导致的问题,例如固定 / 解除固定时有时会发生的小跳动,或某些罕见情况下固定元素偶尔的“抖动”。你甚至可以设置
normalizeScroll: true
来避免常见的问题,如移动浏览器地址栏的隐藏 / 显示,同时还能规避 iOS Safari 中偶尔导致抖动的 bug。参见ScrollTrigger.normalizeScroll()了解详情。
安装配置
你的 HTML 内容应存在于一个单独的content
元素中(通常是<div>
,但具体不重要)— 当用户滚动时就是这个元素在移动。这个content
元素会被包裹在一个wrapper
元素中作为视口。实际的滚动条仍然保留在<body>
上,所以你的结构应该如下所示:
<body>
<div id="smooth-wrapper">
<div id="smooth-content">
<!--- ALL YOUR CONTENT HERE --->
</div>
</div>
<!-- position: fixed elements can go outside --->
</body>
内部机制方面,一切内容都通过ScrollTrigger流动,它监听页面原生滚动位置,然后 ScrollSmoother 对content
应用变换以逐渐追上那个滚动位置。因此如果你突然拖动原生滚动条 500px,ScrollSmoother 会使用内联 CSS 变换 (matrix3d()
) 在content
上逐步将内容移动到对应的位置。由于 ScrollSmoother 构建在 ScrollTrigger 之上,请不要忘记注册两者:
gsap.registerPlugin(ScrollTrigger, ScrollSmoother);
示例
// create the scrollSmoother before your scrollTriggers
ScrollSmoother.create({
smooth: 1, // how long (in seconds) it takes to "catch up" to the native scroll position
effects: true, // looks for data-speed and data-lag attributes on elements
smoothTouch: 0.1, // much shorter smoothing time on touch devices (default is NO smoothing on touch devices)
});
加载中...
配置对象
配置对象可以包含以下任一可选属性:
- 元素 | 字符串- 包含所有 HTML 内容的元素。这个
content
元素就是在滚动时被移动的元素。默认情况下,它会自动查找 id 为 "smooth-content" 的元素,因此如果你遵循此命名惯例,就不需要定义content
。HTML 结构如下所示:<div id="smooth-wrapper">
<div id="smooth-content">
<!--- ALL YOUR CONTENT HERE --->
</div>
</div>
<!-- position: fixed elements can go outside --> - 字符串 | 函数- 平滑滚动使用的缓动函数(默认值为 "expo")。
- 布尔值 | 字符串 | 数组- 如果设置为
true
,ScrollSmoother 将找出所有具有data-speed
和/或data-lag
属性的元素,并按指定速度或延迟应用这些效果,因此data-speed="0.5"
将以正常速度的一半滚动,data-speed="2"
将以双倍速度滚动。data-lag="0.8"
would take 0.8 seconds to "catch up" to the smoothed scroll position. You can also use selector text or an Array of elements, soeffects: ".box"
would only look for the attributes on elements with the ".box" class. You can use the effects() method to apply effects directly via JavaScript instead. See that method's docs for more details about how effects work. 注意:效果不应嵌套。 - 数字- 通常应用于某个特定元素的效果会在该元素的自然位置进入视口时开始,在其自然位置离开视口时结束,但在极少数情况下你可能希望扩展这个范围,此时你可以传递一个数字(以像素为单位)作为
effectsPadding
. 添加于 3.11.4 版本。 - 字符串- 可能你已经在使用
data-speed
和/或data-lag
用于其他用途,并且你想为效果数据属性如effectsPrefix: "scroll-"
将解析为data-scroll-speed
和data-scroll-lag
. 添加于 3.10.5 版本。 - Boolean- 如果设置为
true
,触摸屏设备上的垂直调整大小(视口高度的 25%)不会触发ScrollTrigger.refresh()
,避免在重新计算起始/结束值时可能发生的跳跃。请注意,如果你跳过了 refresh(),起始/结束触发位置可能会不准确,但在许多情况下,这优于由于新起始/结束位置导致的视觉跳跃。 - 函数- 当新的元素获得焦点时调用的函数,你可以返回
false
如果你希望 ScrollSmoother 跳过确保该元素位于视口内(覆盖默认行为)。 - 函数- 在平滑滚动停止时(追赶上原生滚动位置)调用的函数。
- 函数- 每次 SmoothScroller 更新内容位置后调用的函数。
- 布尔值- 如果设置为
true
,它会强制滚动在 JavaScript 线程上进行,确保同步性,并防止移动设备上的地址栏显示/隐藏。这等同于调用ScrollTrigger.normalizeScroll()不同之处在于对其进行了防抖处理因为平滑滚动使这成为可能。 - 数字- 追赶上原生滚动位置所需的时间(以秒为单位)。默认是 0.8 秒。
- 布尔值 | 数值- 默认情况下,ScrollSmoother 会非在仅支持触摸的设备(如手机)上应用滚动平滑,因为这通常会让用户感觉奇怪,因为它脱离了他们的手指拖动位置,但你可以通过设置
smoothTouch: true
(与smooth
值相同)或指定一个类似smoothTouch: 0.1
的时间(以秒为单位)来强制在触摸设备上启用平滑滚动。 - 数字- 整体滚动速度的倍数,因此
2
会使滚动速度变为正常速度的两倍,0.5
则会使滚动速度变为一半。添加于 3.11.4 版本。. - 元素 | 字符串- 作为视口的最外层元素。它的唯一子元素应该是
content
元素,这是滚动时被移动的部分。默认情况下,它会自动查找 id 为 "smooth-wrapper" 的元素,所以如果你遵循这个约定,则无需定义wrapper
。如果找不到 wrapper,将自动创建一个。你可以使用类似"#elementID"
的选择器文本或直接引用元素本身。
属性
描述
速度(视差)
当你设置effects: true
时,ScrollSmoother 会找到所有具有data-speed
属性的元素,并根据指定的速度应用视差效果。例如:
<div data-speed="0.5"></div>
<!-- half-speed of scroll -->
<div data-speed="2"></div>
<!-- double-speed of scroll -->
<div data-speed="1"></div>
<!-- normal speed of scroll -->
<div data-speed="auto"></div>
<!-- auto-calculated based on how far it can move inside its container -->
"auto" 速度
当你将速度设置为"auto"
时,它会计算其父容器中在最大间隙方向(向上或向下)可移动的距离。因此它非常适合视差效果——只需让子元素比父元素更大,将其对齐到你想要的位置(通常是顶部边缘与容器顶部对齐,或底部边缘与容器底部对齐),然后让 ScrollSmoother 发挥魔法。当然,在父元素上设置overflow: hidden
以便裁剪子元素。
clamp() 速度效果
你是否曾经原生地将某个元素放置在页面顶部附近,但当你应用data-speed
时,它开始偏离其原生位置?这是因为默认情况下,速度效果会让元素在视口垂直居中时达到其“原生”位置,所以它们一开始可能有偏移。从版本 3.12 开始,你可以将你的速度值包裹在"clamp()"
中,使其在“折叠上方”(即滚动到顶部时位于视口内的部分)的元素保持原生位置。实际上,data-speed
效果是由 ScrollTrigger 实例驱动的,因此这是一种利用 ScrollTrigger 的 clamp() 功能的方式,防止起始/结束值“泄露”出页面边界范围(不能小于 0,也不能大于最大滚动位置)。例如:
<div data-speed="clamp(0.5)"></div>
<!-- clamped half-speed -->
你也可以使用effects()方法动态地为目标应用速度或延迟效果(包括基于函数的效果)。注意:effects不应该嵌套.
let scroller = ScrollSmoother.create({...});
scroller.effects(".box", {speed: 0.5, lag: 0.1});
请注意,这些元素将在视口的中心处到达其“自然”位置。下面是来自@snorkltv:
加载中...
延迟(令人愉快的那种)
把“延迟”想象成让元素变得懒惰一些,让它从正常的滚动位置漂移出去并需要一定时间才能“赶上来”。你可以为邻近的元素分配略微不同的延迟以实现在滚动时非常悦目的错开效果。如果你在 ScrollSmoother.create() 配置中设置了effects: true
,它将会自动查找任何具有data-lag
属性的元素并应用该效果:
<div data-lag="0.5"></div>
<!-- takes 0.5 seconds to "catch up" -->
<div data-lag="0.8"></div>
<!-- takes 0.8 seconds to "catch up" -->
你也可以使用effects()方法通过 JavaScript 动态地为目标应用速度或延迟效果(包括基于函数的效果)。
let scroller = ScrollSmoother.create({...});
scroller.effects(".box", {lag: 0.5, speed: 1});
注意事项
- **
position: fixed
应该位于 wrapper 外部 **- 因为content
上应用了 CSStransform
,浏览器会创建一个新的包含块,这意味着position: fixed
元素将会固定到content
而不是视口。这不是 bug——这只是 CSS/浏览器的工作方式。你可以改用 ScrollTrigger 的固定功能或者你可以把任意position: fixed
元素放在wrapper
/content
. normalizeScroll: true
外部- 最新的 Apple iOS 使得无法阻止这种行为(至少根据我们目前的了解)。尽管event.preventDefault()
在所有与滚动相关的事件中都调用了该方法,但浏览器仍然强制执行了该行为。如果这导致窗口调整大小时出现跳跃,并使你的 ScrollTriggers 重新计算其起始/结束位置,你可以ScrollTrigger.config({ ignoreMobileResize: true });
属性
.progress: 数值 | 整个页面滚动的进度值,其中 0 表示在最顶部,1 表示在最底部,0.5 表示滚动到一半的位置。该值会在平滑滚动期间进行动画变化,并在 |
.scrollTrigger: ScrollTrigger | ScrollSmoother 内部创建的 ScrollTrigger 实例,用于管理页面的平滑滚动效果。 |
.vars: 对象 | 传递给ScrollSmoother.create()的配置对象。 |
方法
.content( element:String | Element ) : Element | self | 获取/设置内容元素。 |
.effects( targets:String | Element | Array, config:Object | null ) : Array | 添加应由 ScrollSmoother 管理的视差元素。 |
.getVelocity( ) : Number | 返回当前平滑滚动的速度,单位为像素/秒。 |
.kill( ) ; | 销毁整个 ScrollSmoother 以及所有已应用的效果。 |
.offset( target:String | Element, position:String ) : Number | 计算对应的数值偏移量(以像素为单位的滚动位置),即特定元素到达指定位置时的偏移量,例如: |
.paused( pause:Boolean ) : Boolean | self | 获取/设置暂停状态 - 如果为 |
.scrollTo( target:Number | String | Element, smooth:Boolean, position:String ) ; | 滚动到特定位置或元素。 |
.scrollTop( position:Number ) : Number | void | 立即获取/设置滚动位置(以像素为单位)。 |
.smooth( duration:Number ) : Number | self | 获取/设置追赶滚动位置所需的时间(即平滑度)。 |
ScrollSmoother.create( ) ; | |
ScrollSmoother.get( ) : ScrollSmoother | 返回 ScrollSmoother 实例(如果已经创建了一个)。任何时候只能存在一个实例。 |
.wrapper( element:String | Element ) : Element | self | 获取/设置包装器元素。 |
示例演示
查看完整系列的滚动动画演示在 CodePen 上。
ScrollSmoother 演示