刚写 CSS 那几年,我总在两个属性之间犹豫:这个横向排列用 Flex 还是 Grid?后来想明白一件事——判断标准不是"哪个更强",而是你要控制的是一维还是二维。
一句话判断
- 内容驱动、沿一个方向排队 → Flex
- 容器驱动、行列同时对齐 → Grid
导航栏、按钮组、表单项、标签流,这些元素的数量和宽度是内容决定的,用 Flex。整页骨架、卡片墙、仪表盘,行列都得对齐,用 Grid。
Flex 的主场
两端对齐的头部
.header {
display: flex;
align-items: center;
justify-content: space-between;
gap: 16px;
}
gap 出现之后,再也不用给子元素写 margin-right 再 :last-child 清除,代码短了一大截。
等宽按钮,且不被文字撑开
.actions > button {
flex: 1 1 0; /* 三个数字:放大、缩小、基准宽度 */
min-width: 0; /* 关键,见下面 */
}
flex: 1 1 0 的意思是"基准宽度算 0,剩余空间平均分",这样两个按钮无论文字长短都一样宽。如果写 flex: 1,它等价于 flex: 1 1 0%,效果一致;但写 flex: auto 就是 1 1 auto,宽度会被内容带偏。
单行省略号失效的那个坑
这大概是 Flex 最经典的坑:text-overflow: ellipsis 写了,就是不出省略号。
原因在于 flex item 的 min-width 默认是 auto,它拒绝被压缩到内容宽度以下。解决办法就一行:
.row { display: flex; gap: 12px; }
.row .title {
flex: 1;
min-width: 0; /* 允许收缩到内容宽度以下 */
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
同一类问题在 Grid 里也存在,minmax(0, 1fr) 就是它的解法。
Grid 的主场
卡片墙,不写媒体查询
.cards {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
gap: 20px;
}
这一段的含义是:每列至少 280px,能塞几列塞几列,剩余空间均分。窗口从 1920 缩到 400,布局自然过渡,一行媒体查询都不需要。
auto-fill 和 auto-fit 的区别只在最后一行:容器很宽而卡片很少时,auto-fill 会留下空轨道,auto-fit 会把现有卡片拉宽填满。卡片墙一般用 auto-fill,想让少数几张图铺满整行就用 auto-fit。
整页骨架
.layout {
display: grid;
grid-template-columns: 240px minmax(0, 1fr);
grid-template-rows: 64px 1fr auto;
grid-template-areas:
"sidebar topbar"
"sidebar main"
"sidebar footer";
min-height: 100vh;
gap: 16px;
}
.layout > .sidebar { grid-area: sidebar; }
.layout > .main { grid-area: main; }
用 grid-template-areas 描述布局,HTML 里直接读得懂结构,改动时改 ASCII 图就行,比一堆百分比定位好维护得多。
什么时候混着用
实际项目里,两种布局是嵌套的,不冲突:
.page {
display: grid; /* 二维:页面骨架 */
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
gap: 20px;
}
.card {
display: flex; /* 一维:卡片内部 */
flex-direction: column;
}
.card .tags { display: flex; flex-wrap: wrap; gap: 6px; }
.card .foot { margin-top: auto; } /* 底部对齐,卡片等高时很好用 */
外层 Grid 定格子,内层 Flex 排内容。margin-top: auto 在 flex 列里能把页脚顶到底部,是等高卡片对齐底部按钮的最省事写法。
结论
别背属性表,就问自己两个问题:
- 我要对齐的是"一条线"还是"一张网格"?
- 宽度由内容决定,还是由容器决定?
一条线加内容驱动,Flex。一张网格加容器驱动,Grid。答完这两个问题,选型就没悬念了。