Rucky 前端笔记

CSS

Flexbox 还是 Grid:一个够用的判断方法

不用背属性表。先问尺寸是由内容决定还是由版面决定,再避开几个常见的坑,布局问题就解决了大半。

一个问题就够了

选 Flexbox 还是 Grid,常见的说法是“一维用 Flex,二维用 Grid”。这句话没错,但实际写页面时,我更常问的是另一个问题:尺寸是由内容决定的,还是由版面决定的?

  • 内容决定尺寸:元素有多宽就占多宽,排不下再换行或收缩。用 Flexbox。
  • 版面决定尺寸:先划好轨道,元素放进去对齐。用 Grid。
场景选择原因
导航栏、按钮组、标签列表Flexbox每一项的宽度取决于文字长度
卡片网格Grid行和列都需要对齐
页面整体框架(侧栏 + 内容)Grid轨道是提前规划好的
左边图标、右边文字Flexbox一行内的对齐和分配剩余空间

两者也不是二选一。常见做法是外层用 Grid 划分版面,组件内部用 Flexbox 排列内容。

动手试一下 Flexbox

调整下面的选项,观察四个方块的变化。下方的代码会实时更新:

这个互动示例需要启用 JavaScript。

三个常见的 Flexbox 问题

长文本把容器撑破了。 Flex 子项的 min-width 默认是 auto,也就是不能比内容更窄。如果子项里有不换行的长文本或代码,它就不肯收缩。给子项加上 min-width: 0 即可:

CSS
.row { display: flex; gap: 12px; }

.row .title {
  flex: 1;
  min-width: 0; /* 允许收缩到比内容更窄 */
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

**flex: 1 到底是什么意思。** 它是 flex-grow: 1; flex-shrink: 1; flex-basis: 0% 的简写。基准宽度为 0,所以几个 flex: 1 的子项会等分空间,和内容多少无关。如果希望先按内容占位,再分配剩余空间,要用 flex: 1 1 auto。

把最后一个元素推到底部或最右边。 不需要额外包一层,在 Flex 容器里,margin-left: auto 或 margin-top: auto 会吃掉所有剩余空间:

CSS
.card { display: flex; flex-direction: column; }
.card .action { margin-top: auto; } /* 按钮始终贴底 */

不写媒体查询的响应式网格

Grid 最实用的一行代码,是让列数随容器宽度自动变化:

CSS
.cards {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(240px, 100%), 1fr));
  gap: 16px;
}

这里有两个细节:

  • **auto-fill 和 auto-fit 的区别**:只有在元素少、一行放不满时才看得出来。auto-fill 会保留空轨道,元素保持原有宽度;auto-fit 会折叠空轨道,元素被拉宽填满整行。
  • **min(240px, 100%)** 防止容器比 240px 还窄时溢出。

用 subgrid 对齐卡片内部

一排卡片的标题长短不一,下面的内容就对不齐,这是个老问题。subgrid 让卡片内部直接使用外层网格的行轨道,标题、正文和按钮在所有卡片之间自动对齐:

CSS
.cards {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 16px;
}

.card {
  display: grid;
  grid-row: span 3; /* 占三行:标题、正文、按钮 */
  grid-template-rows: subgrid;
}

小结

先问尺寸由谁决定。内容决定用 Flexbox,版面决定用 Grid,外层 Grid 配内层 Flexbox 是最常见的组合。遇到 Flex 子项撑破容器,第一反应应该是检查 min-width: 0。

延伸阅读