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

如何让Grid布局容器自动填充侧边栏折叠后腾出的空间?

问题

我在外层2×2的CSS Grid布局中混合使用了Grid与Flexbox:左下角是包含2×2 Grid的可折叠侧边栏,右下角是3×2 Grid布局的主容器。当侧边栏完全向左折叠后,希望主容器能向左拉伸占据腾出的空间,同时自动调整内部元素大小,但目前实现不了。我知道main容器上的flex-grow:1无效,但不知道正确的解决方法。

现有代码

HTML

<html>
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" />
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.2/css/all.min.css" crossorigin="anonymous">
  <link rel="stylesheet" type="text/css" href="styles.css" />
</head>
<body class="body">
  <section class="logo">
    <img class="img" src="../static/images/logo.png">
  </section>
  <header class="header">
    <div class="head-card"><span class="notification">[ some msg ]</span></div>
    <div class="head-card">
    </div>
  </header>

  <!-- Collapsible Side Nav bar for menus -->
  <section id="aside" class="side-bar">
    <div class="side-card">
      <div class='accord-button'>
        <input type='checkbox' id='accordianinput'>
        <label for='accordianinput'>
            <i class="fa-solid fa-arrow-circle-left not-active"></i>
            <i class="fa-solid fa-arrow-circle-right active"></i>
          </label>
      </div>
    </div>
    <div class="side-card">
      <ul class="nav">
        <li><button type="button" class="menu-button" onclick="#">Home</button></li>
        <li><button type="button" class="menu-button" onclick="#">About</button></li>
      </ul>
    </div>
    <div class="side-card">
      <span class="long-copyright">&copy; Runaway Company, Inc.</span>
      <span class="short-copyright">&copy;RC</span>
    </div>
  </section>

  <main class="main">
    <div class="card">
    </div>
    <div class="card">
    </div>
    <div class="card">
    </div>
    <div class="card">
    </div>
    <div class="card">
    </div>
    <div class="card">
    </div>
  </main>
</body>
</html>

CSS

* {
  box-sizing: border-box;
}

.body {
  height: 100vh;
  width: 100vw;
  margin: 0;
  display: grid;
  grid-template-columns: 20% 1fr;
  grid-template-rows: 10% 1fr;
  grid-template-areas: "logo head" "side main";
}

.logo {
  background-color: #fff;
  grid-area: logo;
  display: flex;
  flex-flow: row nowrap;
  justify-content: flex-start;
  align-content: center;
}

.img {
  height: 100%;
  object-fit: cover;
}

.header {
  background-color: #fff;
  padding: 0.3rem;
  grid-area: head;
  display: grid;
  grid-template-columns: 2fr 1fr;
  grid-template-rows: 1fr;
  grid-template-areas: "msg regoraccess";
  gap: 0.5em;
}

.head-card {
  border-radius: .25rem;
  display: flex;
  flex-flow: row wrap;
  justify-content: center;
  align-content: center;
}

.head-card:nth-child(1) {
  grid-area: msg;
}

.notification {
  text-align: center;
  margin: 0;
}

.head-card:nth-child(2) {
  grid-area: regoraccess;
  display: flex;
  flex-flow: row wrap;
  justify-content: flex-end;
  align-content: center;
}

.side-bar {
  background-color: #1c1f23;
  padding: 0.1rem 0 0.1rem 0.1rem;
  grid-area: side;
  display: grid;
  grid-template-columns: 0.05fr 0.95fr;
  grid-template-rows: 0.9fr 0.1fr;
  grid-template-areas: "collapse menu" "rc rc";
}

.side-card {
  display: flex;
}

.side-card:nth-child(1) {
  grid-area: collapse;
  display: flex;
  flex-flow: row wrap;
  justify-content: flex-end;
  align-content: center;
}

.fa-solid {
  color: #3DED97;
}

.accord-button>input {
  display: none;
}

.accord-button>input:checked+label .not-active {
  display: none;
}

.accord-button>input:not(:checked)+label .active {
  display: none;
}

.side-card:nth-child(2) {
  grid-area: menu;
  display: flex;
  flex-flow: column wrap;
  justify-content: flex-start;
  align-content: flex-start;
  transition: width 300ms;
}

.nav {
  display: flex;
  flex-flow: column wrap;
  padding: 1rem;
  gap: 1rem;
}

.nav li {
  display: flex;
}

.menu-button {
  background: transparent;
  border: 0;
  color: white;
}

body:has(.accord-button > input:checked) {
  #aside {
    width: 1em;
  }
  .side-card:nth-child(2) {
    display: none;
  }
  .side-card:nth-child(3) {
    width: 1em;
  }
  .long-copyright {
    display: none;
  }
}

body:has(.accord-button > input:not(:checked)) {
  .short-copyright {
    display: none
  }
}

.side-card:nth-child(3) {
  grid-area: rc;
  display: inline-flex;
  flex-flow: row wrap;
  justify-content: flex-start;
  align-content: flex-end;
}

.long-copyright {
  color: #D3D3D3;
  font-size: 1rem;
}

.short-copyright {
  color: #D3D3D3;
  font-size: 0.5rem;
}

.main {
  background-color: #c3c5ca;
  padding: 0.5rem;
  grid-area: main;
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  grid-template-rows: 1fr 1fr 1fr;
  grid-template-areas: "col-1 col-2 col-3" "col-4 col-4 col-5" "col-4 col-4 col-6";
  gap: 1em;
  flex-grow: 1; /* 无效属性 */
}

.card {
  background-color: #f6f7f9;
  border-radius: 1rem;
}

.card:nth-child(1) {
  grid-area: col-1;
}

.card:nth-child(2) {
  grid-area: col-2;
}

.card:nth-child(3) {
  grid-area: col-3;
}

.card:nth-child(4) {
  grid-area: col-4;
}

.card:nth-child(5) {
  grid-area: col-5;
}

.card:nth-child(6) {
  grid-area: col-6;
}

@media (max-width: 900px) {
  .main {
    grid-template-columns: 1fr;
    grid-template-rows: repeat(6, 1fr);
    grid-template-areas: initial;
  }
  .card {
    grid-area: initial !important;
  }
}
解决方案

问题核心是外层Grid的列宽度是固定的20% 1fr,侧边栏折叠时只是修改自身宽度,但外层Grid的列定义没变化,所以主容器无法扩展。只需要修改外层Grid的列规则,配合:has()选择器实现折叠时的布局调整:

修改步骤

  1. 给外层Grid添加过渡动画,让布局变化更平滑
  2. 折叠状态下重写外层Grid的列宽,把侧边栏列设为min-content(仅占内容所需最小宽度),主容器列保持1fr占据剩余空间
  3. 移除main上无效的flex-grow:1,Grid容器的子元素是Grid项,该属性完全无效
  4. 调整侧边栏折叠时的自身样式,让宽度自适应内容,避免固定宽度导致的布局错位

修改后的关键CSS代码

/* 修改外层Grid,添加过渡动画 */
.body {
  height: 100vh;
  width: 100vw;
  margin: 0;
  display: grid;
  grid-template-columns: 20% 1fr;
  grid-template-rows: 10% 1fr;
  grid-template-areas: "logo head" "side main";
  transition: grid-template-columns 300ms; /* 新增:平滑过渡 */
}

/* 折叠状态下修改外层Grid列宽 */
body:has(.accord-button > input:checked) .body {
  grid-template-columns: min-content 1fr; /* 侧边栏列仅占内容宽度 */
}

/* 移除main上的无效属性 */
.main {
  background-color: #c3c5ca;
  padding: 0.5rem;
  grid-area: main;
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  grid-template-rows: 1fr 1fr 1fr;
  grid-template-areas: "col-1 col-2 col-3" "col-4 col-4 col-5" "col-4 col-4 col-6";
  gap: 1em;
  /* flex-grow: 1; 删掉这行 */
}

/* 调整侧边栏折叠时的样式 */
body:has(.accord-button > input:checked) {
  #aside {
    width: auto; /* 改为自适应内容 */
  }
  .side-card:nth-child(2) {
    display: none;
  }
  .side-card:nth-child(3) {
    width: auto; /* 改为自适应内容 */
  }
  .long-copyright {
    display: none;
  }
}

原理说明

  • 外层Grid的列定义是控制整体布局的核心,折叠时修改grid-template-columns,让侧边栏列只占按钮的宽度,主容器列自动填充剩余空间
  • min-content会根据侧边栏内的折叠按钮宽度自动调整,避免固定宽度导致的适配问题
  • Grid布局中,1fr会自动分配剩余空间,所以主容器会自然拉伸,内部的Grid项也会跟着自动调整大小

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 19:57:02