组件
文字微光 Text Shimmer
运用纯 CSS 渐变遮罩与 GPU 渲染管线,在文字表面平滑扫过一道灵动高光的微动效组件。
基础用法
最简单的文字微光用法。高光将以设定的周期与渐变宽度在文字表面无限循环扫过:
Loading…
安装与引入
通过 CLI 自动添加组件,或手动复制源码至项目中:
pnpm dlx @wui-design/cli@latest add @wui/text-shimmer安装依赖与 Motion 动效库
pnpm add motion clsx tailwind-merge复制组件源码到
components/ui/text-shimmer.tsx"use client"
import * as React from "react"
import { motion, useReducedMotion } from "motion/react"
import { cn } from "@/lib/utils"
export interface TextShimmerProps extends React.ComponentProps<"span"> {
/** Text carrying the shimmer. */
children: string
/** HTML element rendered by the component. @default "span" */
as?: React.ElementType
/** Seconds for one shimmer pass. @default 2 */
duration?: number
/** Gradient width relative to the text. @default 2 */
spread?: number
}
/** Sweeps a theme-aware highlight across text. */
function TextShimmer({
children,
as = "span",
duration = 2,
spread = 2,
className,
style,
...props
}: TextShimmerProps) {
const reduceMotion = useReducedMotion()
const Component = React.useMemo(() => motion.create(as), [as])
const shimmerSpread = `${Math.max(Array.from(children).length * spread, 0)}px`
return (
<Component
data-slot="text-shimmer"
className={cn(
"inline-block bg-clip-text text-transparent [--shimmer-base:var(--muted-foreground)] [--shimmer-highlight:var(--foreground)]",
className
)}
style={{
backgroundImage: reduceMotion
? "linear-gradient(var(--shimmer-base),var(--shimmer-base))"
: "linear-gradient(90deg,transparent calc(50% - var(--shimmer-spread)),var(--shimmer-highlight),transparent calc(50% + var(--shimmer-spread))),linear-gradient(var(--shimmer-base),var(--shimmer-base))",
backgroundRepeat: "no-repeat",
backgroundSize: "250% 100%, auto",
"--shimmer-spread": shimmerSpread,
...style,
} as React.CSSProperties}
animate={
reduceMotion
? { backgroundPosition: "100% center" }
: { backgroundPosition: ["100% center", "0% center"] }
}
transition={
reduceMotion
? { duration: 0 }
: { duration, ease: "linear", repeat: Infinity }
}
{...props}
>
{children}
</Component>
)
}
export { TextShimmer }
属性 Props
TextShimmer 支持以下配置属性,并继承底层渲染 HTML 元素(默认 <span>)的全部属性:
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| children | string | — | 应用微光扫光动效的纯文本内容。 |
| duration | number | 2 | 高光完成一次从左到右完整扫描所花费的时间(单位:秒)。 |
| spread | number | 2 | 高光渐变的宽度扩散系数。数值越大高光边缘越柔和开阔,数值越小高光光柱越集中锋利。 |
| as | React.ElementType | "span" | 外层容器所渲染的语义 HTML 标签(如 span, p, h2, h3 等)。 |
| className | string | — | 应用于外层容器的额外 CSS 类名,可在此定义 CSS 变量 [--shimmer-base] 与 [--shimmer-highlight]。 |
| style | React.CSSProperties | — | 应用于外层容器的内联样式对象。 |
事件 Events
TextShimmer 支持所有原生 HTML 文本元素的鼠标与焦点事件:
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| onClick | (event: React.MouseEvent) => void | — | 点击微光文字区域时触发。 |
使用场景与设计规范
TextShimmer 适用于表达进行时、加载等待或尊贵高光特权,常见于 AI 生成过程提示、高级功能订阅 CTA 按钮、后台任务同步卡片与状态指示器。
- 明暗与对比度保障:默认情况下,底色变量
--shimmer-base采用次级文字色(var(--muted-foreground)),高光变量--shimmer-highlight采用主前景色(var(--foreground))。如需自定义颜色,请确保底色在当前背景下仍满足 WCAG AA 文本对比度标准(≥ 4.5:1)。 - 持续时间建议:扫光周期推荐设置在
1.5s ~ 2.5s。过快的扫光容易引起视觉疲劳,过慢则缺乏流动感。 - 与骨架屏结合:在异步数据加载或 AI 流式准备阶段,相比传统的灰色色块骨架屏,带有扫光的动态文本能给用户更明确的进度预期。
场景示例
高优先级行动按钮
将 TextShimmer 与操作按钮结合,提升 AI 操作或升级入口的吸引力。放在主按钮上时,用 color-mix 基于 --primary-foreground 派生底色与高光:
Loading…
后台处理状态卡片
在多步骤的 AI 任务中,只让“正在进行”的那一步带有微光,已完成与待办步骤保持静态,层级一目了然:
Loading…
自定义主题配色
通过覆盖 --shimmer-base 和 --shimmer-highlight CSS 变量适配语义状态色。示例直接使用主题的 success / info / warning / destructive 令牌,并用 color-mix 与背景色混合出高光,亮暗模式自动适配:
Loading…
<TextShimmer
duration={1.8}
spread={3}
className="[--shimmer-base:theme(colors.emerald.600)] [--shimmer-highlight:theme(colors.emerald.200)]"
>
All nodes synchronized (0 errors)
</TextShimmer>无障碍与交互 Accessibility
- 文本可被正常选中与复制:底层通过
bg-clip-text与text-transparent实现渐变填充,DOM 结构内保留完整纯文本,用户可以正常鼠标双击选词并复制文本。 - 系统减少动态偏好(Reduced Motion):当系统开启
prefers-reduced-motion时,组件将禁用无限循环的backgroundPosition动画,直接展示静态的单色基底文本,保障前庭觉敏感用户的舒适度。