代码演示
如何引入
<script lang="ts">
import { Avatar, AvatarGroup } from '@fibrae/semi-ui-svelte';
</script>
尺寸
可以通过 size 属性设置图标大小,支持extra-extra-small,extra-small,small,default,medium,large,extra-large。
代码
<script lang="ts">
import { Avatar } from '@fibrae/semi-ui-svelte';
const sizes = ['extra-extra-small', 'extra-small', 'small', 'default', 'medium', 'large', 'extra-large'];
</script>
<div>
{#each sizes as size (size)}
<Avatar alt="用户" {size} style="margin: 4px">U</Avatar>
{/each}
</div>颜色
Avatar 支持默认色板的 15 种颜色和白色,包括:amber、 blue、 cyan、 green、 grey、 indigo、 light-blue、 light-green、 lime、 orange、 pink、 purple、 red、 teal、 violet、 yellow。也可以通过 style 来自定义颜色样式。默认为grey。
代码
<script lang="ts">
import { Avatar } from '@fibrae/semi-ui-svelte';
</script>
<div>
<Avatar alt="Alice Swift" style="margin: 4px">AS</Avatar>
<Avatar alt="Bob Matteo" color="red" style="margin: 4px">BM</Avatar>
<Avatar alt="Taylor Joy" color="light-blue" style="margin: 4px">TJ</Avatar>
<Avatar alt="Zank Lance" style="color: #f56a00; background-color: #fde3cf; margin: 4px">ZL</Avatar>
<Avatar alt="Youself Zhang" style="background-color: #87d068; margin: 4px">YZ</Avatar>
</div>自适应字符大小
字符类型的头像,字体大小会根据头像宽度自适应调整。使用gap调整字符头像距离左右两侧的像素大小。
代码
<script lang="ts">
import { Avatar } from '@fibrae/semi-ui-svelte';
</script>
<div>
<Avatar style="margin: 4px">AS</Avatar>
<Avatar gap={4} style="margin: 4px">Semi</Avatar>
<Avatar gap={10} style="margin: 4px">Semi</Avatar>
</div>图片
可以通过 src 设置图片格式的头像。
代码
<script lang="ts">
import { Avatar } from '@fibrae/semi-ui-svelte';
const src = '/assets/placeholder/avatar-a.svg';
</script>
<div>
<Avatar alt="漂亮的猫咪" {src} style="margin: 4px" />
<Avatar alt="可爱的猫咪" size="small" {src} style="margin: 4px" />
</div>形状
Avatar 支持 circle、square 两种形状,默认为 circle。
代码
<script lang="ts">
import { Avatar } from '@fibrae/semi-ui-svelte';
</script>
<div>
<Avatar alt="用户" style="margin: 4px">U</Avatar>
<Avatar alt="用户" shape="square" style="margin: 4px">U</Avatar>
</div>事件
Avatar 支持 onclick、onMouseEnter、onMouseLeave,传了 onclick 才成为可聚焦的 button。通过 hoverMask snippet 传入悬停覆盖层,用 {#snippet hoverMask()}...{/snippet} 写在 Avatar 标签内,覆盖层无默认样式。
代码
<script lang="ts">
import { IconCamera } from '@fibrae/semi-icons-svelte';
import { Avatar } from '@fibrae/semi-ui-svelte';
</script>
<Avatar alt="Bob Downton" color="red">
BD
{#snippet hoverMask()}
<div style="background-color: var(--semi-color-overlay-bg); height: 100%; width: 100%; display: flex; align-items: center; justify-content: center">
<IconCamera />
</div>
{/snippet}
</Avatar>顶部和底部 Slot
topSlot、bottomSlot 属性配置标记外观,topSlotText、bottomSlotText snippet 提供内容。topSlot.render、bottomSlot.render 传 snippet 时,由它完全渲染标记;topSlot.style、bottomSlot.style 是字符串。
代码
<script lang="ts">
import { IconPlus } from '@fibrae/semi-icons-svelte';
import { Avatar } from '@fibrae/semi-ui-svelte';
</script>
<Avatar alt="漂亮的猫咪" border={{ color: '#FE2C55', motion: true }} bottomSlot={{ shape: 'circle', bgColor: '#FE2C55' }} contentMotion size="large" src="/assets/placeholder/avatar-a.svg" style="margin: 4px" topSlot={{ gradientStart: 'rgb(255,23,100)', gradientEnd: 'rgb(237,52,148)' }}>
{#snippet topSlotText()}直播{/snippet}
{#snippet bottomSlotText()}
<IconPlus />
{/snippet}
</Avatar>顶部
代码
<script lang="ts">
import { Avatar } from '@fibrae/semi-ui-svelte';
const sizes = ['medium', 'large', 'extra-large'];
</script>
<div>
{#each sizes as size (size)}
<Avatar color="amber" {size} topSlot={{ gradientStart: 'rgb(255,23,100)', gradientEnd: 'rgb(237,52,148)' }}>
T
{#snippet topSlotText()}直播{/snippet}
</Avatar>
{/each}
</div>底部
T
代码
<script lang="ts">
import { IconPlus } from '@fibrae/semi-icons-svelte';
import { Avatar } from '@fibrae/semi-ui-svelte';
const sizes = ['medium', 'large', 'extra-large'];
</script>
<div>
{#each sizes as size (size)}
<Avatar bottomSlot={{ shape: 'square', bgColor: '#FE2C55' }} color="amber" {size}>
T
{#snippet bottomSlotText()}直播中{/snippet}
</Avatar>
{/each}
<br /><br /><br />
{#each sizes as size (size)}
<Avatar bottomSlot={{ shape: 'circle', bgColor: '#FE2C55' }} color="amber" {size}>
T
{#snippet bottomSlotText()}
<IconPlus />
{/snippet}
</Avatar>
{/each}
</div>额外边框
代码
<script lang="ts">
import { Avatar } from '@fibrae/semi-ui-svelte';
</script>
<div>
{#each [1, 2, 3] as index (index)}
<Avatar border color="amber" style="margin-right: 8px">T</Avatar>
{/each}
</div>额外动效
通过 border 的 motion 字段和 contentMotion 开启边框和内容区域的额外动效。
代码
<script lang="ts">
import { Avatar } from '@fibrae/semi-ui-svelte';
const sizes = ['medium', 'large', 'extra-large'];
</script>
<div>
{#each sizes as size (size)}
<Avatar border={{ motion: true }} color="amber" contentMotion {size} style="margin-right: 8px">T</Avatar>
{/each}
</div>头像组
可以通过 AvatarGroup 将 avatar 显示为组。
Svelte 的 AvatarGroup 用 items 传入每个头像的属性,用 item snippet(参数 { item, index })提供头像内的文字,不接受 Avatar 子节点。
代码
<script lang="ts">
import { AvatarGroup } from '@fibrae/semi-ui-svelte';
const items = [{ alt: 'Lisa LeBlanc', color: 'red' as const }, { alt: 'Caroline Xiao' }, { alt: 'Rafal Matin', color: 'amber' as const }, { alt: 'Zank Lance', style: 'color: #f56a00; background-color: #fde3cf' }, { alt: 'Youself Zhang', style: 'background-color: #87d068' }];
const initials = (alt = '') =>
alt
.split(' ')
.map((word) => word[0])
.join('');
</script>
<div>
<AvatarGroup {items}>
{#snippet item({ item })}
{initials(item.alt)}
{/snippet}
</AvatarGroup>
</div>可以通过 maxCount 设置展示的头像数量。
代码
<script lang="ts">
import { AvatarGroup } from '@fibrae/semi-ui-svelte';
const items = [{ alt: 'Lisa LeBlanc', color: 'red' as const }, { alt: 'Caroline Xiao' }, { alt: 'Rafal Matin', color: 'amber' as const }, { alt: 'Zank Lance', style: 'color: #f56a00; background-color: #fde3cf' }, { alt: 'Youself Zhang', style: 'background-color: #87d068' }];
const initials = (alt = '') =>
alt
.split(' ')
.map((word) => word[0])
.join('');
</script>
<div>
<AvatarGroup {items} maxCount={3}>
{#snippet item({ item })}
{initials(item.alt)}
{/snippet}
</AvatarGroup>
</div>可以通过 more snippet 自定义 more 标签,参数为 { restNumber, restAvatars }。restAvatars 是被隐藏的完整数据项(items 中的对应项);头像的文字内容由 item snippet 提供,不在数据项里。
代码
<script lang="ts">
import { Avatar, AvatarGroup, Popover } from '@fibrae/semi-ui-svelte';
const items = [{ alt: 'Lisa LeBlanc', color: 'red' as const }, { alt: 'Caroline Xiao' }, { alt: 'Rafal Matin', color: 'amber' as const }, { alt: 'Zank Lance', style: 'color: #f56a00; background-color: #fde3cf' }, { alt: 'Youself Zhang', style: 'background-color: #87d068' }];
const initials = (alt = '') =>
alt
.split(' ')
.map((word) => word[0])
.join('');
</script>
<AvatarGroup {items} maxCount={3}>
{#snippet item({ item })}
{initials(item.alt)}
{/snippet}
{#snippet more({ restNumber, restAvatars })}
<Popover autoAdjustOverflow={false} position="bottomRight" style="padding: 12px 8px; padding-bottom: 0">
<!-- the trigger props go on the avatar itself: a wrapper span would put a non-listitem tab stop inside the group's list -->
{#snippet child({ props })}
<Avatar {...props}>{`+${restNumber}`}</Avatar>
{/snippet}
{#snippet content()}
<div>
{#each restAvatars as avatar (avatar.alt)}
<div style="padding-bottom: 12px">
<Avatar {...avatar} size="extra-small">{initials(avatar.alt)}</Avatar>
<span style="margin-left: 8px; font-size: 14px">这是段文字描述</span>
</div>
{/each}
</div>
{/snippet}
</Popover>
{/snippet}
</AvatarGroup>可以通过 overlapFrom 控制头像组的覆盖方式。可选值有 start 和 end,分别表示左边覆盖右边和右边覆盖左边。默认值为 start。
代码
<script lang="ts">
import { AvatarGroup } from '@fibrae/semi-ui-svelte';
const directions = ['start', 'end'] as const;
const items = [{ alt: 'Lisa LeBlanc', color: 'red' as const }, { alt: 'Caroline Xiao' }, { alt: 'Rafal Matin', color: 'amber' as const }, { alt: 'Zank Lance', style: 'color: #f56a00; background-color: #fde3cf' }, { alt: 'Youself Zhang', style: 'background-color: #87d068' }];
const initials = (alt = '') =>
alt
.split(' ')
.map((word) => word[0])
.join('');
</script>
<div>
{#each directions as direction (direction)}
<div>
<AvatarGroup {items} overlapFrom={direction}>
{#snippet item({ item })}
{initials(item.alt)}
{/snippet}
</AvatarGroup>
</div>
{/each}
</div>API 参考
Avatar
Props
| 属性 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| alt | 头像图片或文字的替代文本。 | string | - |
| border | 显示额外边框,可配置颜色和动画。 | boolean | { color?: string; motion?: boolean } | - |
| bottomSlot | 底部标记的形状、背景色、文字颜色、类名和样式字符串;内容使用 bottomSlotText snippet,render 为 snippet 时完全自定义标记。 | AvatarBottomSlot | - |
| bottomSlotText | 预设底部标记中的文字或节点的 snippet。 | Snippet | - |
| children | 头像的文字或自定义内容的 snippet。 | Snippet | - |
| color | 头像的预设背景颜色。 | AvatarColor | "grey" |
| contentMotion | 启用头像内容区域的动画。 | boolean | - |
| gap | 字符内容与头像左右两侧的间距,单位为像素。 | number | 3 |
| hoverMask | 悬停时显示的覆盖层的 snippet,自行设置样式。 | Snippet | - |
| imgAttr | 传给内部 img 元素的原生属性。 | HTMLImgAttributes | - |
| onError | 图片加载失败时调用,返回 false 阻止默认回退。 | Type() => boolean | void | - |
| onMouseEnter | 指针进入头像时调用。 | Type(event: MouseEvent) => void | - |
| onMouseLeave | 指针离开头像时调用。 | Type(event: MouseEvent) => void | - |
| shape | 头像形状,可选 circle 或 square。 | AvatarShape | - |
| size | 头像尺寸,支持预设名称或合法 CSS 尺寸。 | string | - |
| src | 图片头像的资源地址。 | string | - |
| srcSet | 图片头像的响应式资源集合。 | string | - |
| topSlot | 顶部标记的渐变色、文字颜色、类名和样式字符串;内容使用 topSlotText snippet,render 为 snippet 时完全自定义标记。 | AvatarTopSlot | - |
| topSlotText | 预设顶部标记中的文字或节点的 snippet。 | Snippet | - |
class、style、id 与其他原生属性落在头像 span 上;使用 border、topSlot 或 bottomSlot 时,style 落在外层包裹元素上,class 与其他原生属性仍落在头像 span 上。可点击头像的 tabindex、aria-* 落在内部唯一的焦点元素上。
AvatarGroup
Props
| 属性 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| item | 每个头像内容的 snippet,参数为 { item, index },优先于数据项自带的 children。 | TypeSnippet<[AvatarGroupItemContext]> | - |
| items | 组内头像的数据,每项是 Avatar 的属性;组的 size、shape 覆盖数据项自己的。 | AvatarGroupItem[] | [] |
| maxCount | 显示的最大头像数,超出后显示 +N。 | number | - |
| more | 自定义溢出标签的 snippet,参数为 { restNumber, restAvatars }:剩余数量与被隐藏的数据项。 | TypeSnippet<[AvatarGroupMoreContext]> | - |
| overlapFrom | 头像重叠方向,可选 start 或 end。 | AvatarGroupOverlapFrom | "start" |
| shape | 组内头像的形状。 | AvatarGroupShape | "circle" |
| size | 组内头像的尺寸。 | string | "medium" |
class、style 与原生属性(包括 aria-*)落在 AvatarGroup 根元素上,不会传给组内的头像。
Accessibility
- Avatar 一般不用于操作,不需要被获取焦点。但当 Avatar 可以被点击操作时(如:Semi 官网上方的头像)需要被聚焦,并响应键盘
Enter和空格事件。 - 可点击且有图片或文字的 Avatar 只有一个 Tab 停靠点,即图片或文字标签;它收到的焦点顺序与
aria-*属性(包括 Tooltip 注入的)都落在这个元素上。 - 当 Avatar 与其他组件结合使用时,需要同时检查该组件的可访问性指南。
- Avatar的
alt属性可以被屏幕阅读器读取,使用头像组件时,请使用alt属性解释头像的内容。
<script lang="ts">
import { Avatar } from '@fibrae/semi-ui-svelte';
const src = '/assets/placeholder/avatar-a.svg';
</script>
<Avatar alt="一只可爱的猫咪" {src} />
<Avatar alt="姜鹏志" {src} />
替代文本描述头像内容,避免空字符串,也不必重复说明「图片」。可点击时用 onclick 声明操作,组件自动提供 Tab 停靠点,并将 Enter 和空格转为点击。
设计变量
| Sass 变量 | 值 | 用法 |
|---|---|---|
| $animation_duration-additionalBorder | 800ms | 边框动画持续时间 |
| $animation_duration-content | 1000ms | 内容动画持续时间 |
| $animation_opacity-additionalBorder-start | 1 | 边框动画起始透明度 |
| $animation_opacity-additionalBorder-end | 0 | 边框动画结束透明度 |
| $animation_scale-additionalBorder-start | 1 | 边框动画起始缩放比例 |
| $animation_scale-additionalBorder-end | 1.15 | 边框动画结束缩放比例 |
| $animation_scale-content-start | 1 | 边框动画起始缩放比例 |
| $animation_scale-content-middle | 0.9 | 边框动画中间态缩放比例 |
| $z-avatar-default | 100 | 头像 z-index |
| $color-avatar_default-border-default | var(--semi-color-bg-1) | 头像描边颜色 |
| $color-avatar_more_default-bg-default | var(--semi-grey-5) | 「更多」描边颜色 |
| $color-avatar-outline-focus | $color-focus-ring | 头像聚焦轮廓颜色 |
| $width-avatar_extra_extra_small | 20px | 头像尺寸 - 极小 |
| $font-avatar_extra_extra_small-size | 10px | 文本字号 - 极小 |
| $font-avatar_extra_extra_small-lineHeight | 15px | 文本行高 - 极小 |
| $width-avatar_extra_small | 24px | 头像尺寸 - 超小 |
| $font-avatar_extra_small-size | 10px | 文本字号 - 超小 |
| $font-avatar_extra_small-lineHeight | 15px | 文本行高 - 超小 |
| $width-avatar_small | 32px | 头像尺寸 - 小 |
| $width-avatar_default | 40px | 头像尺寸 - 默认 |
| $width-avatar_medium | 48px | 头像尺寸 - 中 |
| $width-avatar_large | 72px | 头像尺寸 - 大 |
| $width-avatar_extra_large | 128px | 头像尺寸 - 超大 |
| $font-avatar_extra_large-size | 64px | 文本字号 - 超大 |
| $font-avatar_extra_large-lineHeight | 77px | 文本行高 - 超大 |
| $radius-avatar | var(--semi-border-radius-circle) | 头像圆角 |
| $width-avatar_extra_large-border | 3px | 头像组头像描边尺寸 - 超大 |
| $spacing-avatar_extra_large-marginLeft | -32px | 头像组头像左侧外边距 - 超大 |
| $width-avatar_large-border | 3px | 头像组头像描边尺寸 - 大 |
| $spacing-avatar_large-marginLeft | -18px | 头像左侧外边距 - 大 |
| $width-avatar_medium-border | 2px | 头像组头像描边尺寸 - 中 |
| $spacing-avatar_medium-marginLeft | -12px | 头像左侧外边距 - 中 |
| $width-avatar_default-border | 2px | 头像组头像描边尺寸 - 默认 |
| $spacing-avatar_default-marginLeft | -12px | 头像左侧外边距 - 默认 |
| $width-avatar_small-border | 2px | 头像组头像描边尺寸 - 小 |
| $spacing-avatar_small-marginLeft | -12px | 头像左侧外边距 - 小 |
| $width-avatar_extra_small-border | 1px | 头像组头像描边尺寸 - 超小 |
| $spacing-avatar_extra_small-marginLeft | -10px | 头像左侧外边距 - 超小 |
| $width-avatar_extra_extra_small-border | 1px | 头像组头像描边尺寸 - 极小 |
| $spacing-avatar_extra_extra_small-marginLeft | -4px | 头像左侧外边距 - 极小 |
| $width-avatar-outline | $width-focus-ring | 头像聚焦轮廓宽度 |
| $width-avatar_additional-border | 1.5px | 额外描边尺寸 |
| $color-avatar_additional-border | var(--semi-color-primary) | 额外描边颜色 |
| $spacing-avatar_additional-borderGap | 2px | 额外描边与内侧间距 |
| $width-avatar-bottom_slot_circle_extra_small | 12px | extra small 头像底部 slot 圆形半径 |
| $width-avatar-bottom_slot_circle_small | 12px | small 头像底部 slot 圆形半径 |
| $width-avatar-bottom_slot_circle_default | 16px | default 头像底部 slot 圆形半径 |
| $width-avatar-bottom_slot_circle_medium | 18px | medium 头像底部 slot 圆形半径 |
| $width-avatar-bottom_slot_circle_large | 28px | large 头像底部 slot 圆形半径 |
| $width-avatar-bottom_slot_circle_extra_large | 28px | extra large 头像底部 slot 圆形半径 |
| $color-avatar-bottom_slot_bg | var(--semi-color-primary) | 头像底部 slot 背景色 |
| $radius-avatar-bottom_slot_square | 4px | 底部 slot square 圆角 |
| $font-avatar_bottom_slot-extra_small-fontSize | 5px | extra small 底部 slot 文字大小 |
| $font-avatar_bottom_slot-small-fontSize | 5px | small 底部 slot 文字大小 |
| $font-avatar_bottom_slot-default-fontSize | 12px | default 底部 slot 文字大小 |
| $font-avatar_bottom_slot-medium-fontSize | 12px | medium 底部 slot 文字大小 |
| $font-avatar_bottom_slot-large-fontSize | 12px | large 底部 slot 文字大小 |
| $font-avatar_bottom_slot-extra_large-fontSize | 14px | extra large 底部 slot 文字大小 |
| $spacing-avatar-bottom_slot_square-paddingX | 4px | 底部 slot square 形状左边距 |
| $spacing-avatar-bottom_slot_square-paddingY | 1px | 底部 slot square 形状右边距 |
| $font-avatar_top_slot-small-fontSize | 5px | small 顶部 slot 文字大小 |
| $font-avatar_top_slot-default-fontSize | 6px | default 顶部 slot 文字大小 |
| $font-avatar_top_slot-medium-fontSize | 8px | medium 顶部 slot 文字大小 |
| $font-avatar_top_slot-large-fontSize | 14px | large 顶部 slot 文字大小 |
| $font-avatar_top_slot-extra_large-fontSize | 16px | extra large 顶部 slot 文字大小 |
| $spacing-avatar-top_slot_small-content-marginTop | 0px | small 顶部文字 marginTop |
| $spacing-avatar-top_slot_default-content-marginTop | -2px | default 顶部文字 marginTop |
| $spacing-avatar-top_slot_medium-content-marginTop | 0px | medium 顶部文字 marginTop |
| $spacing-avatar-top_slot_large-content-marginTop | 0px | large 顶部文字 marginTop |
| $spacing-avatar-top_slot_extra_large-content-marginTop | 0px | extra large 顶部文字 marginTop |
| $color-avatar-bottom_slot_square-border | var(--semi-color-bg-0) | 底部 square 边框颜色 |
| $width-avatar-bottom_slot_square_extra_small-border | 2px | small 头像底部 square 边框宽度 |
| $width-avatar-bottom_slot_square_small-border | 2px | small 头像底部 square 边框宽度 |
| $width-avatar-bottom_slot_square_default-border | 2px | default 头像底部 square 边框宽度 |
| $width-avatar-bottom_slot_square_medium-border | 2px | medium 头像底部 square 边框宽度 |
| $width-avatar-bottom_slot_square_large-border | 2px | large 头像底部 square 边框宽度 |
| $width-avatar-bottom_slot_square_extra_large-border | 2px | extra large 头像底部 square 边框宽度 |
| $color-avatar-top_slot_text | var(--semi-color-bg-0) | 顶部 Slot 文字颜色 |
| $spacing-avatar-top_slot_small-shift | -28px | small 顶部 slot 偏移量, 和 scale 一起控制 slot 的位置 |
| $spacing-avatar-top_slot_default-shift | -32px | default 顶部 slot 偏移量, 和 scale 一起控制 slot 的位置 |
| $spacing-avatar-top_slot_medium-shift | -30px | medium 顶部 slot 偏移量, 和 scale 一起控制 slot 的位置 |
| $spacing-avatar-top_slot_large-shift | -30px | large 顶部 slot 偏移量, 和 scale 一起控制 slot 的位置 |
| $spacing-avatar-top_slot_extra_large-shift | -32px | extra large 顶部 slot 偏移量, 和 scale 一起控制 slot 的位置 |
| $spacing-avatar-top_slot_small-scale | 0.4 | small 顶部 slot 缩放比例 |
| $spacing-avatar-top_slot_default-scale | 0.7 | default 顶部 slot 缩放比例 |
| $spacing-avatar-top_slot_medium-scale | 0.8 | medium 顶部 slot 缩放比例 |
| $spacing-avatar-top_slot_large-scale | 1.1 | large 顶部 slot 缩放比例 |
| $spacing-avatar-top_slot_extra_large-scale | 1.4 | large 顶部 slot 缩放比例 |
| $radius-avatar_extra_extra_small | 3px | 极小尺寸头像的圆角 |
| $radius-avatar_extra_small | 3px | 超小尺寸头像的圆角 |
| $radius-avatar_small | 3px | 小尺寸头像的圆角 |
| $radius-avatar_default | 3px | 默认尺寸头像的圆角 |
| $radius-avatar_medium | 3px | 中尺寸头像的圆角 |
| $radius-avatar_large | 6px | 大尺寸头像的圆角 |
| $radius-avatar_extra_large | 12px | 超大尺寸头像的圆角 |