index.html如何制作一个带有视差滚动效果的网页?

作者:袖梨 2026-06-26
视差滚动本质是JavaScript监听scroll事件,动态设置各层元素transform: translateY()实现速度差;背景层系数小(如0.2)、前景层系数大(如0.8),需配合requestAnimationFrame节流、position定位及z-index分层。

视差滚动本质是 CSS transform + scroll 事件联动

视差滚动不是某个现成的 HTML 标签或属性,而是靠监听 window.scrollY,动态调整不同层级元素的 transform: translateY() 值来模拟远近移动速度差异。纯 CSS 方案(如 background-attachment: fixed)兼容性差、控制粒度粗,现代实现基本依赖 JavaScript 驱动。

关键点在于:背景层位移量 = -scrollY × 0.3,内容层位移量 = -scrollY × 0.1,系数越小“越远”,越大越“近”。系数为 0 就是普通滚动。

常见错误现象:transform 直接写死固定值、没加 will-change: transform 导致卡顿、用 top 替代 transform 触发重排。

  • 必须给参与视差的元素设置 position: relativeabsolute,否则 transform 可能不生效
  • 所有视差元素应包裹在同一个容器内(如 <div id="parallax-container">),便于统一计算基准
  • 移动端需额外监听 touchmovepreventDefault(),否则 iOS Safari 会禁用 scrollY 更新

用 requestAnimationFrame 避免 scroll 事件抖动

直接在 scroll 事件里改样式会导致频繁重绘,尤其低端设备容易掉帧。正确做法是把滚动位置缓存下来,用 requestAnimationFrame 节流更新视差位移。

立即学习“前端免费学习笔记(深入)”;

示例核心逻辑:

let lastScrollY = window.scrollY;function updateParallax() {  const currentScrollY = window.scrollY;  const diff = currentScrollY - lastScrollY;  // 更新各层偏移:layer1.style.transform = `translateY(${currentScrollY * 0.2}px)`  lastScrollY = currentScrollY;}window.addEventListener('scroll', () => {  if (!rafId) rafId = requestAnimationFrame(updateParallax);});

注意:requestAnimationFrame 不是防抖,而是确保只在下一帧执行一次,避免 scroll 事件密集触发导致样式反复计算。

  • 不要用 setTimeout(..., 0)debounce(16) 替代,它们无法保证与屏幕刷新同步
  • 如果页面有多个视差区域,每个区域应独立维护自己的 lastScrollY,不能共用一个全局变量
  • 首次加载时需手动调用一次 updateParallax(),否则初始位置不匹配

background-attachment: fixed 在 Safari 上失效怎么办

很多教程推荐用 background-attachment: fixed 实现简易视差,但它在 iOS Safari 和部分 Android WebView 中被禁用(出于性能考虑),表现为背景图随内容一起滚动,毫无视差效果。

这不是 bug,是 Safari 的明确行为。检查是否生效只需打开 Safari 开发者工具 → Elements → 查看 computed styles 中 background-attachment 是否被标为 invalid 或直接忽略。

  • 替代方案只有 JS 驱动:给背景图容器设 background-position: center calc(50% + ${offset}px),再配合 background-repeat: no-repeat
  • 若坚持用 fixed,必须加降级逻辑:@supports not (background-attachment: fixed) { ... } 里补上 JS 方案
  • 使用 background-size: cover 时,background-position 的百分比计算会受缩放影响,建议统一用 px 单位做偏移

视差层叠顺序和 z-index 容易被忽略

视差不是简单地让背景“往后跑”,而是要让视觉层次符合物理直觉:远处的云应该在山后面,山在建筑后面,建筑在文字前面。但默认情况下,所有元素都在同一 stacking context,z-index 不起作用。

必须为每一层显式创建 stacking context,否则无论怎么调 z-index,层叠顺序都由 HTML 书写顺序决定。

  • 给每层加 position: relative + z-index 是最简方式,例如:<div class="layer" style="z-index: 1;">(远)→ z-index: 10(近)
  • 若某层用了 transform(比如视差位移),它自动成为 stacking context,此时 z-index 仍有效,但仅对它的子元素生效
  • 移动端双指缩放时,transform 层可能意外遮挡其他层,建议在 touchstart 时临时移除视差逻辑,缩放结束后再恢复

真正麻烦的从来不是怎么动起来,而是动起来之后,哪一层该在前、哪一层该透出边缘、缩放时是否撕裂——这些细节没处理好,用户第一反应就是“卡”或者“怪”。

相关文章

精彩推荐