You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何创建响应式完美矩形网格?解决半步网格布局异常

可用演示

以下是CSS实现响应式完美矩形网格的演示,无论屏幕宽度如何,网格始终保持完美矩形。

body {
  max-width: 900px;
}

.grid-1 {
  display: grid;
  grid-template-columns: repeat(auto-fill, 100px);
  gap: 5px;
  max-width: 100%;
  width: fit-content;
  overflow: hidden;
}

.grid-1>* {
  background-color: green;
  width: 100px;
  height: 100px;
}

.grid-2 {
  display: grid;
  grid-template-columns: repeat(auto-fill, 100px);
  gap: 5px;
  width: 1000px;
}

.grid-2>* {
  background-color: red;
  width: 100px;
  height: 100px;
}
<div class="grid-1">
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div class="grid-2">
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
  </div>
</div>

无网格溢出效果

异常演示

当把行列尺寸设为原尺寸的1/2,并让网格项占据2行2列时,问题出现了:特定窗口宽度会导致网格最后一项变成半宽单元格,破坏完美矩形。

body {
  max-width: 900px;
}

.grid-1 {
  display: grid;
  grid-template-columns: repeat(auto-fill, 50px);
  grid-template-rows: repeat(auto-fill, 50px);
  gap: 5px;
  max-width: 100%;
  width: fit-content;
  overflow: hidden;
}

.grid-1>* {
  background-color: green;
  width: 100px;
  height: 100px;
  grid-column: span 2;
  grid-row: span 2;
}

.grid-2 {
  display: grid;
  grid-template-columns: repeat(auto-fill, 100px);
  gap: 10px;
  width: 1000px;
}

.grid-2>* {
  background-color: red;
  width: 100px;
  height: 100px;
}
<div class="grid-1">
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div class="grid-2">
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
  </div>
</div>

网格溢出异常

使用这种方法时,半数情况下整体网格的最后一项会变成半宽红色网格项。需要找到纯CSS方案消除该问题,实现半步网格下的响应式完美矩形,同时保留所有半列、不限制列数为2N。

补充演示说明

以下是更详细的演示,说明为何需要半步网格:希望右上角的tile与其他tile之间有可见间隙,通过半步网格可以减小间隙尺寸,同时不牺牲绿色/红色tile可填充的额外列数。

:root {
    --grid-gap: 0.4rem;
    --grid-division: 2; /*Integer*/
    --tile-base-size: 9.5rem;
    --tile-size: calc(
        var(--tile-base-size) - (
            (var(--grid-division) - 1) 
            * var(--grid-gap)
        )
    );
}

.overlay {
    grid-column-start: calc(-1 - var(--grid-division));
    grid-column-end: -1;
    grid-row-start: 1;
    grid-row-end: calc(1 + var(--grid-division));
    background-color: blue;
}

.filler {
    grid-column-start: calc(-2 - var(--grid-division));
    grid-column-end: -1;
    grid-row-start: 1;
    grid-row-end: calc(1 + 2 * var(--grid-division));
}

body {
    max-width: 900px;
}

.grid-1 {
    display: grid;
    grid-template-columns: repeat(auto-fill, calc(var(--tile-size)/var(--grid-division)));
    gap: var(--grid-gap);
    max-width: 100%;
    width: fit-content;
    overflow: hidden;
    margin: 0 auto;
}

.tile {
    background-color: green;
    width: var(--tile-base-size);
    height: auto;
    aspect-ratio: 1;
    grid-column: span var(--grid-division);
    grid-row: span var(--grid-division);
}

.grid-2 {
    display: inline-grid;
    grid-template-columns: repeat(auto-fill, calc(var(--tile-base-size)));
    column-gap: calc(var(--grid-gap));
    justify-content: start;
    width: 1000px;
    height: var(--tile-base-size);
    grid-row: span var(--grid-division);
    overflow: hidden;
}

.grid-2 > * {
    background-color: red;
    width: 100%;
    height: auto;
    aspect-ratio: 1;
}
<div class="grid-1">
    <div class="tile"></div>
    <div class="tile"></div>
    <div class="tile"></div>
    <div class="tile"></div>
    <div class="tile"></div>
    <div class="tile"></div>
    <div class="tile"></div>
    <div class="tile"></div>
    <div class="tile"></div>
    <div class="tile"></div>
    <div class="tile"></div>
    <div class="tile"></div>
    <div class="tile"></div>
    <div class="tile"></div>
    <div class="tile"></div>
    <div class="tile"></div>
    <div class="grid-2">
        <div></div>
        <div></div>
        <div></div>
        <div></div>
        <div></div>
        <div></div>
        <div></div>
        <div></div>
    </div>
    <div class="filler"></div>
    <div class="overlay"></div>
</div>

解决方案

核心问题是固定宽度设置导致tile在列数不足时被挤压,以及嵌套网格的宽度计算冲突。通过以下纯CSS调整可解决:

  1. 移除固定宽度,依赖Grid布局控制尺寸
    去掉tile的width属性,完全通过grid-column: span var(--grid-division)和aspect-ratio:1保证正方形和正确宽度,避免固定宽度导致的挤压变形。

  2. 优化嵌套网格的宽度控制
    不给嵌套网格设置固定宽度,而是通过grid-column: span X让它占据父网格中指定数量的半列,确保内部tile能完整排列。

  3. 调整变量计算逻辑
    重新计算基础列宽,确保var(--grid-division)个基础列加上间隙的总宽度等于var(--tile-base-size):

    --tile-column-width: calc((var(--tile-base-size) - (var(--grid-division) - 1)*var(--grid-gap)) / var(--grid-division));
    

修改后的完整代码:

:root {
    --grid-gap: 0.4rem;
    --grid-division: 2; /* 可调整的整数分割数 */
    --tile-base-size: 9.5rem;
    /* 计算基础列宽:确保N个列+N-1个间隙= tile基础尺寸 */
    --tile-column-width: calc((var(--tile-base-size) - (var(--grid-division) - 1)*var(--grid-gap)) / var(--grid-division));
}

.overlay {
    grid-column: span var(--grid-division) / -1;
    grid-row: 1 / span var(--grid-division);
    background-color: blue;
}

.filler {
    grid-column: span calc(2*var(--grid-division)) / -1;
    grid-row: 1 / span calc(2*var(--grid-division));
}

body {
    max-width: 900px;
}

.grid-1 {
    display: grid;
    grid-template-columns: repeat(auto-fill, var(--tile-column-width));
    gap: var(--grid-gap);
    max-width: 100%;
    width: fit-content;
    overflow: hidden;
    margin: 0 auto;
}

.tile {
    background-color: green;
    aspect-ratio: 1;
    grid-column: span var(--grid-division);
    grid-row: span var(--grid-division);
}

.grid-2 {
    display: grid;
    grid-template-columns: repeat(auto-fill, var(--tile-base-size));
    gap: var(--grid-gap);
    /* 让嵌套网格占据4个半列(即2个完整tile宽度) */
    grid-column: span calc(2*var(--grid-division));
    grid-row: span var(--grid-division);
}

.grid-2 > * {
    background-color: red;
    aspect-ratio: 1;
}
<div class="grid-1">
    <div class="tile"></div>
    <div class="tile"></div>
    <div class="tile"></div>
    <div class="tile"></div>
    <div class="tile"></div>
    <div class="tile"></div>
    <div class="tile"></div>
    <div class="tile"></div>
    <div class="tile"></div>
    <div class="tile"></div>
    <div class="tile"></div>
    <div class="tile"></div>
    <div class="tile"></div>
    <div class="tile"></div>
    <div class="tile"></div>
    <div class="tile"></div>
    <div class="grid-2">
        <div></div>
        <div></div>
        <div></div>
        <div></div>
    </div>
    <div class="filler"></div>
    <div class="overlay"></div>
</div>

调整后,无论屏幕宽度如何变化,tile都会保持完整的正方形,不会出现半宽情况,同时保留了半列布局的灵活性,可继续使用overlay等元素占据半列空间。

内容的提问来源于stack exchange,提问作者thenickman100

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 19:05:54