无论爱是爱还是讨厌,视差技术都会持续存在。谨慎使用时, 来增加 Web 应用的深度和微妙之处。不过,问题在于 因此可能具有挑战性。在本文中,我们将介绍 讨论一种既高效又同样重要的解决方案 。
![视差图示。](https://developer.chrome.com/static/blog/performant-parallaxing/image/parallax-illustration-330a26c14e2fc.jpg?authuser=19&hl=zh-cn)
要点
- 请勿使用滚动事件或
background-position
来创建视差动画。 - 使用 CSS 3D 转换来创建更准确的视差效果。
- 对于 Mobile Safari,请使用
position: sticky
来确保视差效果 进行传播
如果您需要普适性解决方案,请前往 UI 元素示例 GitHub 代码库,并获取 视差辅助 JS! 您可以在以下位置观看视差滚动条的实时演示: GitHub 代码库。
问题视差器
首先,我们来看看实现视差的两种常见方法 特别是为什么它们不适合我们的用途。
坏:使用滚动事件
视差的关键要求是它应该滚动耦合;用于 每当页面滚动位置发生变化时,视差元素的 。这听起来很简单, 现代浏览器异步工作的能力。这一点适用于我们的 和滚动事件在大多数浏览器中,滚动事件 “尽力而为”并且不一定会在 滚动动画效果!
这条重要信息告诉我们,为什么需要避免 基于 JavaScript 的解决方案,根据滚动事件移动元素: JavaScript 并不保证视差技术能跟上 滚动位置。在旧版本的 Mobile Safari 中,滚动事件 实际上是在滚动结束时才投放的 基于 JavaScript 的滚动效果。较新的版本确实会传递滚动事件 但与 Chrome 浏览器类似,基础。如果 主线程正忙于任何其他工作,滚动事件将不会被传送 这意味着视差效果将会丢失。
错误:正在更新“background-position
”
我们要避免的另一种情况是在每一帧上绘制。多种解决方案
尝试更改 background-position
以提供视差外观,
会使浏览器在滚动时重新绘制网页中受影响的部分
代价可能足以使动画出现明显的卡顿。
如果我们想要实现视差运动的承诺, 可作为加速属性(目前意味着坚持使用 变形和不透明度),并且不依赖于滚动事件。
3D CSS
Scott Kellum 和 Keith Clark 在使用 CSS 3D 实现视差运动方面做了大量工作, 他们实际使用的技术就是:
- 设置一个包含元素以使用
overflow-y: scroll
(可能overflow-x: hidden
)。 - 向该元素应用
perspective
值和perspective-origin
设置为top left
或0 0
。 - 向该元素的子元素应用 Z 轴平移,然后将其缩小 以提供视差运动,而不会影响其在屏幕上的大小。
此方法的 CSS 如下所示:
.container {
width: 100%;
height: 100%;
overflow-x: hidden;
overflow-y: scroll;
perspective: 1px;
perspective-origin: 0 0;
}
.parallax-child {
transform-origin: 0 0;
transform: translateZ(-2px) scale(3);
}
这里假设 HTML 代码段如下所示:
<div class="container">
<div class="parallax-child"></div>
</div>
调整透视缩放比例
将子元素往回推,会使其与 视角值。您可以使用 此公式:(透视 - 距离)/透视。由于我们最有可能 希望视差元素呈现视差效果,但以我们编写的尺寸显示, 则需要以此方式进行扩展,而不是保持原样。
对于上述代码,透视是 1px,
parallax-child
的 Z 距离为 -2px。也就是说,该元素
要放大 3 倍,您可以看到插入代码中的值:
scale(3)
。
对于任何未应用 translateZ
值的内容,您可以
替换成零的值。这意味着该比例为 (perspective - 0) /
透视图,其值为 1,表示经
既不向上也不向下真的非常方便。
此方法的工作原理
一定要弄清楚这种验证方式的有效性,因为我们将使用
知识。滚动实际上是一种转换
accelerated;主要涉及到使用 GPU 来回移动层。在
典型的滚动(没有任何角度概念的滚动)
在比较滚动元素及其子元素时,会采用 1:1 的方式。
如果将某个元素向下滚动 300px
,其子元素将向上转换
相等金额:300px
。
但是,对滚动元素应用透视值会造成混乱
此流程;它会更改支持滚动转换的矩阵。
现在,300px 的滚动可能只会将子视图移动 150px,具体取决于
您选择的 perspective
和 translateZ
值。如果某个元素的
translateZ
值为 0,则它会以 1:1 的比例滚动(和以往一样),但子元素
按 Z 远离透视原点的位置,以不同的角度
评分!最终结果:视差运动。而且,请务必注意
浏览器内部滚动机制的一部分,这意味着
无需监听 scroll
事件或更改 background-position
。
迷幻药剂:Mobile Safari
每种效果都有一定的说明性,而对于转换,其中一个重要的是 子元素保留了 3D 效果。如果 具有透视效果的元素及其视差子元素之间的层次结构, 3D 透视是“扁平化”的,表示效果已丢失。
<div class="container">
<div class="parallax-container">
<div class="parallax-child"></div>
</div>
</div>
在上面的 HTML 中,.parallax-container
是新的,它会有效地
并展平了 perspective
值,这样就会失去视差效果。解决方法:
在大多数情况下,这相当简单:只需添加 transform-style: preserve-3d
使它能够传播任何 3D 效果(比如我们的透视效果)
值)。
.parallax-container {
transform-style: preserve-3d;
}
而在 Mobile Safari 中,则要稍微复杂一些。
从技术上讲,将 overflow-y: scroll
应用于容器元素是可行的,
快速滑动滚动元素的成本解决方法是将
-webkit-overflow-scrolling: touch
,但它也会展平 perspective
这样就无法实现任何视差效果
从渐进式增强的角度来看,这可能并不太 问题。如果我们无法在每种情况下都能实现视差,我们的应用仍会正常运行,但 最好能找到一个解决方法。
position: sticky
前去救援!
事实上,系统会以 position: sticky
的形式提供一些帮助,
允许元素“粘滞”附加到视口顶部或指定父元素
。与大多数规范一样,该规范相当庞大,但其中包含
以下实用小宝石:
乍一看,这可能并不太重要, 当它指的是某个元素的黏度 计算:"偏移是通过参考最近的祖先实体计算得出的 一个滚动框”。也就是说,粘性元素的移动距离 (要让它显示为附加到其他元素或视口)为 在应用任何其他转换之前(而不是之后)计算。这意味着 与前面的滚动示例非常相似,如果偏移 在 300 像素处,这为您提供了使用视角(或任何其他转换)的新机会 将 300 像素的偏移值应用到任何粘性广告之前 元素。
通过对视差元素应用 position: -webkit-sticky
,我们可以:
实际上是“逆向”-webkit-overflow-scrolling:
touch
的扁平化效果。这样可确保视差元素引用
祖先实体具有一个滚动框,在本例中为 .container
。然后,
与之前类似,.parallax-container
会应用 perspective
值,
这会更改计算出的滚动偏移,并产生视差效果。
<div class="container">
<div class="parallax-container">
<div class="parallax-child"></div>
</div>
</div>
.container {
overflow-y: scroll;
-webkit-overflow-scrolling: touch;
}
.parallax-container {
perspective: 1px;
}
.parallax-child {
position: -webkit-sticky;
top: 0px;
transform: translate(-2px) scale(3);
}
这样就能恢复移动 Safari 的视差效果, 一轮!
粘性定位注意事项
这里有区别,但是:position: sticky
确实会改变
视差机制。粘性定位会尝试将元素固定在
滚动容器,非粘性版本则不然。这意味着
但具有粘性的视差最终是与无以下特征的视差相反的:
- 如果使用
position: sticky
,元素越接近 z=0,它就越小 移动。 - 如果没有
position: sticky
,元素越接近 z=0, 它就会移动
如果这一切看起来有点抽象,您可以观看这个演示,由 Robert Flack 完成, 演示了使用和不使用粘性元素时元素的行为方式有何不同 定位。要查看差异,您需要使用 Chrome Canary 版(第 56 版) 或 Safari。
![视差透视屏幕截图](https://developer.chrome.com/static/blog/performant-parallaxing/image/parallax-perspective-scre-e5a0b46e4d2ad.jpg?authuser=19&hl=zh-cn)
Robert Flack 的演示,其中展示了如何
position: sticky
会影响视差滚动。
各种错误和解决方法
不过,和任何事情一样 平滑处理:
- 粘性支持不一致。仍在以下国家/地区提供支持
Chrome、Edge 完全不支持此功能,而 Firefox 则会在将粘性广告与透视转换结合使用时发生绘制错误。在此类
在这种情况下,有必要添加一些代码,以便仅添加
position: sticky
(-webkit-
前缀的版本)(针对移动 Safari) 。 - “效果不尽如人意”在 Edge 中。Edge 尝试在以下时间处理滚动操作: 操作系统级别,这通常是一件好事,但在这种情况下,它会阻止它 检测角度变化。要解决此问题,您可以添加 位置固定的元素,因为这似乎是将 Edge 切换为 非操作系统滚动方式, 并确保考虑了视角变化。
- “页面内容变得异常大!”许多浏览器都考虑到了
在决定网页内容的大小时,Chrome 和 Safari 仍有遗漏
未考虑观点。因此
例如,对某个元素应用 3 倍的缩放值,
都可以看到滚动条等类似内容,即使元素在
已应用“
perspective
”。要解决此问题,可以采用 缩放元素(使用transform-origin: bottom right
),这样做是可行的,因为它会导致尺寸过大的元素成为 “否定区域”(通常为左上角)可滚动 区域不允许您查看或滚动到排除区域中的内容。
总结
谨慎使用视差是一种有趣的效果。如您所见, 实现高性能、滚动耦合、跨浏览器。 因为这需要一点数学修饰, 样板文件以获得所需效果,我们封装了一个小型帮助程序库 和示例,您可以在我们的界面元素示例 GitHub 代码库中找到它们。
来玩一把,告诉我们您的进展情况。