Ant Design Layout 上中下布局详解:构建经典 Header-Content-Footer 页面骨架
本篇基于 Ant Design 官方示例「上中下布局」(components/layout/demo/top.md)展开,系统讲解这一最经典的「Header - Content - Footer」页面骨架的设计动机、可运行的完整实现代码,并结合 Layout 源码与样式实现剖析其 flex 布局机制与 Design Token 默认值,帮助读者快速搭建结构稳定的企业级页面布局,并理解何时该选上中下布局、何时应切换到侧边布局。
什么是「上中下」布局
根据官方示例说明(top.md),这是最基本的『上-中-下』布局:
- 主导航位于页面顶端:从左到右依次为 logo、一级导航项、辅助菜单(用户、设置、通知等)。
- 内容区使用固定尺寸约束:通常将内容放在固定宽度(例如
1200px)内,使整个页面排版稳定,不受用户终端显示器尺寸影响。 - 符合浏览习惯:上下级的结构符合用户自上而下浏览的习惯,是较为经典的网站导航模式。
- 效率与代价的权衡:页面上下切分的方式提高了主工作区域的信息展示效率,但在纵向空间上会有一些牺牲。
- 适用边界:由于导航栏水平空间的限制,这种模式不适合一级导航项很多的信息结构——导航项过多时水平空间无法容纳,此时应考虑侧边布局或顶部-侧边组合布局。
英文版文档(同一文件中 en-US 部分)的表述为:The most basic "header-content-footer" layout. Top-bottom structure is conformed with the top-bottom viewing habit, it's a classical navigation pattern of websites. This pattern demonstrates efficiency in the main workarea, while using some vertical space.
完整可运行的上中下布局示例
Ant Design 仓库中的完整示例位于 top.tsx,可直接复制到项目中使用:
import React from 'react';
import { Breadcrumb, Layout, Menu, theme } from 'antd';
const { Header, Content, Footer } = Layout;
const items = Array.from({ length: 15 }).map((_, index) => ({
key: index + 1,
label: `nav ${index + 1}`,
}));
const App: React.FC = () => {
const {
token: { colorBgContainer, borderRadiusLG },
} = theme.useToken();
const currentYear = new Date().getFullYear();
return (
<Layout>
<Header style={{ display: 'flex', alignItems: 'center' }}>
<div className="demo-logo" />
<Menu
theme="dark"
mode="horizontal"
defaultSelectedKeys={['2']}
items={items}
style={{ flex: 1, minWidth: 0 }}
/>
</Header>
<Content style={{ padding: '0 48px' }}>
<Breadcrumb
style={{ margin: '16px 0' }}
items={[{ title: 'Home' }, { title: 'List' }, { title: 'App' }]}
/>
<div
style={{
background: colorBgContainer,
minHeight: 280,
padding: 24,
borderRadius: borderRadiusLG,
}}
>
Content
</div>
</Content>
<Footer style={{ textAlign: 'center' }}>
Ant Design ©{currentYear} Created by Ant UED
</Footer>
</Layout>
);
};
export default App;
示例中的关键技术点
-
三段式结构:最外层
Layout内依次放置Header、Content、Footer三个子组件,正好对应『上-中-下』三个区域。官方 Layout 组件文档给出的标准嵌套形态为:<Layout> <Header>header</Header> <Layout> <Sider>left sidebar</Sider> <Content>main content</Content> <Sider>right sidebar</Sider> </Layout> <Footer>footer</Footer> </Layout> -
Header 内部的 flex 排布:
Header上直接设置display: 'flex', alignItems: 'center',logo 占位元素固定,Menu通过flex: 1, minWidth: 0吃掉剩余空间——minWidth: 0是 flex 子项的经典防溢出写法,避免 15 个导航项撑破水平导航栏。 -
深色水平菜单:
Menu使用theme="dark"+mode="horizontal",与Header的深色默认背景(tokenheaderBg默认#001529)搭配。源码中 Header 样式特意让内嵌的.ant-menu继承lineHeight(见 style/index.ts 中lineHeight: unit(headerHeight)),使菜单项与 Header 等高对齐,这是「菜单融入顶栏」的官方集成细节。 -
内容卡片使用全局 Token:通过
theme.useToken()取出colorBgContainer与borderRadiusLG,使内容区的背景色、圆角随主题自动切换(亮/暗模式),而不是写死颜色值。 -
面包屑 + 内容卡片:
Content内以Breadcrumb提供路径导航,再放置一块minHeight: 280的内容容器,模拟真实业务页面的主工作区。
源码剖析:Header / Content / Footer 是如何生成的
阅读 layout.tsx 可以看到,四个区域组件均由同一个 generator 工厂函数从 BasicLayout 派生:
const Layout = generator({
tagName: 'div',
displayName: 'Layout',
})(BasicLayout);
const Header = generator({
suffixCls: 'header',
tagName: 'header',
displayName: 'Header',
})(Basic);
const Footer = generator({
suffixCls: 'footer',
tagName: 'footer',
displayName: 'Footer',
})(Basic);
const Content = generator({
suffixCls: 'content',
tagName: 'main',
displayName: 'Content',
})(Basic);
由此得到两点值得注意的实现事实:
- 语义化 HTML:
Layout渲染为div,而Header、Footer、Content分别渲染为<header>、<footer>、<main>语义标签,天然对 SEO 和无障碍(screen reader 的 landmark 识别)友好。 - 类名规则:每个组件在
Basic中通过getPrefixCls('layout')得到前缀,再拼接suffixCls,最终类名为ant-layout、ant-layout-header、ant-layout-footer、ant-layout-content。Basic组件还负责挂接hashId与cssVarCls,即 CSS-in-JS 样式与 CSS 变量模式的接入点。
hasSider:为什么上中下布局是纵向 flex
BasicLayout 的核心职责之一是通过 useHasSider 判断子元素中是否存在 Sider:
// components/layout/hooks/useHasSider.ts
export default function useHasSider(
siders: string[],
children?: React.ReactNode,
hasSider?: boolean,
) {
if (typeof hasSider === 'boolean') {
return hasSider;
}
if (siders.length) {
return true;
}
const childNodes = toArray(children);
return childNodes.some((node) => node.type === Sider);
}
判断结果决定 ant-layout-has-sider 类名是否生效。对应到 样式层:
[componentCls]: {
display: 'flex',
flex: 'auto',
flexDirection: 'column', // 默认:纵向排列,即上中下
minHeight: 0,
background: bodyBg,
'&, *': { boxSizing: 'border-box' },
[`&${componentCls}-has-sider`]: {
flexDirection: 'row', // 含 Sider 时:横向排列
[`> ${componentCls}, > ${componentCls}-content`]: { width: 0 },
},
[`${componentCls}-header, &${componentCls}-footer`]: {
flex: '0 0 auto', // 头、脚固定高度,不伸缩
},
}
对「上中下布局」而言,因为子元素中没有 Sider,Layout 保持 flex-direction: column:Header 与 Footer 都是 flex: 0 0 auto(占位固定),Content 则是 flex: auto + minHeight: 0(见 style/index.ts)——这就是中间内容区自动填满 Header 与 Footer 之间剩余空间、且可被压缩到小于内容高度的原理。minHeight: 0 上的注释表明这是修复 Firefox 中 flex 项无法收缩至内容高度以下的兼容性问题。
从源码结构看,BasicLayout 还通过 LayoutContext 向上层暴露 addSider / removeSider 钩子,供嵌套的 Sider 动态注册自己——这也是「动态增删侧边栏时 has-sider 类名能实时更新」的机制来源。hasSider 属性则如 Layout 文档 的 API 表所述,「表示子元素里有 Sider,一般不用指定。可用于服务端渲染时避免样式闪动」:SSR 首帧无法感知运行时 children 时,手动传入可避免布局方向闪动。
上中下布局相关的 Design Token
prepareComponentToken 定义了 Layout 的组件级 Token 及其默认值,直接决定示例的视觉观感:
| Token | 说明 | 默认值 |
|---|---|---|
headerHeight |
顶部高度 | controlHeight * 2(默认 64px) |
headerBg |
顶部背景色 | #001529 |
headerPadding |
顶部内边距 | 0 ${controlHeightLG * 1.25}px(默认 0 50px) |
headerColor |
顶部文字颜色 | colorText |
footerBg |
页脚背景色 | colorBgLayout |
footerPadding |
页脚内边距 | ${controlHeightSM}px ${controlHeightLG * 1.25}px |
bodyBg |
主体部分背景色 | colorBgLayout |
可以看到 Header 的默认高度 64px 与官方设计规范完全一致。同时源码中声明了废弃 Token 映射(DEPRECATED_TOKENS):colorBgHeader → headerBg、colorBgBody → bodyBg、colorBgTrigger → triggerBg,即旧版 colorBgHeader 等命名已废弃,新代码应直接使用上表中的 Token 名。
设计规范:高度与宽度的取值公式
Layout 文档 的「设计规则」章节给出了页面级尺寸的量化标准,可作为搭建上中下布局时的取值依据:
- 顶部导航(大部分系统):一级导航高度
64px,二级导航48px; - 顶部导航(展示类页面):一级导航高度
80px,二级导航56px; - 顶部导航高度的范围计算公式:
48 + 8n; - 侧边导航宽度的范围计算公式:
200 + 8n。
例如默认的 headerHeight: 64px 恰好是 48 + 8×2。若需要在项目层面统一调整,可以在 ConfigProvider 的 theme.components.Layout 中覆盖 headerHeight、headerBg 等 Token;而一次性调整(比如让 Header 与水平菜单等高)也可以直接在 Header 上通过 style 覆盖,如示例中 display: 'flex', alignItems: 'center' 的做法。
与相邻布局模式的选型对照
官方在同一 demo 目录 下提供了完整布局族谱,上中下布局只是其中一种:
| 示例 | 说明 |
|---|---|
| basic.tsx | 基本结构(Layout 嵌套 Sider + Content) |
| top.tsx | 上中下布局(本篇主题) |
| top-side.tsx | 顶部-侧边布局 |
| top-side-2.tsx | 顶部-侧边布局-通栏 |
| side.tsx | 侧边布局 |
| responsive.tsx | 响应式布局(Sider breakpoint + collapsedWidth) |
| fixed.tsx | 固定头部 |
| fixed-sider.tsx | 固定侧边栏 |
| component-token.tsx | 组件 Token 覆盖 |
结合原文档的结论,选型原则可以归纳为:
- 一级导航项少(如 5 个以内):首选上中下布局,Header 内放水平
Menu; - 一级导航项多、需要分组或层级:改为 top-side.tsx 或 side.tsx,把导航移到
Sider中纵向展开——此时 Layout 自动切换为flex-direction: row; - 需要小屏折叠侧栏:在 responsive.tsx 基础上使用
Sider的breakpoint/collapsedWidth/onBreakpoint属性。
小结
上中下布局是 Ant Design Layout 组件族中最简单的形态:Header(<header>)与 Footer(<footer>)以 flex: 0 0 auto 固定上下,Content(<main>)以 flex: auto 撑满中部,整棵子树统一 box-sizing: border-box 并默认纵向 flex 排列。示例 top.tsx 展示了「深色水平菜单 + 面包屑 + Token 驱动的内容卡片」这一完整套路,而高度取值(48 + 8n)、背景色与内边距均由 style/index.ts 中的 Layout Token 统一管控,可通过 ConfigProvider 在应用级覆盖。理解 useHasSider 驱动的 ant-layout-has-sider 切换机制后,就能在同一套 Layout API 上平滑扩展出顶部-侧边、响应式等更复杂的页面骨架。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0627
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00