wui
组件

视差滚动 Parallax

依据页面或局部容器滚动进度,以差异化速率与缩放变换驱动图层位移的深度空间视觉组件。

第三方依赖 · motion

基础用法

在局部滚动容器中向下滚动:背景图、标题与下方三张图片以不同速度和方向移动,形成纵深层次:

Loading…

安装与引入

通过 CLI 自动添加组件,或手动复制源码至项目中:

pnpm dlx @wui-design/cli@latest add @wui/parallax
安装基础依赖与动效库
pnpm add motion lucide-react class-variance-authority clsx tailwind-merge
复制组件源码到 components/ui/parallax.tsx
components/ui/parallax.tsx
"use client"

import * as React from "react"
import {
  motion,
  useReducedMotion,
  useScroll,
  useSpring,
  useTransform,
  type HTMLMotionProps,
  type SpringOptions,
  type UseScrollOptions,
} from "motion/react"

import { cn } from "@/lib/utils"

export interface ParallaxProps extends Omit<
  HTMLMotionProps<"div">,
  "children"
> {
  /** Content translated as the wrapper crosses the viewport. */
  children: React.ReactNode
  /** Translation axis. @default "y" */
  axis?: "x" | "y"
  /** Translation range in pixels from scroll start to end. @default [-48, 48] */
  distance?: [number, number]
  /** Optional scale range, useful for image-within-frame parallax. */
  scale?: [number, number]
  /** Optional rotation range in degrees. */
  rotate?: [number, number]
  /** Optional opacity range. */
  opacity?: [number, number]
  /** Follow scroll through a spring for a softer, trailing layer. Pass spring options to tune it. @default false */
  smooth?: boolean | SpringOptions
  /** Scrollable element to observe instead of the page. */
  container?: React.RefObject<HTMLElement | null>
  /** Motion scroll offsets for the wrapper. @default ["start end", "end start"] */
  offset?: UseScrollOptions["offset"]
}

const defaultSpring: SpringOptions = {
  stiffness: 120,
  damping: 24,
  mass: 0.4,
  restDelta: 0.0005,
}

/** Moves a layer at a different rate while it crosses the viewport. */
function Parallax({
  children,
  axis = "y",
  distance = [-48, 48],
  scale,
  rotate,
  opacity,
  smooth = false,
  container,
  offset = ["start end", "end start"],
  className,
  style,
  ...props
}: ParallaxProps) {
  const target = React.useRef<HTMLDivElement>(null)
  const reduceMotion = useReducedMotion()
  const { scrollYProgress } = useScroll({ target, container, offset })
  const springProgress = useSpring(
    scrollYProgress,
    typeof smooth === "object" ? smooth : defaultSpring
  )
  const progress = smooth ? springProgress : scrollYProgress
  const translation = useTransform(progress, [0, 1], distance)
  const scaleValue = useTransform(progress, [0, 1], scale ?? [1, 1])
  const rotateValue = useTransform(progress, [0, 1], rotate ?? [0, 0])
  const opacityValue = useTransform(progress, [0, 1], opacity ?? [1, 1])

  return (
    <motion.div
      ref={target}
      data-slot="parallax"
      data-axis={axis}
      className={cn("will-change-transform", className)}
      style={{
        ...style,
        x: reduceMotion || axis === "y" ? 0 : translation,
        y: reduceMotion || axis === "x" ? 0 : translation,
        scale: reduceMotion ? 1 : scaleValue,
        rotate: reduceMotion ? 0 : rotateValue,
        opacity: reduceMotion || !opacity ? style?.opacity : opacityValue,
      }}
      {...props}
    >
      {children}
    </motion.div>
  )
}

export { Parallax }

属性 Props

属性类型默认值说明
childrenReact.ReactNode—受视差滚动力度驱动变换的子图层元素(如图片、文字标语、浮动卡片)。
axis"x" | "y""y"视差变换的位移主轴。
distance[number, number][-48, 48]从视差起始点到结束点的位移区间(单位:像素)。例如 [-100, 100] 表示由上至下位移 200px。
scale[number, number]—伴随滚动进度同步插值的缩放比例区间,如 [1.0, 1.25] 可实现深邃的画框缩放视差。
rotate[number, number]—伴随滚动进度插值的旋转角度区间(度)。
opacity[number, number]—伴随滚动进度插值的不透明度区间,常用于文字随进入视口淡入。
smoothboolean | SpringOptionsfalse让图层通过弹簧跟随滚动进度,产生轻微的惯性拖尾。可传入弹簧参数自定义手感。
containerReact.RefObject<HTMLElement | null>—局部滚动容器的 ref 引用。不传时默认监听整个全局 window 视口滚动。
offsetUseScrollOptions["offset"]["start end", "end start"]Motion useScroll 监听的视口交叉触发锚点区间。
classNamestring—应用于视差动画外层的 CSS 类名(通常配合 will-change-transform 优化渲染)。

使用场景与设计规范

Parallax 适用于官网 Hero 首屏、沉浸式品牌故事页、媒体图文画廊:

  • 分层速率递进:背景层使用低速慢移(如 distance={[-30, 30]}),中景使用标准速度,前景点缀元素使用大位移(如 distance={[-100, 100]}),能够营造出极强的真实 3D 纵深感。
  • 画框内裁切:对图片外层使用 overflow-hidden,并让缩放余量大于位移量(或把图层向外扩展,如 -inset-y-20),避免图片在位移边缘露白。
  • 惯性拖尾:前景小元素开启 smooth 会显得更轻盈;大面积背景保持默认的直接绑定,避免与滚动产生错位感。

场景示例

画框内缩放

图片在固定画框内同时缩放与位移,说明文字通过 opacity 与自定义 offset 随后淡入:

Loading…

无障碍与交互 Accessibility

  • 自动静止降级:当系统配置了 prefers-reduced-motion: reduce 时,组件将直接将 x、y 位移重置为 0,scale 重置为 1,完全消除晃动感。
  • 硬件加速:自动附带 will-change-transform 类名,交由 GPU 独立合成图层渲染,避免重排导致的掉帧与滚动卡顿。