3

I have a number of div elements:

<main>
    <div id="top">Top</div>
    <div id="left">Left</div>
    <div id="right">Right</div>
</main>

which I would like to show in a grid:

┌─────────────────┐
│ Top             │
╞══════╤══════════╡
│ Left │ Right    │
└──────┴──────────┘

I would like to be able to hide one element and have the other fill its space.

┌─────────────────┐
│ Top             │
╞═════════════════╡
│ Right           │
└─────────────────┘

The columns are not evenly spaced. I have used the following CSS for the main and div#top elements:

main {
    display: grid;
    grid-template-rows: 3em 1fr;
    grid-template-columns: 120px 1fr;
    border: medium solid #333;
}
div#top {
    grid-column: 1/3;
}

The problem is that when I hide the first div using display: none, the second one only occupies the original space of the first one.

How can I convince the second div to take up the whole row?

The snippet below illustrates the point.

Note: The question at Make div fill up entire CSS grid's row when the other part is not available asks something similar, but solution doesn’t work in my case. This is because my Left div has a set width.

var left = document.querySelector('div#left');
var right = document.querySelector('div#right');

right.addEventListener('click', function(e) {
  left.style.display = left.style.display == 'none' ? 'block' : 'none';
});
main {
  display: grid;
  grid-template-rows: 3em 1fr;
  grid-template-columns: 120px 1fr;
  border: medium solid #333;
}

div#top, div#left, div#right {
  border: medium solid #999;
  background-color: #f8f8f8;
  margin: 4px;
  font-family: sans-serif;
  padding: .5em;
}
div#top {
  grid-column: 1/3;
}
div#left {

}
div#right {
  
}
<main>
  <div id="top">Top</div>
  <div id="left">Left</div>
  <div id="right">Right: Click to Toggle Left</div>
</main>
Manngo
  • 14,066
  • 10
  • 88
  • 110

2 Answers2

0

Is the JS just for the demo? On click, where the left element is set to display: none, why not also set the right element to grid-column: 1 / 3?

If that's not an option, then try flexbox, which can handle the situation cleanly and easily.

var left = document.querySelector('div#left');
var right = document.querySelector('div#right');

right.addEventListener('click', function(e) {
  left.style.display = left.style.display == 'none' ? 'block' : 'none';
});
main {
  display: flex;
  flex-wrap: wrap;
  border: medium solid #333;
}

div#top {
  flex: 1 0 90%; /* to allow space for margins; see note below */
}

div#left {
  flex: 0 0 120px; /* flex-grow, flex-shrink, flex-basis */
}

div#right {
  flex: 1; /* fg:1, fs:1, fb:0 */
}

main > div {
  border: medium solid #999;
  background-color: #f8f8f8;
  margin: 4px;
  font-family: sans-serif;
  padding: .5em;
}
<main>
  <div id="top">Top</div>
  <div id="left">Left</div>
  <div id="right">Right: Click to Toggle Left</div>
</main>

More Information

Here's an explanation for flex: 1 0 90%:

Here's an explanation for the problem you're encountering with Grid:

Michael Benjamin
  • 346,931
  • 104
  • 581
  • 701
0

Use display:flex

var right = document.querySelector('div#right');

right.addEventListener('click', function(e) {
   var left = document.querySelector('div#left');
   var shown= !(left.style.display == 'none') ;
   if ( !shown ) {
     left.style.display = 'block';
   } else {
     left.style.display = 'none';
   }
});
main {
  grid-template-rows: 3em 1fr;
  grid-template-columns: 120px 1fr;
  border: medium solid #666;
}

div#top, div#left, div#right {
  border: medium solid transparent;
  box-shadow: inset 0px 0px 0px 4px #AAA;
  background-color: #f8f8f8;
  font-family: sans-serif;
  padding: 1em;
}
div#top {
  grid-column: 1/3;
}
div#left {
  width: 33%;
  float: left;
}
div#right {
  display: flex;
}
<main>
  <div id="top">Top</div>
  <div id="left">Left</div>
  <div id="right">Right: Click to Toggle Left</div>
</main>