最可靠方案是用 CSS 变量(如 --space-sm: 8px)统一定义间距标尺并配合 gap 控制模块间距;gap 仅在 flex/grid 容器生效,需避免与 margin 叠加、注意 Safari 14.0 兼容性及首尾留白处理。

直接用 CSS 变量 + gap 统一控制模块间距,是最可靠、可维护性最强的方案;硬写 margin 或靠空格/换行凑间隙,后期改一个数值就要全局搜索替换,90% 的“间距不一致”问题都源于此。
为什么必须用 CSS 变量定义间距标尺
把 --space-sm: 8px 这类变量写死在 :root 里,不是为了炫技,而是解决真实协作痛点:设计稿说“所有卡片间距统一为 16px”,你得确保表单、列表、导航栏、弹窗里的子项间距全是一套值,且改一处就全局生效。
-
--space-xs: 4px、--space-sm: 8px、--space-md: 16px、--space-lg: 24px、--space-xl: 32px是推荐最小集合,单位带px,避免calc()报错 - 不定义
--space-0,直接写0更直观,也省去一层变量解析 - 表单组件可派生
--form-gap: var(--space-md),但基础标尺必须收口到:root - 变量名带语义(
sm/md)而非具体数值(-16),方便未来切换 2x 缩放或深色模式微调
gap 必须配合 flex/grid 才生效,别往普通 div 上乱加
gap 不是通用“空隙开关”,它只在 display: flex 或 display: grid 容器上起作用——这点被踩坑最多:明明写了 gap: var(--space-md),却没反应,八成是父容器还卡在 display: block。
- Flex 场景下,
flex-wrap: wrap是触发row-gap的前提,否则多行时行间无间隔 - Grid 场景下,
gap等价于同时设row-gap和column-gap,但 Safari 14.0 及更早版本不支持简写,必须拆开写 - 子元素若用了
display: contents或display: none,gap对其无效——它只作用于“参与布局的直系子项” - 不要给子项再设
margin,否则和gap叠加导致间距翻倍;调试时先清空子项margin,只靠容器gap控制
Safari 14.0 兼容必须拆开写 row-gap 和 column-gap
真机上 gap: 16px 看不到效果?不是代码漏了,是 Safari 14.0(对应 iOS 14.0–14.4)静默忽略所有 gap 简写,包括单值和双值。DevTools 的 Computed 面板里根本看不到该属性,容易误判为 CSS 未加载。
立即学习“前端免费学习笔记(深入)”;
- 安全写法永远是:
row-gap: var(--space-md); column-gap: var(--space-md); - 非对称场景(如卡片列表垂直紧凑、水平宽松):
row-gap: var(--space-sm); column-gap: var(--space-lg); - 别加
-webkit-gap,Safari 14.0 中它同样无效 - IE 全系不支持,需用
@supports (gap: 1px)检测后降级为margin+:not(:first-child)
首尾留白不能靠 gap,得用 padding 或 margin 单独处理
gap 只管“子项之间”,不管“子项与容器边缘”。所以一个 .card-grid 容器设置了 gap: var(--space-lg),顶部和底部依然紧贴父容器——这是正常行为,不是 bug。
- 想让整个模块上下有呼吸感,给容器自身加
padding,比如padding: var(--space-lg) 0; - 若模块是流式布局中的一环(如紧跟标题之后),可用
margin-top拉开与上一板块距离,但注意块级元素垂直margin会合并 - 打印 PDF 时,多数引擎不支持
gap,导出前需在@media print中降级为margin+display: block - 用 DevTools 的 Computed 面板确认:看到的是
gap值生效,还是子项的margin在撑开空间——这是定位问题的第一步
真正难的不是写出正确的 gap,而是当设计要求“这个区域用 8px,隔壁区域用 24px”时,意识到它们必须是两个独立容器;试图用选择器去 hack 同一个容器下的不同子项间距,只会让逻辑越来越脆。



















