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

相关推荐
To_OC2 小时前
别再串行写 await 了,Promise.all 才是并行请求的正确打开方式
前端·javascript·promise
vipbic2 小时前
中后台越做越乱后,我用插件化把它救回来了
前端·vue.js
Hyyy2 小时前
Computer Use 适合做什么,不适合做什么——一次真实使用后的思考
前端
小和尚同志3 小时前
前端 AI 单元测试思考与落地
前端·人工智能·aigc
invicinble4 小时前
c端系统,其实更像一个信息展示平台
前端
李姆斯5 小时前
管理是否可以被完全量化
前端·产品经理·团队管理
名字还没想好☜5 小时前
Next.js 中间件实战:鉴权、重定向与 A/B 分流
开发语言·前端·javascript·中间件·react·next.js
广州灵眸科技有限公司6 小时前
瑞芯微RV1126B开发板(EASY-EAI-PI2) INI文件操作
java·前端·javascript·网络·人工智能
江华森6 小时前
Web 开发基础:HTTP 与 REST
前端·网络协议·http
IT_陈寒7 小时前
Redis的KEYS命令把我搞崩溃了,改用SCAN才活过来
前端·人工智能·后端