Search code examples
htmlcssflexboxcss-grid

Unable to make a grid layout container auto stretch to fill collapsed space created by adjacent in-row container


I have a mix of CSS Grid and Flexbox within a nested layout. The outer layout is a 2x2 CSS Grid. Each grid container there will either contain another Grid layout or some flexbox components.

The bottom-left container of the outer grid, is a collapsible sidebar containing a 2x2 grid and the bottom-right container has a 3x2 grid.

When I collapse the entire bottom-left container to the left, I want the bottom-right container to stretch left and occupy the vacated space. In the process it should automatically resize it's contained elements. Unfortunately I am unable to make it happen.

* {
  box-sizing: border-box;
  /* this is also essential to avoid a world of width-based pain */
}

.body {
  height: 100vh;
  width: 100vw;
  margin: 0;
  /* negates the default 8px margins */
  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: flex;
  flex-flow: row nowrap;
  justify-content: center;
  align-content: center;
  display: grid;
  /* nested grid inside the header */
  grid-template-columns: 2fr 1fr;
  /* define 3 equal columns each taking same fraction of the space */
  grid-template-rows: 1fr;
  /* there's only one row; so take all the available space */
  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;
}


/* place each of the six cards in their respective areas */

.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: flex;
  flex-flow: row nowrap;
  align-content: flex-start;
  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;
}


/*
    nth-child(1): Collapse button
    nth-child(2): Menu
    nth-child(3): Copyright
*/

.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;
  /* Seafoam Color */
}

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

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

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


/* the menu */

.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
  }
}


/* copyright */

.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;
  /* light-gray */
  font-size: 1rem;
}

.short-copyright {
  color: #D3D3D3;
  /* light-gray */
  font-size: 0.5rem;
}


/* the main engagement area */

.main {
  background-color: #c3c5ca;
  padding: 0.5rem;
  /* padding all around the main container */
  grid-area: main;
  display: grid;
  /* nested grid inside the main */
  grid-template-columns: 1fr 1fr 1fr;
  /* define 3 equal columns each taking same fraction of the space */
  grid-template-rows: 1fr 1fr 1fr;
  /* define 3 equal rows each taking same fraction of available space */
  grid-template-areas: "col-1 col-2 col-3" "col-4 col-4 col-5" "col-4 col-4 col-6";
  gap: 1em;
  /* gap between the rows and the columns */
  flex-grow: 1;
  /* <== will not work here because of the Display: Grid on Parent */
}

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


/* place each of the six cards in their respective areas */

.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 queries */

@media (max-width: 900px) {
  .main {
    grid-template-columns: 1fr;
    grid-template-rows: repeat(6, 1fr);
    grid-template-areas: initial;
  }
  .card {
    grid-area: initial !important;
  }
}
<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/[email protected]/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>

I know the "flex-grow: 1" will not work on the 'main' container but not sure how to go about it. Can anyone please show me the right way?


Solution

  • If you want the sidebar to collapse, I wouldn’t use a 2x2 grid on the body. Make the body just a single column with two rows (1x2). The first row will contain your header, and the second row will contain the sidebar and your main panel.

    Format each row using flexbox. For the header row, use justify-content: space-between. The second row will pretty much look after itself.

    Make sure you use the full page link after running this snippet.

    * {
      box-sizing: border-box;
    }
    
    body, html {
      height: 100vh;
    }
    
    body {
      margin: 0;
      display: grid;
      grid-template-rows: auto 1fr;
    }
    
    header {
      background-color: #fff;
      padding: 0.3rem;
      display: flex;
      justify-content: space-between;
      align-items: center;
      gap: 0.5em;
    }
    
    main {
      display: flex;
    }
    
    .side-bar {
      background-color: #1c1f23;
      padding: 0.1rem 0 0.1rem 0.1rem;
      grid-area: side;
      display: flex;
      flex-flow: row nowrap;
      align-content: flex-start;
      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;
    }
    
    
    /*
        nth-child(1): Collapse button
        nth-child(2): Menu
        nth-child(3): Copyright
    */
    
    .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;
      /* Seafoam Color */
    }
    
    .accord-button>input {
      display: none;
    }
    
    .accord-button>input:checked+label .not-active {
      display: none;
    }
    
    .accord-button>input:not(:checked)+label .active {
      display: none;
    }
    
    
    /* the menu */
    
    .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
      }
    }
    
    
    /* copyright */
    
    .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;
      /* light-gray */
      font-size: 1rem;
    }
    
    .short-copyright {
      color: #D3D3D3;
      /* light-gray */
      font-size: 0.5rem;
    }
    
    
    /* the main engagement area */
    
    .mainpanel {
      background-color: #c3c5ca;
      padding: 0.5rem;
      /* padding all around the main container */
      grid-area: main;
      display: grid;
      /* nested grid inside the main */
      grid-template-columns: 1fr 1fr 1fr;
      /* define 3 equal columns each taking same fraction of the space */
      grid-template-rows: 1fr 1fr 1fr;
      /* define 3 equal rows each taking same fraction of available space */
      grid-template-areas: "col-1 col-2 col-3" "col-4 col-4 col-5" "col-4 col-4 col-6";
      gap: 1em;
      /* gap between the rows and the columns */
      flex-grow: 1;
      /* <== will not work here because of the Display: Grid on Parent */
    }
    
    .card {
      background-color: #f6f7f9;
      border-radius: 1rem;
    }
    
    
    /* place each of the six cards in their respective areas */
    
    .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 queries */
    
    @media (max-width: 900px) {
      .mainpanel {
        grid-template-columns: 1fr;
        grid-template-rows: repeat(6, 1fr);
        grid-template-areas: initial;
      }
      .card {
        grid-area: initial !important;
      }
    }
    <link href="https://cdn.jsdelivr.net/npm/[email protected]/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">
    
    <header>
      <img class="logo" src="https://picsum.photos/80/40">
      <div>header centre</div>
      <div>header right</div>
    </header>
    
    <main>
    
      <nav 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>
      </nav>
    
      <div class="mainpanel">
        <div class="card">
        </div>
        <div class="card">
        </div>
        <div class="card">
        </div>
        <div class="card">
        </div>
        <div class="card">
        </div>
        <div class="card">
        </div>
      </div>
    
    </main>