纯CSS实现背景滚动视差效果-兼容移动端
前言
滚动视差效果应该都不陌生,一种常见的方法是用JS,监听滚动事件,在滚动时不断计算并设置容器的background-position。优点是兼容老平台IE,html结构简单,缺点是性能开销太大,以至于移动端兼容极差。
如何兼容移动端?
其实通过简单地设置background-attachment: fixed;也能实现背景不动的“视差”效果,视觉效果也比较强。但是!这个移动端也不兼容!!!(除了chrome等极少数)。这个老早之前由于开销太大而被砍掉的功能,都2020年了还不给加回来……
好在移动端大多数浏览器还是支持translate3d的,可以直接用CSS实现,性能更高也更自然。
好像iOS还是不支持,至少我那个做出来用iPhone 7 Plus测试是没有效果的。
效果
这里直接上效果图

建议直接看demo页面
可以看到,背景滚动的速度是明显比内容慢的,有多个背景。
原理及实现
先上代码
<div class="parallax-stage">
<div class="main">
<div class="row" id="row0">
<div class="bg-container">
<!-- 背景元素 -->
<div class="background"></div>
</div>
<div class="content-dark">
content here...
</div>
</div>
<div class="row" id="row1">
<!-- #row1没有背景元素,显示为白色 -->
<div class="content-light">
<!-- 此处为内容 -->
...
</div>
</div>
<!-- #row2与#row0相同 -->
<div class="row" id="row2">
<div class="bg-container">
<div class="background"></div>
</div>
<div class="content-dark">
<!-- 此处为内容 -->
...
</div>
</div>
<!-- 其他的 row 省略 -->
<div class="row" id="row3">
...
</div>
...
</div>
</div>
.body {
margin: 0; /* 确保沉浸效果 */
}
.parallax-stage {
/* 滚动容器 */
height: 100vh;
width: 100%;
/*主要看下面的*/
perspective: 1px;
overflow: auto;
}
.main {
position: relative;
/* 这里也需要3D视角,否则无法兼容Firefox等 */
transform-style: preserve-3d;
}
.row {
position: relative;
overflow: hidden;
}
.bg-container {
height: 100%;
width: 100%;
/*主要看下面的*/
/* 视差元素的父级需要3D视角 */
position: absolute;
transform-style: preserve-3d;
}
.background {
/* 滚动比较慢的背景元素 */
width: 100%;
background-size: cover;
background-position: center;
/*主要看下面的*/
position: absolute;
/* 这个-2vw和3.05后面单独讲 */
transform: translate3d(-2vw, -100vh, -2px) scale(3.05);
transform-origin: top;
height: calc((100% - 100vh)/3 + 100vh);
}
/* 再分别设置每个.background的background-image */
/* .content....此处省略 */
视差的原理的话,可以看看张鑫旭大大的这篇,讲的很详细
实不相瞒,我是看了他这篇才做出来的(滑稽)
简单来说,就是通过3D变换使背景元素(.background)远离视点,同时放大 覆盖整个视角。滚动时由于背景元素离视点更远,看起来就像是背景滚动得更慢。
Demo中有5个.row,其中#row0,#row2,#row4都分别有背景元素,有视差效果。而#row1和#row3没有背景元素。
这里主要说下:
背景元素的变换
/* translate3d的三个参数分别相当于translateX, Y和Z */
transform: translate3d(-2vw, -100vh, -2px) scale(3.05);
transform-origin: top;
height: calc((100% - 100vh)/3 + 100vh);
translate
本来应该是translate3d(0, -100vh, -2px) scale(3);
前面设置了.parallax-stage的视距为1px,这里再偏移-2px就是3倍距离,然后设置scale(3)使得大小看起来和变换之前一样。实现背景元素的滚动速度为1/3的效果。
-100vh是为了让背景元素对齐视角顶部,设置transform-origin: top;以顶部为中心缩放。
不知道是滚动条还是什么原因,正常的translate3d(0, -100vh, -2px) scale(3)会留一点白边在左侧,并不能完全覆盖视角。
不过简单地设置为translate3d(-2vw, -100vh, -2px) scale(3.05)就能解决,我也没深究其原因。
height
背景元素的高度为calc((100% - 100vh)/3 + 100vh),是一个计算值。
当背景以1/3的速度滚动时,这个值刚好合适,能够使背景元素在滚动时刚好贴合视角。怎么算的我就不说了,这个涉及数学了不好表述,简单算下应该就能得到。
如果要让背景以1/2或者其他速度滚动,这个就要重新计算。
为什么要有.bg-container
为什么不直接把背景元素放在.row 里,而是放在.bg-container里,再放到.row里?
这里是因为,如果一个元素同时设置overflow: hidden;和transform-style: preserve-3d;,transform-style: preserve-3d;很多时候会失效(但新版chrome能正常显示),原因未知。
这里你肯定不希望变换之后的背景元素超出.row,所以.row要设置overflow: hidden;,却不能同时设置transform-style: preserve-3d;,只能将其设置在.bg-container上。
结束语
由于疫情,这都4月了还没开学。昨天听说了高考延期一个月,估计中考也会延期(没错我初三)。
这样下去我中考体育完了。我也不想延期,毕竟学得比我认真的太多了,延期我也超越不了他们。
中国教育就这样,只有往死里学,才能得到不至于太糟的教育条件。只重视学科成绩,兴趣什么的毫无用处。
想跳出中国教育的高墙?那得有钱。
此博客所有文章默认采用署名—非商业性使用—相同方式共享 4.0 协议进行许可
本文链接:https://blog.texice.xyz/2020/CSS-Parallax/