仅靠 display: flex 无法构成完整栅格系统,因其缺乏列数定义、断点响应、gutter隔离等核心能力;需配合 flex-basis/width 双声明、嵌套 margin 重置、flex-wrap/flex-direction 响应式控制及 calc() 精确计算。

直接用 display: flex 搭建栅格系统是可行的,但「可复用」的关键不在 Flex 本身,而在于如何约束列宽计算、断点响应和嵌套行为——否则很快会陷入 flex-basis 手动写百分比、min-width 冲突、子容器意外继承 flex-direction 的混乱。
为什么不能只靠 display: flex 就算栅格系统?
Flex 是一维布局模型,它不自带列数定义、断点切换或 gutter(间距)隔离能力。所谓「12列栅格」本质是一套约定:每行最多 12 份,每份宽度按比例分配,且在不同屏幕下动态重分。纯 Flex 容器不会自动识别 col-4 表示「占 4/12 = 33.333%」,也不会阻止子项在小屏下撑满导致换行错乱。
常见错误现象包括:
- 写
.col-6但实际宽度不是 50%,因为父容器没设flex-wrap: wrap或子项有默认min-width: auto - 嵌套时内层
.row没重置margin,导致 gutter 叠加放大 - 媒体查询里只改了
flex-basis,但忘了同步调整max-width,小屏下内容溢出
flex-basis 和 width 在栅格类中必须配合使用
仅设 flex-basis: 33.333% 不够稳定:当内容超长或字体缩放时,浏览器可能忽略该值强行拉伸;若同时设 width: 33.333% + flex-shrink: 0,就能锁定基础尺寸,再由 flex-grow 控制剩余空间分配。
立即学习“前端免费学习笔记(深入)”;
推荐写法(以 12 列为例):
.col-1 { flex: 0 0 calc(100% / 12); width: calc(100% / 12); }
.col-2 { flex: 0 0 calc(100% / 6); width: calc(100% / 6); }
.col-12 { flex: 0 0 100%; width: 100%; }注意:flex: 0 0 表示不伸缩不收缩,calc() 避免小数精度误差累积;width 是 fallback,对非 Flex 场景(如旧版 Safari)或调试时可见。
嵌套栅格必须重置 margin 和 flex-wrap
每一层 .row 都应是独立 Flex 容器,但默认 margin 会从父级继承,造成嵌套后左右间距翻倍。必须显式清除:
- 外层
.row:设margin: 0 -0.5rem(负边距抵消子项padding) - 内层
.row:必须重写为margin: 0,否则嵌套两层后左右各多出 1rem - 所有
.row必须带flex-wrap: wrap,否则子项超出一行时会被压缩而非换行
典型结构:
<div class="row">
<div class="col-8">
<div class="row" style="margin: 0"> <!-- 关键:重置 margin -->
<div class="col-6"></div>
<div class="col-6"></div>
</div>
</div>
</div>响应式断点要控制 flex-direction 和 flex-wrap 的组合
移动端常需把横向栅格转为纵向堆叠,比如「桌面端 3 列卡片 → 手机端单列」。仅靠改 flex-basis 不够,必须配合:
-
@media (max-width: 768px)下,给.row加flex-direction: column,让子项垂直排列 - 同时设
flex-wrap: nowrap,防止小屏下因内容高度不一导致错行 - 避免在子项上单独写
order,那会破坏栅格语义;顺序应由 HTML 结构决定
容易被忽略的一点:iOS Safari 在 flex-direction: column + align-items: stretch 下,子项若含 img 且无明确 height,可能触发不可预测的高度计算——此时应在图片外层加 min-height: 1px 或用 object-fit 控制。


















