自适应宽度的卡片列表布局

传统实现

在传统响应式布局的背景下,如果我们需要实现自适应宽度的卡片列表布局,需要媒体查询断点,配合复杂的卡片数量规则,以达成布局效果。

  .card-container {
    font-size: 0; /* 去掉 inline-block 的空隙 */
  }
  .card {
    display: inline-block;
    font-size: 14px; /* 恢复字体大小 */
    margin: 16px 0;
    width: 100%; /* 默认 1 列 */
    background: #fff;
    padding: 16px;
  }

  /* sm: 2 列 */
  @media (min-width: 576px) {
    .card {
      width: 48%;
      margin: 1%;
    }
  }
  /* md: 3 列 */
  @media (min-width: 992px) {
    .card {
      width: 30%;
      margin: 1.66%;
    }
  }
  /* lg: 4 列 */
  @media (min-width: 1200px) {
    .card {
      width: 22%;
      margin: 1%;
    }
  }

Grid 实现

grid 布局日益普及的现在,现在我们可以充分利用 grid 布局的特点,更直观方便地实现自适应卡片布局。

使用 grid-template-columns 可以方便地配置网格布局中列维度的尺寸大小。repeat 属性以更简洁的方式定义重复列属性。

  .card-container {
    display: grid;
    gap: 16px; /* 卡片元素间隔 16px */
    grid-template-columns: 1fr; /* 默认 1 列 */
  }
  .card {
    background: #fff;
    padding: 16px;
  }
 

   /* sm: 2 列 */
  @media (min-width: 576px) {
    .grid {
      grid-template-columns: repeat(2, 1fr);
    }
  }
   /* md: 3 列 */
  @media (min-width: 960px) {
    .grid {
      grid-template-columns: repeat(3, 1fr);
    }
  }
   /* lg: 4 列 */
  @media (min-width: 1200px) {
    .grid {
      grid-template-columns: repeat(4, 1fr);
    }
  }

上面的 grid 方案,我们可以用便利更语义化的方式实现自适应卡片布局,但这种方案仍然强耦合于媒体查询断点。那么有没有更简单的方式来实现,有的兄弟,有的:

.card-container {
  display: grid;
  gap: 16px;
  grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
}
.card {
  background: #fff;
  padding: 16px;
}

关注到上面代码的 grid-template-columns 实现,我们可以对其功能做如下解释:

在网格容器中尽可能多地放入宽度至少 320px、最多按可用空间平分(1fr)的列;当容器变窄时列会自动减少列数(换行),当列数大于网格项数量时会保留空列,网格项之间间隔为 16px。

很先进兄弟,很先进。简单的三行代码即可原生实现自适应宽度的卡片列表布局, 且不依赖于媒体查询断点。而且 grid 布局对 2022 年来说兼容性相当好了,很推荐大家使用。

auto-fill vs auto-fit

/* auto-fill:空列保留,项目可能被压缩成更小宽度 */
.grid-fill { grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); }

/* auto-fit:空列折叠,现有项目会扩展填满整行 */
.grid-fit  { grid-template-columns: repeat(auto-fit,  minmax(320px, 1fr)); }