从一个按钮间距,聊透 CSS 的 gap 属性

文章出现的缘由:为什么我把 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多列布局

这段历史解释了两件事:

  1. 老代码/老教程里的 grid-gap 和今天的 gap 是一回事(现代浏览器仍兼容旧名,新代码请用 gap)。
  2. 因为是"后来才借给 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,往往就藏在这种"谁负责"的判断里。

相关推荐
北冥有鱼1 小时前
mqtt 测试
前端·后端
张鑫旭2 小时前
都AI时代了,我为何还在学习前端基础知识?
前端
swipe2 小时前
正则表达式入门到进阶:从表单校验到手写模板引擎
前端·javascript·面试
阿祖zu2 小时前
别再优化 RAG 了,适配 Agent 的 LLM Wiki 知识库理念
前端·后端·aigc
kyriewen2 小时前
前端错误监控最全指南:捕获 JS 异常、Promise 拒绝、资源加载失败,附上报代码
前端·javascript·监控
狗哥哥3 小时前
船队运营可视化技术方案
前端
大家的林语冰3 小时前
ESLint 近期动态大全,新版本正式发布,antfu 大佬推荐的插件也更新了!
前端·javascript·前端工程化
只会cv的前端攻城狮3 小时前
DSL 领域模型架构设计:消灭 CRUD 重复工作
前端·架构
码事漫谈3 小时前
时序数据库2026盘点:国产数据库如何以“融合多模”走出差异化之路?
前端·后端