Ant Design Grid 基础栅格完全指南:用 Row 与 Col 实现从堆叠到水平排列的 24 栅格系统
【免费下载链接】ant-designAn enterprise-class UI design language and React UI library项目地址: https://gitcode.com/gh_mirrors/ant/ant-design
导读
本文以 Ant Design 官方「基础栅格(Basic Grid)」演示为起点,系统讲解Row与Col这对核心布局组件的使用规则与底层原理:从"从堆叠到水平排列"这一最简单的栅格形态出发,你将掌握 24 等分栅格的划分方式、span占位逻辑、列超宽换行行为,并通过阅读仓库源码理解栅格在 Flex 布局下的真实实现,为后续使用gutter、offset、响应式断点等高级能力打下基础。
从一条演示说起:基础栅格在做什么
官方演示 components/grid/demo/basic.md 的说明非常凝练:
从堆叠到水平排列。使用单一的一组
Row和Col栅格组件,就可以创建一个基本的栅格系统,所有列(Col)必须放在Row内。
这段话包含了两个关键约定:
- 一个基本的栅格系统只需要
Row+Col两组组件,不需要任何额外配置; Col必须放在Row内部,这是栅格组件之间唯一的合法父子关系。
对应的完整示例代码位于 components/grid/demo/basic.tsx:
import React from 'react'; import { Col, Row } from 'antd'; const App: React.FC = () => ( <> <Row> <Col span={24}>col</Col> </Row> <Row> <Col span={12}>col-12</Col> <Col span={12}>col-12</Col> </Row> <Row> <Col span={8}>col-8</Col> <Col span={8}>col-8</Col> <Col span={8}>col-8</Col> </Row> <Row> <Col span={6}>col-6</Col> <Col span={6}>col-6</Col> <Col span={6}>col-6</Col> <Col span={6}>col-6</Col> </Row> </> ); export default App;这段代码只使用了Row与Col的span一个属性,却完整展示了 4 种最常见的栅格排布:整行单列(24)、两等分(12+12)、三等分(8+8+8)、四等分(6+6+6+6)。"从堆叠到水平排列"描述的正是在默认块级流式布局下纵向堆叠的 DOM 元素,被Row的 Flex 容器编排为水平排列的列的过程。
为什么是 24:栅格系统的设计理念
span的取值范围来自 Ant Design 的 24 栅格设计。组件文档 components/grid/index.zh-CN.md 的「设计理念」一节说明:
在多数业务情况下,Ant Design 需要在设计区域内解决大量信息收纳的问题,因此在 12 栅格系统的基础上,我们将整个设计建议区域按照 24 等分的原则进行划分。……建议横向排列的盒子数量最多四个,最少一个。
选择 24 等分的优势在于其因子丰富:24 可被 2、3、4、6、8、12 整除,因此无论是要做两列、三列、四列还是六列布局,都能用整数span精确等分,避免出现小数宽度。示例中的 12/8/6 正是 24 分别除以 2/3/4 的结果。
源码视角:span 在底层如何变成宽度
span并不是魔法,它在编译期被转换成固定的 CSS 类名(如ant-col-8),再由样式系统生成对应的百分比宽度。核心逻辑位于 components/grid/style/index.ts 的genLoopGridColumnsStyle:
const { prefixCls, componentCls, gridColumns } = token; // gridColumns: 24 —— "Row is divided into 24 parts in Grid"(第 186 行)样式生成循环从 24 一直遍历到 0,对每个栅格数i生成:
{ display: 'var(--ant-display)', // 支持被 Form 等组件覆盖 display flex: `0 0 ${(i / gridColumns) * 100}%`, maxWidth: `${(i / gridColumns) * 100}%`, }也就是说,<Col span={8} />最终得到的是flex: 0 0 33.333%+max-width: 33.333%。flex: 0 0 X%表示"不放大、不缩小、基础宽度为 X%",这正是栅格列等宽、稳定的根本保证。同时,genGridColStyle为所有列设置了position: relative; max-width: 100%; min-height: 1(防止空列塌陷)。
值得注意的是span={0}的特例:样式循环里对i === 0单独生成display: none,因此官方文档将span的 0 值描述为"相当于display: none",这也在源码中得到了印证。
Row本身则是一个 Flex 容器。在 components/grid/style/index.ts 的genGridRowStyle中:
[componentCls]: { display: 'flex', flexFlow: 'row wrap', minWidth: 0, ... }flexFlow: 'row wrap'意味着主轴水平、允许换行——这正好解释了文档中的另一条规则:如果一个row中的col总和超过 24,多余的col会作为一个整体另起一行排列。换行能力来自 Flex 的wrap特性,而非任何额外逻辑。
规则细化:谁可以放在 Row 里
组件文档 components/grid/index.zh-CN.md 的「概述」一节总结了基础栅格的完整使用规则:
- 通过
row在水平方向建立一组column(简写 col); - 你的内容应当放置于
col内,并且,只有col可以作为row的直接元素; - 栅格系统中的列是指 1 到 24 的值来表示其跨越的范围。例如,三个等宽的列可以使用
<Col span={8} />来创建; - 如果一个
row中的col总和超过 24,那么多余的col会作为一个整体另起一行排列。
"只有Col可以作为Row的直接元素"是一条值得强调的约定:Row的子元素会被套用 Flex 布局并接收来自RowContext的gutter、wrap信息(见 components/grid/RowContext.ts),只有Col会消费这些上下文,非Col子元素虽然能正常渲染,但无法获得栅格间距等能力。
由基础延伸:Row 与 Col 的属性全景
理解了基础栅格,再看Row/Col的完整 API 就水到渠成。两者类型定义分别位于 components/grid/row.tsx 与 components/grid/col.tsx。
Row 的属性
| 参数 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| align | 垂直对齐方式 | top|middle|bottom|stretch,或按断点的响应式对象 | top |
| gutter | 栅格间隔:像素值、响应式对象{ xs: 8, sm: 16, md: 24 },或数组[水平间距, 垂直间距] | number | object | array | 0 |
| justify | 水平排列方式 | start|end|center|space-around|space-between|space-evenly,或响应式对象 | start |
| wrap | 是否自动换行 | boolean | true |
源码中的取值常量给出了精确范围(components/grid/row.tsx):
const RowAligns = ['top', 'middle', 'bottom', 'stretch'] as const; const RowJustify = [ 'start', 'end', 'center', 'space-around', 'space-between', 'space-evenly', ] as const;Col 的属性
| 参数 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| span | 栅格占位格数,为 0 时相当于display: none | number | - |
| offset | 栅格左侧的间隔格数,间隔内不可以有栅格 | number | 0 |
| order | 栅格顺序 | number | 0 |
| push | 栅格向右移动格数 | number | 0 |
| pull | 栅格向左移动格数 | number | 0 |
| flex | flex 布局属性 | string | number | - |
| xs / sm / md / lg / xl / xxl | 响应式栅格,可为栅格数或包含 span/offset/order 等的对象 | number | object | - |
Col的类型定义(components/grid/col.tsx)还揭示了ColSize的完整形态:
export interface ColSize { flex?: FlexType; span?: ColSpanType; order?: ColSpanType; offset?: ColSpanType; push?: ColSpanType; pull?: ColSpanType; }即响应式断点属性除了接收数字(等价于span),还可以接收一个包含span、offset、push、pull、order、flex的对象。
gutter的间距实现值得一提:Row把水平间距的一半以负 margin 施加在自身(marginLeft = gutter[0] / -2),Col通过RowContext拿到gutter后,把一半以 padding 施加在列上(paddingLeft/Right = gutter[0] / 2),从而在不破坏列宽百分比的前提下实现等宽间隔。相关实现见 components/grid/row.tsx 与 components/grid/col.tsx,官方演示 components/grid/demo/gutter.tsx 展示了数字、响应式对象、数组三种写法:
<Row gutter={16}> {/* 固定水平间距 */} <Row gutter={{ xs: 8, sm: 16, md: 24, lg: 32 }} /> {/* 响应式间距 */} <Row gutter={[16, 24]}> {/* [水平间距, 垂直间距] */}断点与响应式:基础栅格的进阶方向
基础栅格只有span,而实际项目中更常用的是响应式栅格。断点规则同样记录在 components/grid/index.zh-CN.md,并扩展自 Bootstrap 4 的规则:
| 断点 | 屏幕范围 |
|---|---|
| xs | 屏幕 < 576px |
| sm | 屏幕 ≥ 576px |
| md | 屏幕 ≥ 768px |
| lg | 屏幕 ≥ 992px |
| xl | 屏幕 ≥ 1200px |
| xxl | 屏幕 ≥ 1600px |
这些断点对应的媒体查询在 components/_util/responsiveObserver.ts 中基于主题 Token 生成:
const getResponsiveMap = (token: GlobalToken): BreakpointMap => ({ xs: `(max-width: ${token.screenXSMax}px)`, sm: `(min-width: ${token.screenSM}px)`, md: `(min-width: ${token.screenMD}px)`, lg: `(min-width: ${token.screenLG}px)`, xl: `(min-width: ${token.screenXL}px)`, xxl: `(min-width: ${token.screenXXL}px)`, });Row会通过useResponsiveObserver订阅窗口媒体查询变化(components/grid/row.tsx 中subscribe/unsubscribe成对出现),因此gutter、align、justify传入对象形式时能随屏幕实时切换。断点值可通过主题 Tokenscreen[XS|SM|MD|LG|XL|XXL]定制。
测试如何验证这些行为
仓库测试 components/grid/tests/index.test.tsx 用大量用例固化了上文所述的实现事实,可作为深入理解栅格行为的对照:
- 对象与数组形式的
gutter都会在Row上产生负 margin(如gutter={[16, 20]}时marginLeft/marginRight为-8px); - 大屏 mock 下
gutter={[{ xs: 8, ... xl: 40 }, ...]}得到-20px的边距,验证了响应式间距的"按断点取最近命中值"逻辑; align/justify的响应式对象只在命中断点(如xs)时生成ant-row-middle、ant-row-center类,未命中断点(如lg)时不生成;justify="space-evenly"会真实产生justify-content: space-evenly的计算样式;Row卸载时会调用useResponsiveObserver的unsubscribe,避免内存泄漏。
小结与继续探索
至此,你已经完整掌握了 Ant Design 基础栅格的核心:
- 组件骨架:
Row负责水平编排,Col负责占位,所有Col必须放在Row内; - 宽度机制:
span通过 24 等分换算为flex: 0 0 (span/24*100)%的百分比宽度,总和超过 24 时自动换行; - 实现原理:整套系统构建在 Flex 布局之上,
Row是display: flex; flex-flow: row wrap的容器; - 进阶路径:
gutter、offset、push/pull、order与xs~xxl断点构成了从基础栅格通向响应式布局的完整能力集。
如果想继续深入,建议按以下路径阅读仓库:
- 更多演示(间距、偏移、排序、对齐、响应式、Flex 填充):components/grid/demo 目录下的
gutter.tsx、offset.tsx、sort.tsx、responsive.tsx等; - 完整 API 文档:components/grid/index.zh-CN.md;
- 组件入口与导出:components/grid/index.tsx(同时导出了
useBreakpointHook); - 样式生成细节:components/grid/style/index.ts;
- 响应式订阅机制:components/_util/responsiveObserver.ts。
【免费下载链接】ant-designAn enterprise-class UI design language and React UI library项目地址: https://gitcode.com/gh_mirrors/ant/ant-design
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考