图号 DRG-002 主题 前端 修订 2026.08.01

现代 CSS 布局:Grid 与容器查询入门

过去写响应式布局,习惯按视口宽度堆媒体查询。组件一旦被放进不同的容器,断点就会失效。本文用 Grid 和容器查询,把「组件自己决定如何排布」这件事讲清楚。

从断点堆叠到容器查询

媒体查询回答的问题是「屏幕有多宽」。容器查询回答的问题是「我的容器有多宽」。后者对组件复用更合理:同一个卡片列表,放在侧栏时变窄,放在主区时变宽,它应该根据自身宽度调整,而不是听命于整个页面。

Grid 的基础写法

先看一个最常用的自适应栅格:用 auto-fill 和 minmax,让列数由容器宽度自动决定。

.cards {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  gap: 1rem;
}

含义:每列最少 240px,最多 1fr;容器能放下几列就放几列。这个写法省掉了大多数「桌面三列、平板两列、手机一列」的媒体查询。

容器查询入门

容器查询需要两步:先声明容器,再用 @container 写条件。

.card-list {
  container-type: inline-size;
  container-name: cards;
}

@container cards (min-width: 480px) {
  .card {
    display: grid;
    grid-template-columns: 6rem 1fr;
    gap: 1rem;
  }
}

当 .card-list 的宽度达到 480px 时,里面的卡片自动从上下堆叠切换为左右分栏。容器变窄时自动回到单列,不需要任何 JavaScript。

一个组合示例

把两者组合起来:外层用 Grid 分栏,内层用容器查询切换卡片形态。

.layout {
  display: grid;
  grid-template-columns: 18rem 1fr;
  gap: 2rem;
}

.sidebar {
  container-type: inline-size;
}

.sidebar .card {
  display: grid;
  gap: 0.5rem;
}

@container (min-width: 400px) {
  .sidebar .card {
    grid-template-columns: 3.5rem 1fr;
    align-items: center;
  }
}

要点:容器查询作用在「最近的有 container-type 的祖先」上,所以侧栏里的卡片只对侧栏宽度负责,主区的卡片对主区宽度负责。

兼容性与降级

  • Grid 已得到所有现代浏览器支持,可以放心使用。
  • 容器查询在现代浏览器可用;旧浏览器会忽略 @container 内的规则,因此请把基础样式写在 @container 外面。
  • 把「默认形态」写在外层,把「宽容器形态」写进查询里,就是天然降级。

判断是否支持:CSS.supports("container-type: inline-size")。不支持时保持基础布局即可。