Skeleton 骨架屏

内容加载期间保持其形状的占位块。

'use client'

import { useState } from 'react'
import { Avatar, Button, Card, Inline, Skeleton, Stack, Text } from '@hina-ui/react'

export default function Demo() {
  const [loading, setLoading] = useState(true)

  return (
    <Stack className="w-full max-w-sm">
      <Card>
        <Inline gap="sm" align="start">
          <Skeleton loading={loading} className="rounded-full">
            <Avatar size="lg" src="/avatars/selfie.webp" alt="星见书音" />
          </Skeleton>
          <Stack gap="xs" className="min-w-0 flex-1">
            <Skeleton loading={loading}>
              <Text className="font-medium">星见书音</Text>
            </Skeleton>
            <Skeleton loading={loading}>
              <Text tone="muted" size="sm">
                翻译了 128 本轻小说
              </Text>
            </Skeleton>
          </Stack>
        </Inline>
      </Card>
      <Button size="sm" variant="soft" tone="neutral" onClick={() => setLoading(!loading)}>
        {loading ? '显示内容' : '显示骨架'}
      </Button>
    </Stack>
  )
}
tsx

用法

import { Skeleton } from '@hina-ui/react'
ts

用它包住真实内容,再传入 loading。loading 为真时内容隐藏但仍然参与布局,因此占位块的尺寸与内容将来的尺寸完全一致;loading 变为假之后包裹元素消失,只剩内容本身。

'use client'

import { useState } from 'react'
import { Button, Inline, Skeleton, Stack, Text } from '@hina-ui/react'

export default function Demo() {
  const [loading, setLoading] = useState(true)

  return (
    <Stack className="w-full max-w-sm">
      <Inline>
        <Skeleton loading={loading}>
          <Text>ATRI</Text>
        </Skeleton>
        <Skeleton loading={loading}>
          <Text tone="muted" size="sm">
            第 42 章
          </Text>
        </Skeleton>
      </Inline>
      <Button size="sm" variant="soft" tone="neutral" onClick={() => setLoading(!loading)}>
        {loading ? '加载完成' : '重新加载'}
      </Button>
    </Stack>
  )
}
tsx

不放内容时,Skeleton 就是一个普通的块,尺寸由类名给出。

import { Skeleton, Stack } from '@hina-ui/react'

export default function Demo() {
  return (
    <Stack gap="sm" className="w-full max-w-sm">
      <Skeleton className="h-4 w-1/3" />
      <Skeleton className="h-4 w-full" />
      <Skeleton className="h-4 w-4/5" />
    </Stack>
  )
}
tsx

示例

形状

形状完全由类名决定:图片用圆角矩形,头像用 rounded-full,一行文字用一条短块。

import { Card, Inline, Skeleton, Stack } from '@hina-ui/react'

export default function Demo() {
  return (
    <Card className="w-full max-w-sm">
      <Stack gap="sm">
        <Skeleton className="h-32 w-full rounded-lg" />
        <Inline gap="sm" align="center">
          <Skeleton className="size-10 rounded-full" />
          <Stack gap="xs" className="flex-1">
            <Skeleton className="h-4 w-1/2" />
            <Skeleton className="h-3 w-1/3" />
          </Stack>
        </Inline>
      </Stack>
    </Card>
  )
}
tsx

行为

  • 渐变光带从左向右扫过固定底色,默认周期为 1.2 秒;RTL 布局中方向反转。
  • 系统开启减弱动态效果时停止扫光,占位块保持静止。
  • loading 为假时组件只渲染传入的内容,不留下任何包裹元素。

无障碍

  • 占位块带 aria-hidden 和 inert,屏幕阅读器会跳过它,其中的内容也无法获得焦点。
  • 加载状态在拥有它的区域上播报,不必在每个占位块上重复。

API

属性
类型
默认值
说明
loading
boolean
true
是否显示占位块
as
string
'span'
渲染的标签
className
string
—
追加至占位块的类名
属性
说明
children
真实内容,占位块的尺寸取自它