代码演示
如何引入
<script setup lang="ts">
import { Card, CardGroup, CardMeta } from '@fibrous/semi-ui-vue';
</script>
CardMeta 即 Card.Meta,两种写法等价。
基础卡片
基础卡片包含标题、内容等部分。
代码
<script setup lang="ts">
import { Card, TypographyText } from '@fibrous/semi-ui-vue';
</script>
<template>
<Card :style="{ maxWidth: '360px' }" title="Semi Design">
<template #headerExtraContent>
<TypographyText link>更多</TypographyText>
</template>
Semi Design 是由抖音前端团队与 UED 团队共同设计开发并维护的设计系统。设计系统包含设计语言以及一整套可复用的前端组件,帮助设计师与开发者更容易地打造高质量的、用户体验一致的、符合设计规范的 Web 应用。
</Card>
</template>简洁卡片
卡片可以只设置内容区域。
代码
<script setup lang="ts">
import { IconInfoCircle } from '@fibrous/semi-icons-vue';
import { Avatar, Card, CardMeta, Popover } from '@fibrous/semi-ui-vue';
const bodyStyle = { display: 'flex', alignItems: 'center', justifyContent: 'space-between' };
</script>
<template>
<Card :style="{ maxWidth: '360px' }"> Semi Design 是由抖音前端团队与 UED 团队共同设计开发并维护的设计系统。 </Card>
<br />
<Card :bodyStyle="bodyStyle" :style="{ maxWidth: '360px' }">
<CardMeta title="Semi Doc">
<template #avatar>
<Avatar alt="Card meta img" size="default" src="/assets/placeholder/logo.svg" />
</template>
</CardMeta>
<Popover position="top" showArrow>
<template #content>
<article :style="{ padding: '6px' }">这是一个 Card</article>
</template>
<IconInfoCircle aria-label="信息" :style="{ color: 'var(--semi-color-primary)' }" />
</Popover>
</Card>
</template>封面
可以使用 #cover 插槽设置封面。

代码
<script setup lang="ts">
import { Card, CardMeta } from '@fibrous/semi-ui-vue';
</script>
<template>
<Card :style="{ maxWidth: '300px' }">
<template #cover>
<img alt="example" src="/assets/root-web-sites/card-cover-docs-demo2.jpeg" />
</template>
<CardMeta title="卡片封面" />
</Card>
</template>边线和外边框
可以使用 bordered 设置卡片是否有外边框,默认为 true 。同时,也可以使用 headerLine 设置内容区和标题区是否有边线, footerLine 设置内容区和页尾区是否有边线。
代码
<script setup lang="ts">
import { Card } from '@fibrous/semi-ui-vue';
</script>
<template>
<div :style="{ display: 'inline-block', padding: '20px', backgroundColor: 'var(--semi-color-fill-0)' }">
<Card :bordered="false" headerLine :style="{ maxWidth: '360px' }" title="Semi Design"> Semi Design 是由抖音前端团队与 UED 团队共同设计开发并维护的设计系统。设计系统包含设计语言以及一整套可复用的前端组件,帮助设计师与开发者更容易地打造高质量的、用户体验一致的、符合设计规范的 Web 应用。 </Card>
</div>
</template>阴影
可以使用 shadows 设置显示阴影的时机,可选值为: hover(hover 时显示阴影)、always(始终显示阴影),如果不设置该属性则没有阴影。
代码
<script setup lang="ts">
import { IconInfoCircle } from '@fibrous/semi-icons-vue';
import { Avatar, Card, CardMeta, Popover } from '@fibrous/semi-ui-vue';
const bodyStyle = { display: 'flex', alignItems: 'center', justifyContent: 'space-between' };
</script>
<template>
<div>
<Card :bodyStyle="bodyStyle" shadows="hover" :style="{ maxWidth: '360px' }">
<CardMeta title="Semi Doc">
<template #avatar>
<Avatar alt="Card meta img" size="default" src="/assets/placeholder/logo.svg" />
</template>
</CardMeta>
<Popover position="top" showArrow>
<template #content>
<article :style="{ padding: '6px' }">这是一个 Card</article>
</template>
<IconInfoCircle aria-label="信息" :style="{ color: 'var(--semi-color-primary)' }" />
</Popover>
</Card>
<br />
<Card :bodyStyle="bodyStyle" shadows="always" :style="{ maxWidth: '360px' }">
<CardMeta title="Semi Doc">
<template #avatar>
<Avatar alt="Card meta img" size="default" src="/assets/placeholder/logo.svg" />
</template>
</CardMeta>
<Popover position="top" showArrow>
<template #content>
<article :style="{ padding: '6px' }">这是一个 Card</article>
</template>
<IconInfoCircle aria-label="信息" :style="{ color: 'var(--semi-color-primary)' }" />
</Popover>
</Card>
</div>
</template>更灵活的内容展示
可以利用 CardMeta 支持更灵活的内容,通过 #title(或 title 属性)、#avatar、#description 插槽设置。
代码
<script setup lang="ts">
import { Avatar, Button, Card, CardMeta, Space, TypographyText } from '@fibrous/semi-ui-vue';
</script>
<template>
<Card :footerStyle="{ display: 'flex', justifyContent: 'flex-end' }" footerLine :style="{ maxWidth: '340px' }">
<template #title>
<CardMeta title="Semi Doc">
<template #description>全面、易用、优质</template>
<template #avatar>
<Avatar alt="Card meta img" size="default" src="/assets/placeholder/logo.svg" />
</template>
</CardMeta>
</template>
<template #headerExtraContent>
<TypographyText link>More</TypographyText>
</template>
<template #cover>
<img alt="example" src="/assets/root-web-sites/card-cover-docs-demo.jpeg" />
</template>
<template #footer>
<Space>
<Button theme="borderless" type="primary">精选案例</Button>
<Button theme="solid" type="primary">开始使用</Button>
</Space>
</template>
Semi Design 是由抖音前端团队与 UED 团队共同设计开发并维护的设计系统。
</Card>
</template>内部卡片
卡片内部可以嵌套其他卡片。
代码
<script setup lang="ts">
import { Card, TypographyText } from '@fibrous/semi-ui-vue';
</script>
<template>
<Card title="Card title">
<Card :style="{ marginBottom: '20px' }" title="Inner Card title">
<template #headerExtraContent>
<TypographyText link>More</TypographyText>
</template>
Inner Card content
</Card>
<Card title="Inner Card title">
<template #headerExtraContent>
<TypographyText link>More</TypographyText>
</template>
Inner Card content
</Card>
</Card>
</template>栅格卡片
在系统概览页面常常和栅格进行配合。
代码
<script setup lang="ts">
import { Card, Col, Row } from '@fibrous/semi-ui-vue';
const rows = [
[8, 8, 8],
[16, 8],
];
</script>
<template>
<div :style="{ backgroundColor: 'var(--semi-color-fill-0)', padding: '20px' }">
<Row v-for="(spans, rowIndex) in rows" :key="rowIndex" :gutter="[16, 16]">
<Col v-for="(span, colIndex) in spans" :key="colIndex" :span="span">
<Card :bordered="false" title="Card Title">Card Content</Card>
</Col>
</Row>
</div>
</template>内置预加载
可以使用 Card 的 loading 属性来设置卡片内容区是否显示占位元素,当它为 true 时将显示占位元素,反之则不显示。
代码
<script setup lang="ts">
import { ref } from 'vue';
import { Card, CardMeta, Switch } from '@fibrous/semi-ui-vue';
const loading = ref(true);
</script>
<template>
<Switch aria-label="显示内容" @change="(v) => (loading = !v)" />
<br />
<br />
<Card :loading="loading" :style="{ maxWidth: '360px' }">
<CardMeta title="Semi Doc">
<template #description>全面、易用、优质</template>
</CardMeta>
</Card>
</template>更丰富的预加载效果
Card 自带的 loading 属性只能设置内容区的预加载效果,如果你想要设置其他部分的预加载,或者自定义更丰富的预加载效果,你可以结合 Skeleton 组件来实现。
代码
<script setup lang="ts">
import { ref } from 'vue';
import { Avatar, Card, CardMeta, Skeleton, SkeletonAvatar, SkeletonImage, SkeletonParagraph, SkeletonTitle, Switch, TypographyText, TypographyTitle } from '@fibrous/semi-ui-vue';
const loading = ref(true);
</script>
<template>
<Switch aria-label="显示内容" @change="(v) => (loading = !v)" />
<br />
<br />
<Card :style="{ maxWidth: '300px' }">
<template #title>
<CardMeta>
<template #title>
<Skeleton :loading="loading" :style="{ width: '80px' }">
<template #placeholder>
<SkeletonTitle />
</template>
<TypographyTitle :heading="5">Semi Doc</TypographyTitle>
</Skeleton>
</template>
<template #description>
<Skeleton :loading="loading" :style="{ width: '150px', marginTop: '12px' }">
<template #placeholder>
<SkeletonParagraph :rows="1" />
</template>
<TypographyText>全面、易用、优质</TypographyText>
</Skeleton>
</template>
<template #avatar>
<Skeleton :loading="loading">
<template #placeholder>
<SkeletonAvatar />
</template>
<Avatar alt="Card meta img" size="default" src="/assets/placeholder/logo.svg" />
</Skeleton>
</template>
</CardMeta>
</template>
<template #headerExtraContent>
<Skeleton :loading="loading" :style="{ width: '50px' }">
<template #placeholder>
<SkeletonParagraph :rows="1" />
</template>
<TypographyText link>More</TypographyText>
</Skeleton>
</template>
<template #cover>
<Skeleton :loading="loading" :style="{ maxWidth: '100%', height: '220px' }">
<template #placeholder>
<SkeletonImage />
</template>
<img alt="example" src="/assets/root-web-sites/card-cover-docs-demo.jpeg" />
</Skeleton>
</template>
</Card>
</template>带页签的卡片
可以结合 Tabs 组件,实现带页签的卡片。
代码
<script setup lang="ts">
import { Card, TabPane, Tabs } from '@fibrous/semi-ui-vue';
</script>
<template>
<Card title="Card title">
<Tabs :style="{ marginTop: '-20px', marginBottom: '-20px' }" type="line">
<TabPane itemKey="1">
<template #tab>Tab 1</template>
<p>content1</p>
<p>content1</p>
<p>content1</p>
</TabPane>
<TabPane itemKey="2">
<template #tab>Tab 2</template>
<p>content2</p>
<p>content2</p>
<p>content2</p>
</TabPane>
</Tabs>
</Card>
</template>卡片操作区
#actions 插槽中的每个直接子节点是一个操作,元素间将以 12px 的水平间距展示于内容区底部。

代码
<script setup lang="ts">
import { Card, CardMeta, Rating } from '@fibrous/semi-ui-vue';
</script>
<template>
<Card :headerLine="false" :style="{ maxWidth: '300px' }">
<template #cover>
<img alt="example" src="/assets/root-web-sites/card-cover-docs-demo.jpeg" />
</template>
<template #actions>
<Rating :defaultValue="4" size="small" />
</template>
<CardMeta title="Semi Doc">
<template #description>全面、易用、优质</template>
</CardMeta>
</Card>
</template>卡片组
CardGroup 中的卡片将呈现为等间距排列,利用 spacing 属性可以设置卡片间距大小。
代码
<script setup lang="ts">
import { ref } from 'vue';
import { Card, CardGroup, Slider, TypographyText } from '@fibrous/semi-ui-vue';
const spacing = ref(12);
const onSpacingChange = (value: number | number[]) => {
if (typeof value === 'number') spacing.value = value;
};
</script>
<template>
<TypographyText id="card-group-spacing">滑动调节 Card 间距</TypographyText>
<Slider aria-labelledby="card-group-spacing" :defaultValue="12" :max="40" :min="10" :style="{ width: '360px' }" @change="onSpacingChange" />
<br />
<CardGroup :spacing="spacing">
<Card v-for="idx in 8" :key="idx" :headerLine="false" shadows="hover" :style="{ width: '260px' }" title="Card title">
<template #headerExtraContent>
<TypographyText link>More</TypographyText>
</template>
<TypographyText>Card content</TypographyText>
</Card>
</CardGroup>
</template>网格型卡片组
使用 CardGroup 的 type 属性,可以将卡片组设置为网格型。
代码
<script setup lang="ts">
import { Card, CardGroup, TypographyText } from '@fibrous/semi-ui-vue';
</script>
<template>
<CardGroup type="grid">
<Card v-for="idx in 7" :key="idx" :headerLine="false" shadows="hover" :style="{ width: '260px' }" title="Card title">
<template #headerExtraContent>
<TypographyText link>More</TypographyText>
</template>
<TypographyText>Card content</TypographyText>
</Card>
</CardGroup>
</template>API 参考
Card
Props
| 属性 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| bodyStyle | 内容区的内联样式。 | StyleValue | semiGlobalDefault("Card", "bodyStyle") |
| bordered | 是否显示卡片外边框。 | boolean | semiDefault("Card", "bordered", true) |
| footerLine | 页脚区与内容区之间是否有边线。 | boolean | semiDefault("Card", "footerLine", false) |
| footerStyle | 页脚区的内联样式。 | StyleValue | semiGlobalDefault("Card", "footerStyle") |
| headerLine | 标题区与内容区之间是否有边线。 | boolean | semiDefault("Card", "headerLine", true) |
| headerStyle | 标题区的内联样式。 | StyleValue | semiGlobalDefault("Card", "headerStyle") |
| loading | 是否在内容区显示加载占位,开启时根元素的 aria-busy 为 true。 | boolean | semiDefault("Card", "loading", false) |
| shadows | 显示阴影的时机,可选 hover 或 always;不设置则没有阴影。 | Shadows | semiGlobalDefault("Card", "shadows") |
| title | 标题文字,按 6 号标题的样式渲染为 div,超长时省略并显示提示;与 title 插槽等价,两者同时给出时插槽优先。 | string | undefined |
Events
| 事件 | 说明 | 回调参数 |
|---|---|---|
| 无 |
Slots
| 插槽 | 说明 | 作用域参数 |
|---|---|---|
| default | 卡片内容。 | any |
| title | 卡片标题;只有一段文字时按 title 属性的样式渲染,其他内容原样渲染。 | any |
| headerExtraContent | 标题右侧的额外内容。 | any |
| header | 自定义整个标题区,会取代 title 和 headerExtraContent。 | any |
| cover | 卡片封面。 | any |
| actions | 操作区,每个直接子节点作为一个操作,位于内容区底部,间距 12px。 | any |
| footer | 自定义页脚。 | any |
Exposes
| 名称 | 说明 | 类型 |
|---|---|---|
| 无 |
class、style 及其他未声明的属性落在根元素上。
CardGroup
Props
| 属性 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| spacing | 卡片间距,数值或 [水平间距, 垂直间距];type 为 grid 时不生效。 | number | [number, number] | semiDefault("CardGroup", "spacing", 16) |
| type | 设为 grid 时呈现为网格型,覆盖 spacing。 | "grid" | semiGlobalDefault("CardGroup", "type") |
| wrap | 是否换行,传给 Space;纵向排列时不生效。 | boolean | semiDefault("CardGroup", "wrap", true) |
| align | 子项的交叉轴对齐方式,传给 Space,可选 start、center、end、baseline。 | Align | semiGlobalDefault("CardGroup", "align") |
| vertical | 是否纵向排列,传给 Space。 | boolean | semiDefault("CardGroup", "vertical", false) |
Events
| 事件 | 说明 | 回调参数 |
|---|---|---|
| 无 |
Slots
| 插槽 | 说明 | 作用域参数 |
|---|---|---|
| default | 要排列的卡片。 | any |
Exposes
| 名称 | 说明 | 类型 |
|---|---|---|
| 无 |
未声明的属性落在内部 Space 的根元素上。
Card.Meta
Props
| 属性 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| title | 标题文字,等价于 title 插槽,两者同时给出时插槽优先。 | string | undefined |
Events
| 事件 | 说明 | 回调参数 |
|---|---|---|
| 无 |
Slots
| 插槽 | 说明 | 作用域参数 |
|---|---|---|
| avatar | 头像。 | any |
| title | 标题。 | any |
| description | 描述。 | any |
Exposes
| 名称 | 说明 | 类型 |
|---|---|---|
| 无 |
未声明的属性落在根元素上。
Accessibility
- Card 支持传入
aria-label或aria-labelledby来表示该 Card 作用,传入后根元素带role="group"(传入的role优先) - Card loading 时,将开启
aria-busy - 字符串
title按 h6 的样式渲染,但元素是div,不带标题语义,不会打乱页面的标题层级;需要标题语义时,传入自己的标题元素作为title(Vue 中写在#title插槽里) - Card 为容器型组件,卡片内部的任何元素需要遵循各自的可访问性指南
文案规范
- 卡片标题
- 卡片标题应具有信息描述性,聚焦最重要的信息
- 尽量将标题限制在 1 个短语或句段中
- 卡片标题应句子大小写书写
- 不要以标点符号结尾(除了问号)
- 正文
- 可操作的:使用祈使句而不是“你可以”来描述正文,可以更好的告诉用户可以做什么
| ✅ 推荐用法 | ❌ 不推荐用法 |
|---|---|
| Get order progress for details | You can get order progress for details |
- 总是优先说最重要的信息
- 使用 “Need to”而不是”must“
设计变量
| Sass 变量 | 值 | 用法 |
|---|---|---|
| $color-card-bg-default | var(--semi-color-bg-0) | 卡片背景颜色 |
| $color-card-border | var(--semi-color-border) | 卡片描边颜色 |
| $color-card_title-text | var(--semi-color-text-0) | 卡片标题文字颜色 |
| $color-card_description-text | var(--semi-color-text-2) | 卡片描述文字颜色 |
| $color-card_extra-text | var(--semi-color-text-0) | 卡片附加文字颜色 |
| $color-card_body-text | var(--semi-color-text-1) | 卡片正文文字颜色 |
| $font-card_default-fontWeight | $font-weight-regular | 卡片文字字重 - 默认 |
| $font-card_extra-fontWeight | 700 | 卡片文字字重 - 附加文字 |
| $font-card_title-fontWeight | 700 | 卡片文字字重 - 标题 |
| $font-card_default-lineHeight | 20px | 卡片文字行高 - 默认 |
| $font-card_title-lineHeight | 22px | 卡片文字行高 - 标题 |
| $font-card_default-fontSize | $font-size-regular | 卡片文字大小 - 默认 |
| $font-card_extra-fontSize | $font-size-header-6 | 卡片文字大小 - 附加文字 |
| $font-card_title-fontSize | $font-size-header-6 | 卡片文字大小 - 标题 |
| $radius-card | var(--semi-border-radius-medium) | 卡片圆角 |
| $motion-card-transition_duration | 300ms | 卡片悬浮动画时长 |
| $width-card-border | $border-thickness-control | 卡片描边宽度 |
| $shadow-card | var(--semi-shadow-elevated) | 卡片阴影 |
| $spacing-card-padding | $spacing-base-loose | 卡片内边距 |
| $spacing-card-margin | $spacing-base-loose | 卡片外边距 |
| $spacing-card_avatar-marginRight | $spacing-base-tight | 卡片头像右侧外边距 |
| $spacing-cardGroup_card-margin | -1px | 卡片组外边距 |
| $z-card_hover | 1 | 悬浮后卡片 zindex |