background-attachment: fixed 是最简视差实现方式,但 Safari(iOS 15+/macOS Monterey 后)在非 body 元素或硬件加速容器中会静默降级为 scroll;推荐仅用于 body 或全屏 section,并避免 transform、will-change 等触发硬件加速的属性,否则需改用 IntersectionObserver + requestAnimationFrame 的 JS 方案。

用 background-attachment: fixed 实现基础视差,但注意 Safari 兼容性问题
直接写 background-attachment: fixed 是最简方式,它让背景图相对于视口固定,而内容滚动,形成视差感。但 Safari(尤其是 iOS 15+ 和 macOS Monterey 后)对 background-attachment: fixed 在非 body 元素或启用了硬件加速的容器中会静默降级为 scroll,导致特效失效。
实操建议:
- 仅对
<body>或全屏<section>使用,避免嵌套在transform、will-change、overflow: hidden的父容器内 - 强制触发硬件加速时慎用
backface-visibility: hidden或transform: translateZ(0),它们会破坏 fixed 行为 - 必须支持 Safari?改用 JS 驱动方案(见下一条)
用 IntersectionObserver + requestAnimationFrame 做轻量级 JS 视差
绕过 CSS 兼容限制的可靠做法:监听元素进入视口位置,动态更新 background-position-y。关键不是“逐像素计算”,而是用滚动进度做插值,控制背景图移动速度慢于滚动速度。
示例逻辑(不依赖框架):
立即学习“前端免费学习笔记(深入)”;
const hero = document.querySelector('.hero');
const observer = new IntersectionObserver(([entry]) => {
if (!entry.isIntersecting) return;
const scrollY = window.scrollY;
const speed = 0.3; // 背景移动速度系数,< 1 即实现视差
const yPos = -scrollY * speed;
hero.style.backgroundPositionY = `${yPos}px`;
}, { threshold: 0 });
<p>observer.observe(hero);</p><p>// 配合 requestAnimationFrame 防抖滚动事件
let ticking = false;
window.addEventListener('scroll', () => {
if (!ticking) {
requestAnimationFrame(() => {
const scrollY = window.scrollY;
const yPos = -scrollY * 0.3;
hero.style.backgroundPositionY = <code>${yPos}px</code>;
ticking = false;
});
ticking = true;
}
});注意点:
- 不要在
scroll回调里直接计算并赋值——性能差;用requestAnimationFrame节流是底线 -
IntersectionObserver仅用于初始化监听,真正驱动靠scroll + rAF - 移动端需加
{ passive: true }到事件监听器,否则可能被浏览器忽略
用 transform 替代 background-position 实现更高性能视差
当大图作为独立 <img> 或伪元素存在时,用 transform: translateY() 替代修改 background-position,能触发 GPU 加速,滚动更顺滑,且兼容性更好。
结构建议:
<section class="hero"> <div class="hero__bg"><img src="hero.jpg" alt=""></div> <div class="hero__content">...</div> </section>
JS 更新逻辑改为:
const bgImg = document.querySelector('.hero__bg img');
// 在 rAF 中:
bgImg.style.transform = `translateY(${scrollY * 0.4}px)`;优势与限制:
- 比
background-position更快,尤其在低端 Android 设备上明显 - 需确保
.hero__bg有overflow: hidden,否则图片移出区域会露边 - 图片宽高比需匹配容器,否则
transform移动时会出现留白或裁切异常
响应式断点下必须重置视差系数和监听逻辑
视差效果在小屏上容易造成内容挤压、背景偏移过度或触控延迟。不能只写一套系数撑全场。
处理方式:
- 用
matchMedia监听(max-width: 768px),在平板/手机断点关闭视差(设系数为 0)或降为 0.1 - 移动端慎用
background-attachment: fixed—— iOS WebKit 已明确将其标记为“不推荐用于非 body 元素” - 如果用了
transform方案,记得在 resize 后重新计算初始偏移,否则窗口缩放后视差起点错位
最常被忽略的一点:视差区域的 height 必须是明确值(比如 100vh),不能依赖内容撑开;否则滚动进度计算失准,视差抖动或中断。


















