「Grid 还是 Flexbox」这个问题没有标准答案,但有判断依据:看你要控制的是一个方向,还是行列同时对齐。下面用三个最常见的布局场景说明。

CSS Grid 还是 Flexbox:按场景选对布局方案 示意图

先分清一维与二维

  • 一维:一行按钮、一个导航条、卡片内部的图标加文字。用 Flexbox;
  • 二维:行列都要对齐,例如「左侧设置 + 右侧预览」「三列卡片、间距统一」。用 Grid;
  • 页面级骨架用 Grid,组件内部用 Flexbox,是最省心的组合。

Flexbox:一行之内怎么排

导航、按钮组、列表项这类「沿一个方向排列」的场景,Flexbox 的 justify-content 与 align-items 已经够用。

.toolbar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem;
}

.toolbar .spacer {
    margin-left: auto; /* 把右侧操作推到最右 */
}

用 gap 而不是给子元素加 margin-right,换行时不会多出多余的间距。flex: 1 让搜索框占满剩余空间,比写死宽度更适应窄屏。

Grid:行列同时对齐

卡片列表最典型。用 auto-fit 加 minmax 可以写出「不写媒体查询也能自适应」的网格:

.cards {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
    gap: 1.25rem;
}

minmax(16rem, 1fr) 表示每列最窄 16rem、剩余空间平均分配;容器放得下几列就排几列,放不下自动减少列数。相比固定 grid-template-columns: 1fr 1fr 1fr 再写三个断点,维护成本低很多。

左右分栏与粘性侧栏

.layout {
    display: grid;
    gap: 2rem;
    grid-template-columns: minmax(0, 1fr);
}

@media (min-width: 1024px) {
    .layout {
        grid-template-columns: minmax(0, 1fr) 18rem;
    }
}

minmax(0, 1fr) 里的 0 很关键:默认的 1fr 会被内容撑开,长代码块或长链接会把右侧栏挤走。加上 minmax(0, 1fr) 才能让内容在自己的列里滚动或换行。

两个常见误区

  • 用 Grid 做「一行三个等宽按钮」,然后在每个按钮内部又用 Grid 居中 —— 内部其实用 display: flex; align-items: center; justify-content: center 更直观;
  • 用 Flexbox 硬做二维网格,靠 width: 33.33% 加负边距凑间距。换成 Grid 加 gap 一行就够。

响应式的两种思路

一种是「容器宽度决定列数」,用 auto-fit;另一种是「断点决定布局」,用媒体查询切换 grid-template-areas。前者适合卡片流,后者适合页面骨架。

.page {
    display: grid;
    grid-template-areas:
        "header"
        "main"
        "aside";
}

@media (min-width: 1024px) {
    .page {
        grid-template-areas:
            "header header"
            "main aside";
        grid-template-columns: minmax(0, 1fr) 18rem;
    }
}

用 grid-template-areas 的好处是布局在 CSS 里一眼能看懂,改顺序不用动 HTML。

小结

一句话选择法:只控制一个方向的间距与对齐,用 Flexbox;要同时控制行列,用 Grid;页面骨架用 Grid、局部组件用 Flexbox。真正决定可维护性的不是选哪个,而是统一 gap 与容器宽度,避免每个组件各写一套边距。布局改完记得在窄屏实测,图片与字体的加载优化可以接着看前端性能清单。