组件
极光动态背景 Aurora Background
融合多重径向渐变光斑、柔和高斯模糊与无限平滑缓动的现代极光氛围背景组件。
基础用法
极光光斑缓慢漂移;开启 interactive 后,三层光斑会以不同深度缓缓追随指针。背景跟随主题:亮色下是柔和的色雾,暗色下以滤色混合发光:
Loading…
安装与引入
通过 CLI 自动添加组件,或手动复制源码至项目中:
pnpm dlx @wui-design/cli@latest add @wui/aurora-background安装基础依赖与动效库
pnpm add motion lucide-react class-variance-authority clsx tailwind-merge复制组件源码到
components/ui/aurora-background.tsx"use client"
import * as React from "react"
import {
motion,
useMotionValue,
useReducedMotion,
useSpring,
useTransform,
type HTMLMotionProps,
type MotionValue,
} from "motion/react"
import { cn } from "@/lib/utils"
export interface AuroraBackgroundProps extends Omit<
HTMLMotionProps<"div">,
"children"
> {
/** Foreground content rendered above the aurora layers. */
children?: React.ReactNode
/** Three CSS colors used by the moving light fields. @default ["var(--chart-1)", "var(--chart-3)", "var(--chart-5)"] */
colors?: [string, string, string]
/** Seconds for one complete movement cycle. @default 18 */
duration?: number
/** Blur strength in pixels. @default 56 */
blur?: number
/** Let the light fields drift toward the pointer at different depths. @default false */
interactive?: boolean
/** Classes applied to every aurora layer. */
layerClassName?: string
}
const layers = [
{
position: "-left-[18%] -top-[28%] h-[85%] w-[75%]",
depth: 48,
x: [0, 42, -24, 0],
y: [0, -24, 30, 0],
},
{
position: "-bottom-[34%] left-[24%] h-[90%] w-[72%]",
depth: -64,
x: [0, -36, 28, 0],
y: [0, -24, 30, 0],
},
{
position: "-right-[24%] top-[8%] h-[72%] w-[62%]",
depth: 32,
x: [0, 42, -24, 0],
y: [0, 34, -18, 0],
},
]
interface AuroraLayerProps {
color: string
index: number
blur: number
duration: number
animated: boolean
pointerX: MotionValue<number>
pointerY: MotionValue<number>
className?: string
}
function AuroraLayer({
color,
index,
blur,
duration,
animated,
pointerX,
pointerY,
className,
}: AuroraLayerProps) {
const layer = layers[index]
const x = useTransform(pointerX, (value) => value * layer.depth)
const y = useTransform(pointerY, (value) => value * layer.depth)
return (
<motion.div className={cn("absolute", layer.position)} style={{ x, y }}>
<motion.div
data-slot="aurora-background-layer"
className={cn(
"size-full rounded-[50%] opacity-45 will-change-transform dark:opacity-60 dark:mix-blend-screen",
className
)}
style={{
background: `radial-gradient(closest-side, ${color}, transparent)`,
filter: `blur(${blur}px)`,
}}
animate={
animated
? { x: layer.x, y: layer.y, scale: [1, 1.12, 0.96, 1] }
: undefined
}
transition={{
duration: duration + index * 2,
repeat: Infinity,
ease: "easeInOut",
}}
/>
</motion.div>
)
}
/** Layers slow, blurred color fields behind content. */
function AuroraBackground({
children,
colors = ["var(--chart-1)", "var(--chart-3)", "var(--chart-5)"],
duration = 18,
blur = 56,
interactive = false,
className,
layerClassName,
onPointerMove,
onPointerLeave,
...props
}: AuroraBackgroundProps) {
const reduceMotion = Boolean(useReducedMotion())
const rawX = useMotionValue(0)
const rawY = useMotionValue(0)
const pointerX = useSpring(rawX, { stiffness: 36, damping: 18, mass: 1 })
const pointerY = useSpring(rawY, { stiffness: 36, damping: 18, mass: 1 })
return (
<motion.div
data-slot="aurora-background"
className={cn(
"bg-background relative isolate overflow-hidden",
className
)}
onPointerMove={(event) => {
if (interactive && !reduceMotion && event.pointerType !== "touch") {
const rect = event.currentTarget.getBoundingClientRect()
rawX.set((event.clientX - rect.left) / rect.width - 0.5)
rawY.set((event.clientY - rect.top) / rect.height - 0.5)
}
onPointerMove?.(event)
}}
onPointerLeave={(event) => {
rawX.set(0)
rawY.set(0)
onPointerLeave?.(event)
}}
{...props}
>
<div
aria-hidden="true"
className="pointer-events-none absolute inset-0 -z-10"
>
{colors.map((color, index) => (
<AuroraLayer
key={index}
color={color}
index={index}
blur={blur}
duration={duration}
animated={!reduceMotion}
pointerX={pointerX}
pointerY={pointerY}
className={layerClassName}
/>
))}
</div>
<div className="relative z-10">{children}</div>
</motion.div>
)
}
export { AuroraBackground }
属性 Props
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| children | React.ReactNode | — | 渲染在极光背景上层的主体内容(标题、按钮组、指标卡片等)。 |
| colors | [string, string, string] | ["var(--chart-1)", "var(--chart-3)", "var(--chart-5)"] | 驱动极光三层光斑的 CSS 颜色值(支持 Hex、RGB、HSL、OKLCH 或 CSS 变量),默认使用主题图表色。 |
| duration | number | 18 | 极光完成一次完整位置漂移循环所需的总秒数。 |
| blur | number | 56 | 极光光斑的高斯模糊半径(像素)。 |
| interactive | boolean | false | 光斑是否以不同深度缓慢追随指针,形成空间视差。触屏与“减少动态效果”下不生效。 |
| layerClassName | string | — | 应用于极光单个浮动图层的额外 CSS 类名。 |
| className | string | — | 应用于极光最外层包装容器的 CSS 类名。 |
事件 Events
该组件为纯视觉背景容器组件,直接继承标准 React div 的原生事件属性。
使用场景与设计规范
AuroraBackground 适用于产品发布 Hero 区、AI 会话背景、VIP 定价卡片、创意案例展台:
- 主题自适应:默认底色为
bg-background。亮色主题下光斑以普通混合呈现柔和色雾;暗色主题下切换为mix-blend-screen发光。需要固定深色舞台时,可通过className覆盖底色。 - 微弱不抢戏:极光动画的
duration推荐在 12 ~ 20 秒之间,缓慢流动的光效能提供高级的“呼吸感”,避免过快移动造成视觉疲劳。
场景示例
定价卡片
在单张卡片内使用更小的模糊半径与更短的周期:
Loading…
无障碍与交互 Accessibility
- 自动静止降级:当用户开启
prefers-reduced-motion: reduce时,光斑漂移动画将自动停滞,保留静态但依旧美观的高斯发光光晕。 - 层级隔离:极光图层默认标记
pointer-events-none与aria-hidden="true",保证上层所有表单、按钮正常获取焦点。