如何使用 CSS 完成视差滚动效果?
问题解析
视差滚动(Parallax Scrolling)是一种通过多层背景以不同速度移动来创建立体运动效果的技术。面试考察这个问题,是想要了解候选人是否掌握 CSS 高级特性,以及能否用纯 CSS 实现视觉效果。
什么是视差滚动
视差滚动是指多层背景以不同的速度移动,形成立体的运动效果,带来出色的视觉体验。
网页可以解构成三个层次:
- 背景层:移动最慢(通常是背景图)
- 内容层:正常移动(主要内容)
- 悬浮层:移动最快(浮动元素)
当滚动页面时,各层以不同速度移动,产生深度感。
CSS 实现方案
方案一:background-attachment: fixed
最简单直接的视差实现方式:
.parallax-section {
height: 100vh;
background-attachment: fixed; /* 关键属性 */
background-position: center;
background-repeat: no-repeat;
background-size: cover;
}
.bg-1 { background-image: url('bg1.jpg'); }
.bg-2 { background-image: url('bg2.jpg'); }
.bg-3 { background-image: url('bg3.jpg'); }
<section class="parallax-section bg-1">
<h1>第一屏内容</h1>
</section>
<section class="content-section">
<p>普通内容</p>
</section>
<section class="parallax-section bg-2">
<h1>第二屏内容</h1>
</section>
原理
background-attachment: fixed 使背景图相对于视口固定,而不是随元素滚动。当元素滚动经过视口时,背景保持不动,产生视差效果。
优缺点
| 优点 | 缺点 |
|---|---|
| 实现简单 | 效果相对单一 |
| 性能较好 | 无法实现多层视差 |
| 兼容性好 | 移动端可能有兼容问题 |
方案二:transform + perspective(3D 视差)
更强大的多层视差实现:
/* 容器设置 3D 视角 */
.parallax-container {
height: 100vh;
overflow-x: hidden;
overflow-y: auto;
perspective: 1px; /* 3D 视角深度 */
}
/* 内容层 */
.parallax-layer {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
}
/* 背景层 - 移动最慢 */
.layer-back {
transform: translateZ(-2px) scale(3); /* 远离屏幕,移动慢 */
}
/* 中间层 - 正常速度 */
.layer-base {
transform: translateZ(0); /* 正常位置 */
}
/* 前景层 - 移动最快 */
.layer-front {
transform: translateZ(1px) scale(0.5); /* 靠近屏幕,移动快 */
}
原理
利用 CSS 3D 变换:
perspective创建 3D 透视效果translateZ()将元素在 Z 轴方向上移动- 距离屏幕越远的元素(Z 值越小),滚动时移动越慢
scale补偿 Z 轴移动带来的大小变化
计算公式:scale = 1 + (translateZ * -1) / perspective
例如 translateZ(-2px) 配合 perspective: 1px:
scale = 1 + 2/1 = 3
完整示例
<div class="parallax-wrapper">
<div class="parallax-layer layer-back">
<img src="mountains.jpg" alt="远山">
</div>
<div class="parallax-layer layer-base">
<h1>主要内容</h1>
<p>滚动查看效果</p>
</div>
<div class="parallax-layer layer-front">
<img src="trees.png" alt="前景树木">
</div>
</div>
.parallax-wrapper {
perspective: 1px;
height: 100vh;
overflow-x: hidden;
overflow-y: auto;
scroll-behavior: smooth;
}
.parallax-layer {
position: absolute;
inset: 0;
display: flex;
align-items: center;
justify-content: center;
}
.layer-back {
transform: translateZ(-4px) scale(5);
}
.layer-base {
transform: translateZ(0);
}
.layer-front {
transform: translateZ(2px) scale(0.5);
}
深入理解
性能优化
.parallax-layer {
/* 开启硬件加速 */
will-change: transform;
/* 或者 */
transform: translateZ(0);
backface-visibility: hidden;
}
移动端适配
iOS Safari 对 background-attachment: fixed 支持不佳,建议使用:
@supports (-webkit-touch-callout: none) {
/* iOS 设备 */
.parallax-section {
background-attachment: scroll;
/* 或使用 JS 方案 */
}
}
使用 CSS 变量控制速度
:root {
--parallax-speed-slow: -2;
--parallax-speed-normal: 0;
--parallax-speed-fast: 1;
}
.parallax-layer {
--speed: var(--parallax-speed-normal);
--scale: calc(1 + (var(--speed) * -1) / var(--perspective, 1));
transform:
translateZ(calc(var(--speed) * 1px))
scale(var(--scale));
}
.layer-slow {
--speed: var(--parallax-speed-slow);
}
.layer-fast {
--speed: var(--parallax-speed-fast);
}
JavaScript 增强方案
纯 CSS 视差有局限,复杂场景可结合 JS:
window.addEventListener('scroll', () => {
const scrolled = window.pageYOffset;
// 不同层以不同速度移动
document.querySelector('.layer-back').style.transform =
`translateY(${scrolled * 0.5}px)`;
document.querySelector('.layer-front').style.transform =
`translateY(${scrolled * -0.3}px)`;
});
注意:使用 requestAnimationFrame 和 passive: true 优化性能:
let ticking = false;
window.addEventListener('scroll', () => {
if (!ticking) {
window.requestAnimationFrame(() => {
// 更新视差效果
ticking = false;
});
ticking = true;
}
}, { passive: true });
现代 CSS 方案
scroll-timeline(实验性)
@keyframes parallax {
to {
transform: translateY(100px);
}
}
.parallax-element {
animation: parallax linear;
animation-timeline: scroll(root);
}
最佳实践
- 不要过度使用:过多视差效果会导致眩晕
- 考虑性能:视差效果消耗 GPU 资源
- 提供关闭选项:尊重用户的
prefers-reduced-motion设置
@media (prefers-reduced-motion: reduce) {
.parallax-layer {
transform: none !important;
}
}
- 移动端简化:移动设备上减少或禁用视差效果
面试要点
- 能够说出
background-attachment: fixed实现视差的方法 - 理解
transform: translateZ()配合perspective的 3D 视差原理 - 了解视差效果的性能影响和优化方法
- 知道移动端的兼容性问题和解决方案
- 了解
prefers-reduced-motion媒体查询的无障碍支持