文章出现的缘由:为什么我把
margin-right换成了gap?以及你也该这么做的理由
引子:一个"能用但不舒服"的写法
最近改一个小程序卡片,底部并排两个按钮------「更换订单」和「进入订单列表」,中间要留一点间距。我顺手写了:
css
.btn-row {
display: flex;
}
.change-center {
margin-right: 50px; // 给左边按钮加个右间距
}
效果没问题,设计稿也还原了。但盯着它看,总觉得哪里"硬": 间距明明是这一行的事,为什么要让左边那个按钮自己去扛? 如果哪天加第三个按钮、或者调换顺序,这个 margin-right 就成了要小心维护的"暗雷"。
于是我把它换成了一行属性 gap。这篇文章就从这个小改动出发,把属性 gap 讲透。
一、gap 是什么:把"间距"还给容器
先看改完的样子:
css
.btn-row {
display: flex;
gap: 50px; // 间距由容器统一声明
}
/* .change-center 上的 margin-right 删掉了 */
区别看着小,理念差很多:
margin方案:让子元素操心"我和邻居之间留多远"。gap方案:让容器声明"我的孩子们彼此间隔多远",孩子互不关心。
这和我们用 flex: 1 / flex-shrink: 0 是同一种思维------每个元素只声明跟自己有关的事,把"协调关系"交给容器。代码因此更可读、可维护。
二、一段不长的历史:它本来不叫 gap
很多人不知道,gap 最早是 Grid 专属的,那时它叫:
grid-gap/grid-row-gap/grid-column-gap
后来 CSS 规范把它从 Grid 模块提取到通用的 Box Alignment 模块,正式更名为 gap / row-gap / column-gap,并扩展到 Flexbox 和多列布局。
这段历史解释了两件事:
- 老代码/老教程里的
grid-gap和今天的gap是一回事(现代浏览器仍兼容旧名,新代码请用gap)。 - 因为是"后来才借给 flex 的",flex 下的 gap 支持就比 grid 晚------这正是早年大家对 flex gap 有兼容顾虑的根源。
三、使用场景: 必须有"布局上下文"
最关键的一点:gap 不是 flex 专属,但它只在"会管理子元素排布的容器"里才生效。
| 布局 | gap 生效? | 备注 |
|---|---|---|
Flex (display: flex) |
✅ | 支持较晚,早年兼容顾虑的来源 |
Grid (display: grid) |
✅ | gap 的"娘家",支持最早最稳 |
多列 (column-count/columns) |
✅ | 控制列间隙 |
| 普通块级/行内 (默认 block、inline) | ❌ | 完全不生效,写了也没用 |
换句话说:在一个没开 flex/grid 的普通 <div> 上写 gap,它会静默失效 ------不报错、间距也不出现。这是新手最容易踩的坑,排查时第一步永远是确认:容器是 flex 或 grid 吗?
四、用法速查
css
/* 行、列间距相同 */
.box { display: flex; gap: 30rpx; }
/* 两个值:行间距在前,列间距在后 */
.box { display: flex; flex-wrap: wrap; gap: 20rpx 30rpx; }
/* ↑行 ↑列 */
/* 等价的单独属性 */
.box {
row-gap: 20rpx; /* 行与行之间 */
column-gap: 30rpx; /* 列与列之间 */
}
记住三条:
- gap 只加在容器上,不加在子元素上。
- 只作用于子元素之间,容器首尾边缘不会多出间距。
- 一个值 = 行列通用;两个值 =
行 列(行在前,别记反)。
五、它取代了哪些"祖传技巧"
gap 真正的价值,要和它取代的老写法对比才看得出来。
老技巧 A------margin + 排除最后一个:
css
.item:not(:last-child) { margin-right: 30rpx; }
/* 或者猫头鹰选择器 */
.row > * + * { margin-left: 30rpx; }
能用,但选择器有心智负担,换行时边缘还会留多余 margin。
老技巧 B------负 margin hack(换行网格的经典噩梦):
css
.row { margin: -10rpx; }
.item { margin: 10rpx; } /* 用容器负 margin 抵消子项外扩的间距 */
负 margin 会溢出容器、和 padding/border 互相打架、极易翻车。
gap 一行干掉以上所有,且没有任何副作用。
六、高光场景:换行布局
单行两个按钮,其实体现不出 gap 的威力。它真正的主场是换行:
css
/* 标签云 / 筛选项:自动换行,行列间距都均匀,边缘无多余空隙 */
.tags {
display: flex;
flex-wrap: wrap;
gap: 16rpx 24rpx; /* 行间距 16,列间距 24 */
}
"换行 + 两个方向都要间距"正是 margin 方案最难写、最容易出 bug 的场景,而 gap 一行搞定且边缘干净。如果你要给文章配一个最能打动人的例子,用这个。
七、几个容易忽略的特性
- gap 不会外边距合并(margin collapse): 相邻 margin 会取最大值合并,gap 所见即所得。
- gap 区域不可点击: 和 padding 不同(padding 属于元素、可点)。用 gap 分隔按钮能天然拉开点击热区,减少误触------一个常被忽略的 UX 加分点。
flex: 1与 gap 协同正确: 子项平分宽度时,gap 先从可用空间扣除再均分剩余,不会把布局挤破。- gap 只管中间不管边缘: 要边缘间距,请用容器的
padding。
八、什么时候"别用" gap
好文章会讲边界。以下情况 gap 不一定是最优解:
- 只有一个间距、不换行、不增减元素: 一个
margin就很清楚,没必要为"政治正确"硬上 flex+gap。 - 要兼容很老的环境(老安卓 WebView、老小程序基础库):评估后可能仍需 margin 兜底。
- 间距只在某一侧、或需要包含边缘: gap 只管中间,这时用 padding/margin 反而更直白。
兼容性附录
Flex gap 起始支持版本(发文前建议在 caniuse.com 复核):
| 浏览器 | 起始版本 | 大致时间 |
|---|---|---|
| Chrome / Edge | 84 | 2020 年中 |
| Firefox | 63 | 2018 年 |
| Safari / iOS | 14.1 / iOS 14.5 | 2021 年初 |
Grid gap 支持早得多(2017 左右)。小程序场景:webview 渲染依赖设备底层内核,现代机型无忧,老安卓机建议真机回归。
结语
gap 不是要消灭 margin,而是把"元素之间的间距"这类需求,从挂在子元素上的补丁 ,升级成由容器声明的布局属性------可读、可维护,换行场景尤其香。
但记住它的两条边界:只在 flex/grid/多列里生效 ,只管中间不管边缘。用之前先看清楚布局上下文,你就能避开 90% 的坑。
从一个 margin-right 到一个 gap,改的是一行代码,变的是"谁该为间距负责"的思路。而好的 CSS,往往就藏在这种"谁负责"的判断里。