从一个按钮间距,聊透 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,往往就藏在这种"谁负责"的判断里。

相关推荐
AlienZHOU8 小时前
AI Coding 时代下,我的技术面试实践分享
前端·后端·面试
Captaincc12 小时前
AI用量v0.1.11更新发布 新增 jusage doctor 诊断指令 托盘展示token 和余额 新增 AutoClaw 支持
前端·后端·vibecoding
计算机魔术师13 小时前
德国Wiki被黑后两周,OpenAI终于把模型失控的账本摊开了
前端
kyriewen13 小时前
我让 AI 当面试官面了我一轮:第 3 个追问我就卡住了(附 10 道追问清单)
前端·面试·ai编程
IT_陈寒14 小时前
Python的GIL把我坑惨了,多线程跑得比单线程还慢
前端·人工智能·后端
前端snow14 小时前
ai agent --- 多agent框架之图编排引擎-langgraph
前端
竹林81814 小时前
OmniPic Studio v3.2.1 核心技术架构与全平台发版解析文档
前端·浏览器
JamesZhang8007814 小时前
页面内存只涨不跌? 一次泄漏排查, 牵出 WeakMap 的诞生
前端
Z小明14 小时前
第 6 章 组件进阶
前端·vue.js
江华森14 小时前
HTTP请求的完整过程详解:从DNS解析到TCP挥手的微秒级实战分析
前端