I know there are similar questions but this is specifically asking how to do this using CSS Grid Layout.
So we have this basic grid setup:
HTML (with sidebar):
<div class="grid">
<div class="content">
<p>content</p>
</div>
<div class="sidebar">
<p>sidebar</p>
</div>
</div>
CSS:
.grid {
display: grid;
grid-template-columns: 1fr 200px;
}
To create a layout that looks something like this:
| content | sidebar |
If the page doesn't have a sidebar though, ie. the html looks like this but with the same CSS:
HTML (no sidebar):
<div class="grid">
<div class="content">
<p>content</p>
</div>
</div>
The page layout looks like this (dashes represent empty space)
| content | ------- |
I know why it does that, the grid column is still defined in the grid-template-columns
rule.
I'm just wondering how to tell the grid that if there is no content, then fill the remaining space similar to how flex-grow
works for flexbox
.
The desired result would look like this if no sidebar is present.
| content |
I think I know the definitive answer to this question now. The problem with the answers so far is that they don't explain how to handle a sidebar that is on the left side of the main content (mainly because I didn't ask for it in the original question).
<div class="grid">
<nav>
<p>navigation</p>
</nav>
<main>
<p>content</p>
</main>
<aside>
<p>sidebar</p>
</aside>
</div>
You can use this CSS:
.grid {
display: grid;
grid-template-columns: fit-content(200px) 1fr fit-content(200px);
}
nav, aside {
width: 100%;
}
/* ensures that the content will always be placed in the correct column */
nav { grid-column: 1; }
main { grid-column: 2; }
aside { grid-column: 3; }
This is also a good use case for grid-areas
.grid {
display: grid;
grid-template-columns: fit-content(200px) 1fr fit-content(200px);
grid-template-areas: "nav content sidebar";
}
nav, aside {
width: 100%;
}
/* ensures that the content will always be placed in the correct column */
nav { grid-area: nav; }
main { grid-area: content; }
aside { grid-area: sidebar; }
An IE compatible version would look like this:
.grid {
display: -ms-grid;
display: grid;
-ms-grid-columns: auto 1fr auto;
grid-template-columns: auto 1fr auto;
}
nav, aside {
width: 100%; /* Ensures that if the content exists, it takes up max-width */
max-width: 200px; /* Prevents the content exceeding 200px in width */
}
/* ensures that the content will always be placed in the correct column */
nav {
-ms-grid-column: 1;
grid-column: 1;
}
main {
-ms-grid-column: 2;
grid-column: 2;
}
aside {
-ms-grid-column: 3;
grid-column: 3;
}
You can get closer by using content sizing keywords, something like:
.grid {
display: grid;
grid-template-columns: 1fr fit-content(200px);
}
.sidebar {
width: 100%;
}
The fit-content
keyword will look at the size of the content and act like max-content
until it gets to the value you pass in.
In reality you probably wouldn't need to stick a size on sidebar as the content is likely to dictate a size of at least 200 pixels (for example) but you can play around with this.
Don't define the columns explicitly with grid-template-columns
.
Make the columns implicit instead and then use grid-auto-columns
to define their widths.
This will allow the first column (.content
) to consume all space in the row when the second column (.sidebar
) doesn't exist.
.grid {
display: grid;
grid-auto-columns: 1fr 200px;
}
.content {
grid-column: 1;
}
.sidebar {
grid-column: 2;
}
.grid > * {
border: 1px dashed red; /* demo only */
}
<p>With side bar:</p>
<div class="grid">
<div class="content">
<p>content</p>
</div>
<div class="sidebar">
<p>sidebar</p>
</div>
</div>
<p>No side bar:</p>
<div class="grid">
<div class="content">
<p>content</p>
</div>
</div>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With