反馈类

骨架屏

在需要等待加载内容的位置提供的占位组件。

概述

  • Avatar:占位头像,默认为圆形,默认尺寸:Avatar medium: width: 48px,height: 48px。支持 size、shape 属性,取值见 API 参考。
  • Image:占位图像,默认尺寸:width: 100%,height: 100%。
  • Title:占位标题,默认尺寸:width: 100%, height: 24px。
  • Paragraph:占位内容部分,默认尺寸:width: 100%,height: 16px,margin-bottom: 10px。
  • Button:占位按钮,默认尺寸:width: 115px,height: 32px。

注意:默认样式均可通过 class 或 style(字符串)进行自定义。Svelte 版的占位块既是 Skeleton.Avatar 这类静态成员,也是同一引用的具名导出:SkeletonAvatar、SkeletonImage、SkeletonTitle、SkeletonParagraph、SkeletonButton。

代码演示

如何引入

<script lang="ts">
    import { Skeleton, SkeletonAvatar, SkeletonButton, SkeletonImage, SkeletonParagraph, SkeletonTitle } from '@fibrae/semi-ui-svelte';
</script>

<Skeleton loading>
    {#snippet placeholder()}
        <SkeletonAvatar />
    {/snippet}
    <p>内容</p>
</Skeleton>

加载时显示 placeholder snippet,加载结束后显示 children。

基本使用

显示加载内容




代码
<script lang="ts">
    import { Avatar, Button, Skeleton, SkeletonAvatar, SkeletonButton, SkeletonImage, SkeletonParagraph, SkeletonTitle, Switch } from '@fibrae/semi-ui-svelte';

    let loading = $state(true);
</script>

<span style="display: flex; align-items: center">
    <Switch aria-labelledby="skeleton-basic-toggle" checked={!loading} onChange={() => (loading = !loading)} />
    <span id="skeleton-basic-toggle" style="margin-inline-start: 10px">显示加载内容</span>
</span>
<br />
<Skeleton {loading}>
    {#snippet placeholder()}
        <SkeletonAvatar />
    {/snippet}
    <Avatar color="blue" style="margin-bottom: 10px">U</Avatar>
</Skeleton>
<br />
<Skeleton {loading} style="width: 200px; height: 150px">
    {#snippet placeholder()}
        <SkeletonImage />
    {/snippet}
    <img alt="avatar" height="150" src="/assets/placeholder/avatar-a.svg" />
</Skeleton>
<br />
<Skeleton {loading} style="width: 80px">
    {#snippet placeholder()}
        <SkeletonTitle style="margin-bottom: 10px" />
    {/snippet}
    <h4 style="margin-bottom: 0">Semi UI</h4>
</Skeleton>
<Skeleton {loading} style="width: 240px">
    {#snippet placeholder()}
        <SkeletonParagraph rows={2} />
    {/snippet}
    <p style="width: 240px">精心打磨每一个组件的用户体验,从用户的角度考虑每个组件的使用场景。</p>
</Skeleton>
<br />
<Skeleton {loading}>
    {#snippet placeholder()}
        <SkeletonButton />
    {/snippet}
    <Button>Button</Button>
</Skeleton>

组合使用

图片和标题。

代码
<script lang="ts">
    import { Skeleton, SkeletonImage, SkeletonTitle } from '@fibrae/semi-ui-svelte';
</script>

<Skeleton loading>
    {#snippet placeholder()}
        <div>
            <SkeletonImage style="width: 200px; height: 150px" />
            <SkeletonTitle style="width: 120px; margin-top: 10px" />
        </div>
    {/snippet}
    <img alt="avatar" height="150" src="/assets/placeholder/avatar-a.svg" />
    <h4>Semi UI</h4>
</Skeleton>

统计数字。

代码
<script lang="ts">
    import { Descriptions, Skeleton, SkeletonParagraph, SkeletonTitle } from '@fibrae/semi-ui-svelte';

    const data = [{ key: '实际用户数量', value: '1,480,000' }];
</script>

<Skeleton loading>
    {#snippet placeholder()}
        <div>
            <SkeletonParagraph rows={1} style="width: 80px; margin-bottom: 10px" />
            <SkeletonTitle style="width: 120px" />
        </div>
    {/snippet}
    <Descriptions {data} row />
</Skeleton>

头像和标题。

代码
<script lang="ts">
    import { Avatar, Skeleton, SkeletonAvatar, SkeletonTitle } from '@fibrae/semi-ui-svelte';
</script>

<Skeleton loading>
    {#snippet placeholder()}
        <div style="display: flex; align-items: center">
            <SkeletonAvatar style="margin-inline-end: 12px" />
            <SkeletonTitle style="width: 120px" />
        </div>
    {/snippet}
    <Avatar color="blue" style="margin-inline-end: 12px">UI</Avatar>
    <span>Semi UI</span>
</Skeleton>

居中段落和按钮。

代码
<script lang="ts">
    import { Button, Skeleton, SkeletonButton, SkeletonParagraph } from '@fibrae/semi-ui-svelte';

    const style = 'display: flex; flex-direction: column; align-items: center; width: 300px; margin-bottom: 10px';
</script>

<Skeleton loading style="text-align: center">
    {#snippet placeholder()}
        <div {style}>
            <SkeletonParagraph rows={3} {style} />
            <SkeletonButton />
        </div>
    {/snippet}
    <div style="text-align: center">
        <p>Hi, Bytedance dance dance.</p>
        <p>Hi, Bytedance dance dance.</p>
        <Button>Button</Button>
    </div>
</Skeleton>

头像、标题和段落。

代码
<script lang="ts">
    import { Avatar, Skeleton, SkeletonAvatar, SkeletonParagraph, SkeletonTitle } from '@fibrae/semi-ui-svelte';

    const style = 'display: flex; align-items: flex-start';
</script>

<Skeleton loading>
    {#snippet placeholder()}
        <div {style}>
            <SkeletonAvatar style="margin-inline-end: 12px" />
            <div>
                <SkeletonTitle style="width: 120px; margin-bottom: 12px; margin-top: 12px" />
                <SkeletonParagraph rows={3} style="width: 240px" />
            </div>
        </div>
    {/snippet}
    <div {style}>
        <Avatar color="blue" style="margin-inline-end: 12px">UI</Avatar>
        <div>
            <h3>Semi UI</h3>
            <p>Hi, Bytedance dance dance.</p>
            <p>Hi, Bytedance dance dance.</p>
            <p>Hi, Bytedance dance dance.</p>
        </div>
    </div>
</Skeleton>

表格。

代码
<script lang="ts">
    import { Skeleton, SkeletonParagraph, SkeletonTitle, Table, type ColumnProps } from '@fibrae/semi-ui-svelte';

    const columns: ColumnProps[] = [
        {
            title: 'Name',
            dataIndex: 'name',
        },
        {
            title: 'Age',
            dataIndex: 'age',
        },
        {
            title: 'Address',
            dataIndex: 'address',
        },
    ];

    const dataSource = [
        {
            key: '1',
            name: 'John Brown',
            age: 32,
            address: 'New York No. 1 Lake Park, New York No. 1 Lake Park',
        },
        {
            key: '2',
            name: 'Jim Green',
            age: 42,
            address: 'London No. 1 Lake Park',
        },
        {
            key: '3',
            name: 'Joe Black',
            age: 32,
            address: 'Sidney No. 1 Lake Park',
        },
        {
            key: '4',
            name: 'Disabled User',
            age: 99,
            address: 'Sidney No. 1 Lake Park',
        },
    ];

    const placeholderColumns: ColumnProps[] = [1, 2, 3].map((key) => ({ dataIndex: `${key}` }));
    const placeholderDataSource = [1, 2, 3, 4].map((key) => ({ key }));
</script>

<Skeleton loading>
    {#snippet placeholder()}
        <div style="position: relative">
            <Table columns={placeholderColumns} dataSource={placeholderDataSource} pagination={false} style="background-color: var(--semi-color-bg-1)">
                {#snippet headerCell()}
                    <SkeletonTitle style="width: 0" />
                {/snippet}
                {#snippet cell({ column })}
                    <SkeletonParagraph rows={1} style="width: {50 * Number(column.dataIndex)}px" />
                {/snippet}
            </Table>
            <div style="position: absolute; inset: 0"></div>
        </div>
    {/snippet}
    <div>
        <Table {columns} {dataSource} pagination={false} />
    </div>
</Skeleton>

加载动画

通过设置 active 属性可以展示动画效果。

代码
<script lang="ts">
    import { Avatar, Skeleton, SkeletonAvatar, SkeletonParagraph, SkeletonTitle } from '@fibrae/semi-ui-svelte';

    const style = 'display: flex; align-items: flex-start';
</script>

<Skeleton active loading>
    {#snippet placeholder()}
        <div {style}>
            <SkeletonAvatar style="margin-inline-end: 12px" />
            <div>
                <SkeletonTitle style="width: 120px; margin-bottom: 12px; margin-top: 12px" />
                <SkeletonParagraph rows={3} style="width: 240px" />
            </div>
        </div>
    {/snippet}
    <div {style}>
        <Avatar color="blue" style="margin-inline-end: 12px">UI</Avatar>
        <div>
            <h3>Semi UI</h3>
            <p>Hi, Bytedance dance dance.</p>
            <p>Hi, Bytedance dance dance.</p>
            <p>Hi, Bytedance dance dance.</p>
        </div>
    </div>
</Skeleton>

API 参考

Skeleton

Props

属性说明类型默认值
active是否展示动画效果。boolean-
children加载结束后显示的内容。Snippet-
loading为 true 时显示 placeholder,反之显示 children。booleantrue
placeholder加载等待时的占位元素。Snippet-

class、style(字符串)与原生属性和事件落在占位根元素上。loading 为 false 时组件只渲染子内容,不再有根元素,这些属性随占位一起丢弃。根元素的 aria-busy="true" 不能被关闭。

Skeleton.Avatar

Svelte 版下面的 Skeleton.Avatar 也可写成具名导出 SkeletonAvatar,其余同理。

Props

属性说明类型默认值
prefixCls类名前缀,默认为 semi-skeleton。string-
shape占位头像的形状,可选 circle 或 square。'circle' | 'square'-
size占位头像的大小。Type'extra-extra-small' | 'extra-small' | 'small' | 'medium' | 'large' | 'extra-large'-
type替换占位块自带的类型,同时决定它的类名;不为 avatar 时 size、shape 不生效。string"avatar"

class、style(字符串)与原生属性和事件落在占位块上。

Skeleton.Image

Props

属性说明类型默认值
prefixCls类名前缀,默认为 semi-skeleton。string-
type替换占位块自带的类型,同时决定它的类名。string"image"

Skeleton.Title

Props

属性说明类型默认值
prefixCls类名前缀,默认为 semi-skeleton。string-
type替换占位块自带的类型,同时决定它的类名。string"title"

Skeleton.Button

Props

属性说明类型默认值
prefixCls类名前缀,默认为 semi-skeleton。string-
type替换占位块自带的类型,同时决定它的类名。string"button"

SkeletonImage、SkeletonTitle、SkeletonButton 没有 size、shape,class、style 与原生属性和事件落在占位块上。

Skeleton.Paragraph

Props

属性说明类型默认值
prefixCls类名前缀,默认为 semi-skeleton。string"semi-skeleton"
rows占位段落的行数。number4

class、style(字符串)与原生属性和事件落在 ul 根元素上。

Accessibility

  • 加载时 Skeleton 的外层带有 aria-busy="true",占位块与段落占位带有 aria-hidden="true",读屏只知道内容正在加载;使用方传入的同名属性优先于占位块上的 aria-hidden,aria-busy 不能被关闭。
  • 加载结束后直接渲染子内容,不再有 Skeleton 的外层元素。

文案规范

  • 不变的固定内容直接展示固定内容,可变的内容使用骨架屏展示

设计变量

下表是组件内部的 Sass 变量,不能覆写。定制样式请覆写 --semi-* CSS 变量(见 Design Token 页),或写不分层的 CSS 规则。
Sass 变量值用法
$animation_duration-skeleton-highlight1400ms骨架屏高亮动画时长
$animation_function-skeleton-highlightease
$color-skeleton_default-bg-defaultvar(--semi-color-fill-0)骨架屏背景色 - 默认
$color-skeleton_loading-gradient-bg-activevar(--semi-color-fill-1)骨架屏背景色 - 动画开启后
$width-skeleton_avatar_extra_extra_small20px头像骨架屏尺寸 - 极小
$width-skeleton_avatar_extra_small24px头像骨架屏尺寸 - 超小
$width-skeleton_avatar_small32px头像骨架屏尺寸 - 小
$width-skeleton_avatar_medium48px头像骨架屏尺寸 - 中
$width-skeleton_avatar_large72px头像骨架屏尺寸 - 大
$width-skeleton_avatar_extra_large128px头像骨架屏尺寸 - 超大
$width-skeleton_button115px按钮骨架屏宽度
$height-skeleton_li16px段落骨架屏高度
$height-skeleton_title$height-control-small标题骨架屏高度
$height-skeleton_button$height-control-default按钮骨架屏高度
$spacing-skeleton_li-marginBottom10px按钮骨架屏高度
$radius-skeleton_itemvar(--semi-border-radius-small)骨架屏圆角
$radius-skeleton_livar(--semi-border-radius-small)骨架屏圆角