文章目录
目录导航
快速定位文章内容
正文
刚开始写布局时,我很长一段时间都在靠
margin 处理间距。列表项之间加一点。
卡片之间推开一点。
导航按钮之间隔一点。
看起来都能做,而且写起来也很顺手。
但项目做多了之后,我越来越明显地感觉到一件事:
很多“布局越来越乱”的问题,不是因为 CSS 太难,而是因为我一开始就把“组件自身的外边距”和“容器内部的排布间距”混在了一起。
这也是为什么我现在只要是处理一组元素之间的间距,第一反应通常都会先看一句:
能不能直接用
gap?margin 不是不能用,而是它经常承担了不该它承担的事
先说清楚一点。
margin 本身当然没有问题。
它依然是 CSS 里非常基础、也非常有用的属性。问题在于,很多时候我们明明想表达的是:
- 这一组元素之间要有固定间距
- 间距由父容器统一控制
- 第一个和最后一个元素不需要特殊处理
但最后却写成了这样:
.list-item { margin-right: 16px; }
或者:
.card + .card { margin-top: 20px; }
短期看没问题。
可一旦这个结构开始变化,你很快就会遇到下面这些情况:
- 最后一个元素多出一截空白
- 横排改竖排时,原来的
margin-right全得重写 - 组件被搬到另一个容器里之后,外边距语义不对了
- 嵌套布局一多,间距到底是谁控制的会越来越难看清
也就是说,
margin 很容易把“排版责任”塞进组件自己身上。而我现在更想要的是:
组件只管长什么样。
至于它和别人隔多远,尽量交给外层布局来决定。
gap 更像是在描述“这一组元素怎么排”
gap 的好处,不只是少写几行代码。更重要的是,它表达得更准。
比如这段:
.list { display: flex; gap: 16px; }
这句话的意思非常清楚:
- 这是一个
flex容器 - 容器里的子项彼此相隔
16px - 不需要关心第一个和最后一个元素怎么处理
这其实是在描述“布局关系”。
而不是像
margin 那样,把间距挂在某一个具体元素身上。这种区别在小 demo 里不明显,但一到真实页面里就特别重要。
因为页面里的结构不是静止的。
它经常会变:
- 横排变竖排
- 一行变多行
- 项目数量变多变少
- 内容从按钮换成卡片
- 组件被复用到别的区域
这时候,如果间距是靠容器统一控制的,整个结构会稳很多。
我现在最常用 gap 的几个场景
1. 按钮组
.actions { display: flex; gap: 12px; }
这个场景几乎没什么悬念。
按钮和按钮之间的距离,本来就应该由这一组按钮的容器来控制。
如果你给每个按钮都写
margin-right,那它一旦换行、反向排列,或者插入一个新按钮,维护成本就会上来。2. 卡片列表
.card-list { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 24px; }
这个比给每张卡片写外边距自然得多。
因为这里真正存在的是“网格之间的间隙”,而不是“某张卡片自己要往外顶 24px”。
尤其在
grid 里,gap 基本就是天选属性。
它和布局模型本身是贴合的。3. 表单项堆叠
.form-section { display: flex; flex-direction: column; gap: 16px; }
这类纵向结构以前很容易写成:
.form-item { margin-bottom: 16px; }
但一旦最后一个元素不想留白,或者中间插入帮助文本、错误提示,你就会开始补各种选择器。
换成
gap 之后,这类问题会少很多。4. 导航、标签、筛选项
.tag-list { display: flex; flex-wrap: wrap; gap: 10px; }
这个场景我现在几乎默认先用
gap。因为一旦允许换行,
margin 的控制就会变得很别扭。
横向间距、纵向间距、最后一列、换行后的对齐,都会变得更麻烦。而
gap 对“换行后的整体观感”通常更友好。响应式场景里,gap 会省事很多
我后来越来越喜欢
gap,还有一个很现实的原因:它特别适合做响应式。
比如:
.list { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 24px; } @media (max-width: 768px) { .list { grid-template-columns: 1fr; gap: 16px; } }
这里你只需要改容器。
子项本身完全不用动。
但如果你之前是靠每个子项的
margin 在撑结构,那响应式时经常会变成:- 改方向
- 改边距方向
- 去掉最后一个间距
- 调整特殊项
- 修正嵌套样式
最后就会越来越像在补漏洞。
什么时候我还是会继续用 margin
说了这么多,不代表
margin 就该退场。我现在的习惯更像是这样:
如果我要表达的是“元素和元素之间的编排间距”,优先想
gap。
如果我要表达的是“某个元素需要和外界保持距离”,那还是用 margin。比如这些场景,我还是会直接用
margin:1. 文章段落和标题之间的间距
这是排版的一部分,不一定总能抽出一个专门容器统一控制。
2. 某个独立组件和上下文之间的留白
比如一个卡片模块和页面其他区块之间要拉开距离,这时候
margin-top、margin-bottom 依然很直接。3. 需要刻意制造“这个元素自己往外让一点”的效果
比如徽标、浮动按钮、吸顶条这些局部元素,它们的空间关系更偏组件级,而不是容器级。
所以重点不是“全面禁用
margin”。而是先想清楚:
这个间距,到底属于组件自己,还是属于父级布局?
一个我现在很在意的小原则
如果某个组件离开当前容器之后,间距定义就显得奇怪,那大概率这个间距本来就不该写在组件自己身上。
这句话对我帮助挺大。
因为它会逼着我区分两件事:
- 组件的样式
- 布局的样式
以前这两件事我经常混着写,结果就是复用一多,结构就开始打架。
现在我会更倾向于这样处理:
.card-list { display: grid; gap: 20px; } .card { padding: 16px; border-radius: 12px; background: #fff; }
容器负责“卡片之间怎么排”。
卡片自己负责“卡片长什么样”。
这样拆开之后,代码会清楚很多。
最后
我现在不是不用
margin 了,而是不会再第一反应就拿它处理一组元素之间的间距。因为很多时候,我真正想控制的是布局关系。
而不是给某个元素强行塞一个外边距。
对这类问题来说,
gap 的语义更准,结构也更稳。尤其是列表、卡片、标签、按钮组、表单堆叠、响应式布局这些场景,它通常比
margin 更像是“站在布局这一层解决问题”。如果一句话总结我现在的习惯,就是:
能由容器统一控制的间距,就尽量别让子项自己背着走。