首页
/ Ant Design 栅格卡片布局实战:用 Row/Col 在概览页中编排 Card

Ant Design 栅格卡片布局实战:用 Row/Col 在概览页中编排 Card

2026-09-06 18:06:39作者:虞亚竹Luna

系统概览页(Overview / Dashboard)最常见的形态,就是"标题 + 一组并排的信息卡片"。Ant Design 的官方示例明确给出了这一范式:Card 常与栅格(Row/Col)列布局配合使用(详见 components/card/demo/in-column.md)。本文以该示例为核心,结合仓库中 Card、Row、Col 的源码与测试快照,讲清"卡片放进栅格"的标准写法、间距(gutter)的底层实现、无边框变体(variant)的作用,以及如何改造成响应式多列布局。读完你将能直接在概览页中落地一套可对齐、可换行、可适配屏幕的卡片栅格。

一、示例速览:原文档说明了什么

官方为 Card 提供了名为 栅格卡片(Card in column) 的演示,文档描述非常聚焦:

  • 中文说明:在系统概览页面常常和栅格进行配合。
  • 英文说明:Cards usually cooperate with grid column layout in overview page.

该演示以 background="grey" 方式注册在组件文档中(见 components/card/index.en-US.mdcomponents/card/index.zh-CN.md),对应实现文件为 components/card/demo/in-column.tsx。它的业务价值很清晰:概览页需要把多条并列信息用同一套视觉框架展示,栅格负责"分列 + 间距 + 响应式",Card 负责"每条信息的内容容器"。

二、完整示例代码

演示代码本身非常精简,全文如下(源自 components/card/demo/in-column.tsx):

import React from 'react';
import { Card, Col, Row } from 'antd';

const App: React.FC = () => (
  <Row gutter={16}>
    <Col span={8}>
      <Card title="Card title" variant="borderless">
        Card content
      </Card>
    </Col>
    <Col span={8}>
      <Card title="Card title" variant="borderless">
        Card content
      </Card>
    </Col>
    <Col span={8}>
      <Card title="Card title" variant="borderless">
        Card content
      </Card>
    </Col>
  </Row>
);

export default App;

这段代码一共只用了三个 API,却覆盖了栅格卡片布局的全部要点:

API 用法 作用
Row gutter={16} 声明列与列之间的水平间距(单位 px),并向下传递给所有 Col
Col span={8} 三列各占 8/24,合计 24,恰好一行排满,宽度一致
Card title + variant="borderless" 提供统一的内容容器;borderless 关闭描边,风格更轻盈

三张卡片的 title 与 body 结构完全一致,配上等宽的三列,视觉上就形成了规整的"概览卡片组"。这正是原文档所说的"在系统概览页面常常和栅格进行配合"的最小可运行实现。

三、原理拆解:gutter 间距是怎么"恰好"落在列中间的

把卡片放进栅格后,最值得理解的细节是 Row gutter={16} 带来的间距机制。从 components/grid/row.tsx 的源码可以看到它做了两件事:

  1. Row 容器上设置负向水平外边距rowStyle.marginInline = gutter / -2),并支持通过 rowGap 表达纵向间距 gutterV
  2. 通过 RowContext 把计算后的 gutter 传给子级 Col

而在 components/grid/col.tsx 中,Col 会从 RowContext 取出 gutter,然后给自己设置等量的一半内边距mergedStyle.paddingInline = gutter / 2)。

把两者拼起来看就明白了:gutter={16} 时,Row 左右各让出 -8px 的外边距,同时每个 Col 左右各吃到 8px 的内边距,于是列与列之间净间距恒为 16px,而整行两端的 8px 又被 Row 的负外边距吸收,不会在页面边缘留下多余空白。这段渲染结果被固化在测试快照中,见 components/card/tests/snapshots/demo.test.ts.snap

<div class="ant-row" style="margin-inline: -8px">
  <div class="ant-col ant-col-8" style="padding-inline: 8px">
    <div class="ant-card">
      <div class="ant-card-head">
        <div class="ant-card-head-wrapper">
          <div class="ant-card-head-title">Card title</div>
        </div>
      </div>
      <div class="ant-card-body">Card content</div>
    </div>
  </div>
  <!-- 另外两列结构相同 -->
</div>

这份快照还顺带证明了 Card 渲染出的语义结构:.ant-card 下先渲染 .ant-card-head(内含 .ant-card-head-title),再渲染 .ant-card-body。也就是说,title="Card title" 会被渲染进卡片头部,而不是 body。

四、variant="borderless":无边框卡片背后的参数演进

示例特意给每张卡都传了 variant="borderless"。翻阅 components/card/index.en-US.md 的 API 表可以确认其取值:

  • variant'outlined' | 'borderless',默认 'outlined',自 5.24.0 引入;
  • 旧属性 bordered 已被标记为废弃(deprecated),官方建议改用 variant 替代;同样被替代的还有 headStylestyles.headerbodyStylestyles.body

components/card/Card.tsx 中,bordered 会通过 useVariant('card', customVariant, bordered)(该 hook 位于 components/form/hooks/useVariants.ts)统一换算成最终的 variant,随后:

classString = clsx(prefixCls, ..., {
  [`${prefixCls}-bordered`]: variant !== 'borderless',
  ...
});

可见"是否有边框"最终体现为是否追加 .ant-card-bordered 类。因此在概览页中,当你希望整组卡片去边框、只靠内容与间距组织视觉层级时,统一使用 variant="borderless" 即可与栅格背景(示例中的灰色 background="grey" 演示底)自然融为一体。

五、实操改造:从三列示例到响应式概览页

理解示例后,可以按需扩展,核心仍不离开 Row/Col 的栅格语义:

  1. 调整列数:24 栅格体系下,两列用 span={12},四列用 span={6},三列示例则维持 span={8}。只要各列 span 之和不超过 24,即可保证一行排布不换行。

  2. 响应式断点Col 支持以断点命名的属性(xssmmdlgxlxxl 等,定义见 components/grid/col.tsxColSize 与响应式属性声明)。例如宽屏三列、窄屏单列可写为:

    <Row gutter={[16, 16]}>
      <Col xs={24} md={12} xl={8}>
        <Card title="指标一">Card content</Card>
      </Col>
      {/* 其余卡片同理 */}
    </Row>
    

    注意 gutter 也支持数组 [horizontal, vertical],写成 [16, 16] 即可让行与行之间也有纵向间距,这是多行卡片网格的常用写法。

  3. 列内内容的组织:把每张卡放进独立 Col 后,Card 作为块级元素会占满所在列的宽度,列内标题与 body 天然对齐。需要更丰富内容时,仍可在 Card 内部使用 actionscovertabListloading 等能力(这些 prop 的声明见 components/card/Card.tsx 中的 CardProps),外围栅格结构无需改变。

六、证据与延伸阅读

本文涉及的关键事实均可在仓库中复现核对:

若需要"卡片内部再分块"的相邻方案,可对比参考同目录下的 grid-card.mdgrid-card.tsx,它演示的是在一张 Card 内部通过 Card.Grid 分割区域的用法——前者是"多卡片进栅格",后者是"单卡片内做栅格",两者结合即可覆盖概览页绝大多数信息呈现需求。

登录后查看全文
热门项目推荐
相关项目推荐