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

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

代码
import { Card, Rating } from '@fibrous/semi-ui-solid';
const coverSrc = '/assets/root-web-sites/card-cover-docs-demo.jpeg';
export default function CardDemo() {
return (
<Card style={{ 'max-width': '300px' }} actions={[<Rating size="small" defaultValue={4} />]} headerLine={false} cover={<img alt="example" src={coverSrc} />}>
<Card.Meta title="Semi Doc" description="全面、易用、优质" />
</Card>
);
}卡片组
CardGroup 中的卡片将呈现为等间距排列,利用 spacing 属性可以设置卡片间距大小。
代码
import { For, createSignal } from 'solid-js';
import { Card, CardGroup, Slider, Typography } from '@fibrous/semi-ui-solid';
const cardIndexes = Array.from({ length: 8 }, (_, index) => index);
export default function CardDemo() {
const [spacing, setSpacing] = createSignal(12);
return (
<>
<Typography.Text id="card-group-spacing">滑动调节 Card 间距</Typography.Text>
<Slider
aria-labelledby="card-group-spacing"
defaultValue={12}
max={40}
min={10}
style={{ width: '360px' }}
onChange={(value) => {
if (typeof value === 'number') setSpacing(value);
}}
/>
<br />
<CardGroup spacing={spacing()}>
<For each={cardIndexes}>
{() => (
<Card shadows="hover" title="Card title" headerLine={false} style={{ width: '260px' }} headerExtraContent={<Typography.Text link>More</Typography.Text>}>
<Typography.Text>Card content</Typography.Text>
</Card>
)}
</For>
</CardGroup>
</>
);
}网格型卡片组
使用 CardGroup 的 type 属性,可以将卡片组设置为网格型。
代码
import { For } from 'solid-js';
import { Card, CardGroup, Typography } from '@fibrous/semi-ui-solid';
const cardIndexes = Array.from({ length: 7 }, (_, index) => index);
export default function CardDemo() {
return (
<CardGroup type="grid">
<For each={cardIndexes}>
{() => (
<Card shadows="hover" title="Card title" headerLine={false} style={{ width: '260px' }} headerExtraContent={<Typography.Text link>More</Typography.Text>}>
<Typography.Text>Card content</Typography.Text>
</Card>
)}
</For>
</CardGroup>
);
}API 参考
Card
Props
| 属性 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| actions | 操作区,每个元素作为一个操作,位于内容区底部,操作之间以 12px 的水平间距排列。 | JSX.Element[] | - |
| bodyStyle | 内容区的内联样式,键使用 kebab-case 的 CSS 属性名。 | JSX.CSSProperties | string | - |
| bordered | 是否显示卡片外边框。 | boolean | true |
| cover | 卡片封面,位于标题区之下。 | JSX.Element | - |
| footer | 自定义页脚,位于卡片底部。 | JSX.Element | - |
| footerLine | 页脚区与内容区之间是否有边线。 | boolean | false |
| footerStyle | 页脚区的内联样式,键使用 kebab-case 的 CSS 属性名。 | JSX.CSSProperties | string | - |
| header | 自定义整个标题区,传入后取代 title 与 headerExtraContent。 | JSX.Element | - |
| headerExtraContent | 标题右侧的额外内容。 | JSX.Element | - |
| headerLine | 标题区与内容区之间是否有边线。 | boolean | true |
| headerStyle | 标题区的内联样式,键使用 kebab-case 的 CSS 属性名。 | JSX.CSSProperties | string | - |
| loading | 是否在内容区显示加载占位,开启时根元素的 aria-busy 为 true。 | boolean | false |
| shadows | 显示阴影的时机,可选 hover 或 always;不设置则没有阴影。 | Shadows | - |
| title | 标题。字符串按 6 号标题的样式渲染为 div,超长时省略并显示提示;传入 JSX 元素时原样渲染。 | JSX.Element | - |
class、style、ref 与原生属性和事件(如 id、aria-*、onClick)落在卡片的根元素(div)上。
CardGroup
Props
| 属性 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| align | 子项的交叉轴对齐方式,透传给 Space,可选 start、center、end、baseline,默认 center。 | Align | - |
| spacing | 卡片间距,数值或 [水平间距, 垂直间距];type 为 grid 时不生效。 | number | [number, number] | 16 |
| type | 设为 grid 时呈现为网格型,覆盖 spacing。 | CardGroupType | - |
| vertical | 是否纵向排列,透传给 Space。 | boolean | - |
| wrap | 是否换行,透传给 Space;纵向排列时不生效。 | boolean | true |
class、style、ref 与原生属性和事件同样落在内部 Space 的根元素上。
Card.Meta
Props
| 属性 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| avatar | 头像,位于标题与描述的左侧。 | JSX.Element | - |
| description | 描述内容,位于标题之下。 | JSX.Element | - |
| title | 标题内容。 | JSX.Element | - |
class、style、ref 与原生属性和事件落在根元素(div)上。
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 |