本文翻译自 https://developers.google.com/web/updates/2016/12/performant-parallaxing,作者: Paul Lewis,译文: 接灰的电子产品
爱也好,恨也好,视差效果已经遍布web之上了。当你用的巧妙的时候,它可以给应用增加深度和隐喻效果。但问题在于实现一个高性能的视差效果是一个很有挑战的工作。在这篇文章里,我们将讨论如何构造一个高性能的视差效果,当然同样重要的是还得跨浏览器。
视差效果示意图
摘要
不要使用滚动事件(scroll events)或者背景定位(background-position)来创建视差动画。
使用 CSS 3D 变换来创建一个更准确的视差效果。
对于iOS移动设备的Safari浏览器使用 position: sticky 来确保视差可以生效。
如果你想要一个开箱即用的方案,请访问 Parallax helper JS ,这里还有一个 demo演示:
观看演示
视差的问题分析
在开始之前,我们先来看两个现有的常见的实现视差的方法,探讨为何它们不适合我们要追求的目标。
不好的方案:使用滚动事件
视差的关键需求是它应该是滚动耦合的:对于页面滚动的每一个位置变化,视差元素的位置也应被更新。这看上去很容易,现代浏览器的重要机制之一就是它们可以异步处理工作。尽管如此,在大多数浏览器中,滚动事件是被作为“尽量好”(best effort)的工作处理的,也就意味着:浏览器并不确保每一帧的滚动动画送达!
这个重要的信息告诉我们为什么要避免使用Javascript基于滚动事件去移动元素:Javascript并不能确保视差会和页面滚动保持同样的步调。。在一些老版本的Mobile Safari上,滚动事件甚至是在滚动完成后才触发的,这一点让基于Javascript的滚动效果无法实现。在较新的Mobile Safari版本中,滚动事件可以在动画过程中触发了,但是和Chrome一样,它是一个基于“尽量好”的原则的。所以当主线程忙于其他工作时,滚动事件不会立即触发,也就意味着视差效果的丢失。
不好的方案:更新背景位置
我们要避免的另一个场景是在每帧都进行绘制。很多方案试图采用改变 background-position 来提供视差效果, 但这会让浏览器在滚动时重绘受影响的部分,而这可能会是相当消耗资源的,这种影响会使动画卡顿。
如果我们想提供一个高质量的视差动画,我们想要的是一个可以当作加速的属性(这里我们指的是 transform 和 opacity ),而这是不依赖于滚动事件的。
CSS 3D
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 是下面的样子: