Skeleton 骨架屏
Skeleton 用于展示加载状态,并预览组件的预期形状。
用法
import { Skeleton } from '@lenso/ui';此预览复用英文版适配,不代表中文源示例已完成本地实现。
"use client";// Adapted from HeroUI v3.2.6 (Apache-2.0).import { Skeleton } from "@lenso/ui";import * as stylex from "@stylexjs/stylex";const styles = stylex.create({ panel: { width: 250, display: "flex", flexDirection: "column", gap: 20, borderRadius: "var(--radius-lg)", backgroundColor: "transparent", padding: 16, boxShadow: "var(--shadow-panel)", }, text: { display: "flex", flexDirection: "column", gap: 12 }, picture: { height: 128, borderRadius: "var(--radius-lg)" }, short: { height: 12, width: "60%", borderRadius: "var(--radius-lg)" }, long: { height: 12, width: "80%", borderRadius: "var(--radius-lg)" }, shortest: { height: 12, width: "40%", borderRadius: "var(--radius-lg)" },});export function Basic() { return ( <div {...stylex.props(styles.panel)}> <Skeleton xstyle={styles.picture} /> <div {...stylex.props(styles.text)}> <Skeleton xstyle={styles.short} /> <Skeleton xstyle={styles.long} /> <Skeleton xstyle={styles.shortest} /> </div> </div> );}export default Basic;Local adaptation source above. Derived from HeroUI v3.2.6 source.
示例
文本内容
此预览复用英文版适配,不代表中文源示例已完成本地实现。
"use client";// Adapted from HeroUI v3.2.6 (Apache-2.0).import { Skeleton } from "@lenso/ui";import * as stylex from "@stylexjs/stylex";const styles = stylex.create({ text: { width: "100%", maxWidth: 448, display: "flex", flexDirection: "column", gap: 12 }, line: { height: 16, borderRadius: "var(--radius)" }, full: { width: "100%" }, five: { width: "83.333333%" }, four: { width: "66.666667%" }, half: { width: "50%" },});export function TextContent() { return ( <div {...stylex.props(styles.text)}> <Skeleton xstyle={[styles.line, styles.full]} /> <Skeleton xstyle={[styles.line, styles.five]} /> <Skeleton xstyle={[styles.line, styles.four]} /> <Skeleton xstyle={[styles.line, styles.full]} /> <Skeleton xstyle={[styles.line, styles.half]} /> </div> );}export default TextContent;Local adaptation source above. Derived from HeroUI v3.2.6 source.
用户资料
此预览复用英文版适配,不代表中文源示例已完成本地实现。
"use client";// Adapted from HeroUI v3.2.6 (Apache-2.0).import { Skeleton } from "@lenso/ui";import * as stylex from "@stylexjs/stylex";const styles = stylex.create({ row: { display: "flex", alignItems: "center", gap: 12 }, avatar: { height: 40, width: 40, flexShrink: 0, borderRadius: "50%" }, text: { flex: 1, display: "flex", flexDirection: "column", gap: 8 }, name: { height: 12, width: 144, borderRadius: "var(--radius-lg)" }, detail: { height: 12, width: 96, borderRadius: "var(--radius-lg)" },});export function UserProfile() { return ( <div {...stylex.props(styles.row)}> <Skeleton xstyle={styles.avatar} /> <div {...stylex.props(styles.text)}> <Skeleton xstyle={styles.name} /> <Skeleton xstyle={styles.detail} /> </div> </div> );}export default UserProfile;Local adaptation source above. Derived from HeroUI v3.2.6 source.
列表项
此预览复用英文版适配,不代表中文源示例已完成本地实现。
"use client";// Adapted from HeroUI v3.2.6 (Apache-2.0).import { Skeleton } from "@lenso/ui";import * as stylex from "@stylexjs/stylex";const styles = stylex.create({ list: { width: "100%", maxWidth: 384, display: "flex", flexDirection: "column", gap: 16 }, row: { display: "flex", alignItems: "center", gap: 12 }, avatar: { height: 40, width: 40, flexShrink: 0, borderRadius: "var(--radius-lg)" }, text: { flex: 1, display: "flex", flexDirection: "column", gap: 8 }, full: { height: 12, width: "100%", borderRadius: "var(--radius)" }, short: { height: 12, width: "80%", borderRadius: "var(--radius)" },});export function List() { return ( <div {...stylex.props(styles.list)}> {Array.from({ length: 3 }, (_, index) => ( <div key={index} {...stylex.props(styles.row)}> <Skeleton xstyle={styles.avatar} /> <div {...stylex.props(styles.text)}> <Skeleton xstyle={styles.full} /> <Skeleton xstyle={styles.short} /> </div> </div> ))} </div> );}export default List;Local adaptation source above. Derived from HeroUI v3.2.6 source.
网格
此预览复用英文版适配,不代表中文源示例已完成本地实现。
"use client";// Adapted from HeroUI v3.2.6 (Apache-2.0).import { Skeleton } from "@lenso/ui";import * as stylex from "@stylexjs/stylex";const styles = stylex.create({ grid: { display: "grid", width: "100%", maxWidth: 576, gridTemplateColumns: "repeat(3, minmax(0, 1fr))", gap: 16, }, bone: { height: 96, borderRadius: "var(--radius-xl)" },});export function Grid() { return ( <div {...stylex.props(styles.grid)}> <Skeleton xstyle={styles.bone} /> <Skeleton xstyle={styles.bone} /> <Skeleton xstyle={styles.bone} /> </div> );}export default Grid;Local adaptation source above. Derived from HeroUI v3.2.6 source.
单次闪烁
同步的 shimmer 效果会一次性扫过所有骨架元素。在父容器上应用 skeleton--shimmer 类,并将子骨架的 animationType 设为 "none"。
此预览复用英文版适配,不代表中文源示例已完成本地实现。
"use client";// Adapted from HeroUI v3.2.6 (Apache-2.0).import { Skeleton } from "@lenso/ui";import * as stylex from "@stylexjs/stylex";const styles = stylex.create({ grid: { display: "grid", width: "100%", maxWidth: 576, gridTemplateColumns: "repeat(3, minmax(0, 1fr))", gap: 16, borderRadius: "var(--radius-xl)", backgroundColor: "transparent", }, bone: { height: 96, borderRadius: "var(--radius-xl)" },});export function SingleShimmer() { return ( <Skeleton xstyle={styles.grid}> <Skeleton animationType="none" xstyle={styles.bone} /> <Skeleton animationType="none" xstyle={styles.bone} /> <Skeleton animationType="none" xstyle={styles.bone} /> </Skeleton> );}export default SingleShimmer;Local adaptation source above. Derived from HeroUI v3.2.6 source.
动画类型
此预览复用英文版适配,不代表中文源示例已完成本地实现。
"use client";// Adapted from HeroUI v3.2.6 (Apache-2.0).import { Skeleton } from "@lenso/ui";import * as stylex from "@stylexjs/stylex";const styles = stylex.create({ grid: { display: "grid", width: "100%", maxWidth: 576, gridTemplateColumns: { default: "1fr", "@media (min-width: 640px)": "repeat(2, minmax(0, 1fr))", "@media (min-width: 1024px)": "repeat(3, minmax(0, 1fr))", }, gap: 24, }, column: { display: "flex", flexDirection: "column", gap: 8 }, label: { fontSize: 12, lineHeight: "16px", color: "var(--muted)", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", }, panel: { display: "flex", flexDirection: "column", gap: 12, borderRadius: "var(--radius-lg)", backgroundColor: "transparent", padding: 16, boxShadow: "var(--shadow-panel)", }, picture: { height: 80, borderRadius: "var(--radius-lg)" }, short: { height: 12, width: "60%", borderRadius: "var(--radius-lg)" }, long: { height: 12, width: "80%", borderRadius: "var(--radius-lg)" },});export function AnimationTypes() { return ( <div {...stylex.props(styles.grid)}> {(["shimmer", "pulse", "none"] as const).map((animationType) => ( <div key={animationType} {...stylex.props(styles.column)}> <p {...stylex.props(styles.label)}> {animationType === "shimmer" ? "Shimmer" : animationType === "pulse" ? "Pulse" : "None"} </p> <div {...stylex.props(styles.panel)}> <Skeleton animationType={animationType} xstyle={styles.picture} /> <Skeleton animationType={animationType} xstyle={styles.short} /> <Skeleton animationType={animationType} xstyle={styles.long} /> </div> </div> ))} </div> );}export default AnimationTypes;Local adaptation source above. Derived from HeroUI v3.2.6 source.
自定义样式
Tailwind CSS
此预览复用英文版适配,不代表中文源示例已完成本地实现。
"use client";// Adapted from HeroUI v3.2.6 (Apache-2.0).import { Skeleton } from "@lenso/ui";import * as stylex from "@stylexjs/stylex";const shine = stylex.keyframes({ from: { translate: "-100% 0" }, to: { translate: "100% 0" },});const styles = stylex.create({ panel: { width: 250, display: "flex", flexDirection: "column", gap: 20, borderRadius: "var(--radius-xl)", border: "1px solid color-mix(in oklab, var(--border) 80%, transparent)", backgroundColor: "var(--surface)", padding: 16, boxShadow: "0 1px 2px 0 rgb(0 0 0 / .05), 0 0 0 1px light-dark(rgb(0 0 0 / .05), rgb(255 255 255 / .1))", }, text: { display: "flex", flexDirection: "column", gap: 12 }, bone: { borderRadius: "var(--radius-lg)", backgroundColor: "light-dark(oklch(92.2% 0 0 / .9), oklch(26.9% 0 0 / .9))", "::after": { position: "absolute", inset: 0, width: "100%", height: "100%", content: '""', translate: "-100% 0", backgroundImage: "linear-gradient(120deg, transparent 10%, light-dark(rgb(255 255 255 / .3), rgb(255 255 255 / .1)) 45%, light-dark(rgb(255 255 255 / .1), rgb(255 255 255 / .04)) 55%, transparent 90%)", animationName: { default: shine, "@media (prefers-reduced-motion: reduce)": "none" }, animationDuration: "3s", animationTimingFunction: "ease-in-out", animationIterationCount: "infinite", pointerEvents: "none", }, }, picture: { height: 128 }, short: { height: 12, width: "60%" }, long: { height: 12, width: "80%" }, shortest: { height: 12, width: "40%" },});export function CustomStyles() { return ( <div {...stylex.props(styles.panel)}> <Skeleton xstyle={[styles.bone, styles.picture]} /> <div {...stylex.props(styles.text)}> <Skeleton xstyle={[styles.bone, styles.short]} /> <Skeleton xstyle={[styles.bone, styles.long]} /> <Skeleton xstyle={[styles.bone, styles.shortest]} /> </div> </div> );}export default CustomStyles;Local adaptation source above. Derived from HeroUI v3.2.6 source.
全局 CSS
若要自定义组件类,可使用 @layer components 指令。了解更多。
@layer components { /* Base skeleton styles */ .skeleton { @apply bg-surface-secondary/50; /* Change base background */ }
/* Shimmer animation gradient */ .skeleton--shimmer:before { @apply viasurface; /* Change shimmer gradient color */ }
/* Pulse animation */ .skeleton--pulse { @apply animate-pulse opacity-75; /* Customize pulse animation */ }
/* No animation variant */ .skeleton--none { @apply opacity-50; /* Style for static skeleton */ }}全局动画配置
可在全局 CSS 中通过 --skeleton-animation 变量为所有 Skeleton 组件设置默认动画类型:
/* 全局 CSS 文件 */:root { /* 可选值:shimmer、pulse、none */ --skeleton-animation: pulse;}
/* 也可为浅色/深色主题设置不同值 */.light, [data-theme="light"] { --skeleton-animation: shimmer;}
.dark, [data-theme="dark"] { --skeleton-animation: pulse;}在单个组件上指定 animationType 属性会覆盖此全局设置。
样式参考
HeroUI 遵循 BEM 方法论,确保组件变体与状态可复用且易于自定义。
全局动画配置
你可以通过在应用中定义 --skeleton-animation CSS 变量,为所有 Skeleton 设置默认动画类型:
/* In your global CSS file */:root { /* Possible values: shimmer, pulse, none */ --skeleton-animation: pulse;}
/* You can also set different values for light/dark themes */.light, [data-theme="light"] { --skeleton-animation: shimmer;}
.dark, [data-theme="dark"] { --skeleton-animation: pulse;}在单个组件上指定 animationType 时,会覆盖上述全局设置。
CSS 类
Skeleton 使用以下 CSS 类(查看源码样式):
基础类 [!toc]
.skeleton - 包含背景与圆角等基础骨架样式
动画变体类 [!toc]
.skeleton--shimmer- 添加带渐变效果的闪烁动画(默认).skeleton--pulse- 使用 Tailwind 的animate-pulse添加脉冲动画.skeleton--none- 无动画的静态骨架
动画
Skeleton 支持三种动画类型,视觉效果各不相同:
闪烁动画 [!toc]
闪烁效果会在骨架元素上移动渐变:
.skeleton--shimmer:before { @apply animate-skeleton via-surface-3 absolute inset-0 -translate-x-full bg-gradient-to-r from-transparent to-transparent content-[''];}闪烁动画在主题中通过以下方式定义:
@theme inline { --animate-skeleton: skeleton 2s linear infinite;
@keyframes skeleton { 100% { transform: translateX(200%); } }}脉冲动画 [!toc]
脉冲动画使用 Tailwind 内置的 animate-pulse 工具类:
.skeleton--pulse { @apply animate-pulse;}无动画 [!toc]
用于不需要任何动画的静态骨架:
.skeleton--none { /* No animation styles applied */}API 参考
Skeleton
| Prop | 类型 | 默认值 | 描述 |
|---|---|---|---|
animationType | "shimmer" | "pulse" | "none" | "shimmer" 或 CSS 变量 | Skeleton 的动画类型;也可通过 --skeleton-animation CSS 变量进行全局配置 |
className | string | - | 额外的 CSS 类名 |