Search code examples
csscss-grid

CSS-Grid: Stretch main if sidebar is empty


I've got little styling issues with a simple grid layout, containing a sidebar (aside) and some main content.

<body>
  <header>Header</header>
  <nav>Navigation Links</nav>
  <aside>Sidebar</aside>
  <main>Some main content</main>
  <footer>Footer</footer>
</body>

On some pages there is no aside included in my html:

<body>
  <header>Header</header>
  <nav>Navigation Links</nav>

  <main>Some main content</main>
  <footer>Footer</footer>
</body>

Here is my code

body {
  height: 100%;
  display: grid;
  /* mobile layout */
  grid-template: auto auto auto 1fr auto / 1fr;
  grid-template-areas:
    "header"
    "nav"
    "aside"
    "main"
    "footer";
}

header {
  background-color: blue;
  grid-area: header;
}

nav {
  background-color: aquamarine;
  grid-area: nav;
}

aside {
  background-color: green;
  grid-area: aside;
}

main {
  background-color: yellow;
  grid-area: main;
}

footer {
  background-color: orange;
  grid-area: footer;
}

/* desktop layout */
@media (min-width: 768px) {
  body {
    grid-template: auto auto 1fr auto / minmax(300px, 25%) 1fr;
    grid-template-areas:
      "header header"
      "nav nav"
      "aside main"
      "footer footer";
  }
}
<body>
  <header>Header</header>
  <nav>Navigation Links</nav>
  <!-- if aside is deleted main should strech whole space-->
  <aside>Sidebar</aside>
  <main>Some main content</main>
  <footer>Footer</footer>
</body>

If the sidebar is displayed, it should have a minimum width of 300px. If sidebar is not displayed main content should take the whole width. However its not possible, its still taking only 75% of the width (25% are max for aside).

Some solutions i thought about:

  1. If no aside is displayed, I could adjust grid-template to use only one grid column:
    grid-template: auto auto auto 1fr auto / 1fr;
    
    However, I do not know how accomplish this with CSS. :has selector is still working draft.
  2. Set width for first grid column to 0.
    grid-template: auto auto 1fr auto / 0 1fr;
    
    However, how can I override this setting if aside is displayed?

Thanks for your help!


Solution

  • Define the width inside the aside element and keep auto in the template. Since you are dealing with a full width/height grid, you can consider the use of 25vw instead of 25%.

    You have to aslo consider the mobile layout and correctly place both main and footer

    body {
      height: 100vh;
      margin: 0;
      display: grid;
      grid-template: auto auto auto 1fr auto / 1fr;
    }
    
    header { background-color: blue;}
    nav { background-color: aquamarine;}
    aside { background-color: green;}
    main { background-color: yellow;grid-row:4}
    footer { background-color: orange;grid-row:5}
    
    /* desktop layout */
    
    @media (min-width: 768px) {
      body {
        grid-template: auto auto 1fr auto / auto 1fr;
        grid-template-areas: "header header" "nav nav" "aside main" "footer footer";
      }
      aside {
        width: min(300px, 25vw);
      }
      header { grid-area: header;}
      nav { grid-area: nav; }
      aside { grid-area: aside;}
      main { grid-area: main;}
      footer {grid-area: footer;}
    }
    <body>
      <header>Header</header>
      <nav>Navigation Links</nav>
      <!-- if aside is deleted main should strech whole space-->
      <aside>Sidebar</aside>
      <main>Some main content</main>
      <footer>Footer</footer>
    </body>