CSS-Grid: Stretch main if sidebar is empty

Viewed 317

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!

2 Answers

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>

Use fit-content() and specify a min-width for aside:

body {
  margin: 0;
  min-height: 100vh;
}

.grid {
  height: 100vh;
  display: grid;
  /* mobile layout */
  grid-template-columns: 1fr;
  grid-template-rows: repeat(3, auto) 1fr auto;
  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;
  min-width: 300px;
}

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

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


/* desktop layout */

@media (min-width: 768px) {
  .grid {
    grid-template-columns: fit-content(300px) 1fr;
    grid-template-rows: repeat(2, auto) 1fr auto;
    grid-template-areas: 
      "header header"
      "nav nav"
      "aside main"
      "footer footer";
  }
}
<div class="grid">
  <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>
</div>

<div class="grid">
  <header>Header</header>
  <nav>Navigation Links</nav>
  <main>Some main content</main>
  <footer>Footer</footer>
</div>

Related