Search code examples
htmlcssflexboxhidden

How to make a flex-grow element take up the space of a hidden flex item?


I want the entire window divided into two or three areas - depending on the state of a checkbox. If the box is not checked I want the second area to be hidden while I want the first area to grow into this additional window space.

The way I set it up for larger screens (>640px) works perfectly fine: checked box large screens and unchecked box lange screens

For smaller screens, however, I run into trouble. Here the second area is placed in between area 1 and 3: checked box small screens

But once I uncheck the box, area 1 remains the same and does not grow into the space of the hidden area 2. Instead area 3 moves up and centers itself in the now available space (grey background): unchecked box small screens

I think I know why this happens but have not been able to come up with a solution yet.

As I used flex-direction: column for the wrapper the flex-grow:1 only works horizontally for the children. Therefore I at first tried to use flex-direction: row but that put the elements next to each other horizontally. Even if I tried to use flex-wrap:wrap while restricting the wrapper to the viewport width.

The grey space above and below area 3 seems to be the result of the height:20% of the hidden area 2. While I thought that using display:none would completely stop this height from being considered this seemed not to be the case. Therefore I secondly tried to use Javascript to change the height:20% of the hidden area 2 to 0% only if the box is unchecked and the screen-size is below the threshhold. But in the dev tools it looked like document.getElementById("hint").style.height="0%" did not change anything at all. But even if it did it seems like setting the height to 0% directly in the css wont solve my issue as the grey wrapper area still remains.

Here is my attemot of a reproducible example but I am not sure if it is minimal and of any help:

function visCheck (){
if (document.getElementById("hint").style.display=="block"){ document.getElementById("hint").style.display="none";
}
else if (document.getElementById("hint").style.display=="none"){
document.getElementById("hint").style.display="block";
}
else{   document.getElementById("hint").style.display="block";
}
}
*{
  box-sizing: border-box;
  }
body{
    margin: 0;
    height: 100vh;
    width: 100%;
}
main{
    height: 100%;
    box-sizing: border-box;
}
.maingrid-wrapper{
    box-sizing: border-box;
    display: flex;
    flex-direction: row;
    flex-wrap: wrap;
    position: relative;
    display: flex;
    width: 100%;
    height: 100%;
}
.maingrid-content{
/*   border: red solid; */
}
.image{
    flex:2 1 60%;
    flex-grow:2;
    height: 90%;
    background-color: lightblue;
}
.sidehint{
    background-color: lightgreen;
    flex:1 1 40%;
    height: 90%;
}

.footer-wrapper{
    background-color: lightpink;
    height:10%;
    width: 100%;
    display: flex;
    flex-direction: row;
}

@media all and (max-width: 640px){
    .maingrid-wrapper{
        box-sizing: border-box;
        display: flex;
        flex-direction: row;
        flex-wrap: wrap;
        position: relative;
        display: flex;
        width: 100%;
        height: 100%;
      background-color: lightgrey;
    }
    .maingrid-content{
/*         border: red solid; */
        box-sizing: border-box;
    }
    .image{
      height: 70%;
        flex:1 1 100%;
        flex-grow: 2;
        background-color:lightblue;
    }
    .sidehint{
        height: 20%;
        background-color: lightgreen;
    }
    
    .footer-wrapper{
        height:10%;
        width: 100%;
        display: flex;
        background-color: lightpink;
    }
}
<body>
  <main>
    <div class="maingrid-wrapper">
      <div class="image maingrid-content">A</div>
      <div class="sidehint maingrid-content"
           id="hint" style="display:none">B</div>
      <div class="footer-wrapper 
                  maingrid-content">
        <input class="bulb-input" id="hint-toggle"
               type="checkbox"
               onchange="visCheck()">C</div>
    </div>
  </main>
</body>


Solution

  • I cleaned up your CSS, which was bloated with redundancy, default values, and extraneous declarations.

    Your CSS would benefit from a "mobile first" approach where media queries are used to add styling as the viewport widens, instead of using media queries to overwrite the declarations for narrower viewports.

    function visCheck() {
    
      if (document.getElementById("hint").style.display=="block") {
        document.getElementById("hint").style.display="none";
      }
      else if (document.getElementById("hint").style.display=="none") {
        document.getElementById("hint").style.display="block";
      }
      else {
        document.getElementById("hint").style.display="block";
      }
    }
    * {
      box-sizing: border-box;
      }
      
    body {
      margin: 0;
      height: 100vh;
      }
      
    main{
      height: 100%;
      }
    
    .maingrid-wrapper{
      display: flex;
      flex-wrap: wrap;
      height: 100%;
      }
    
    .maingrid-content{
      /* border: red solid; */
      }
    
    .image{
      flex: 2;
      height: 90%;
      background-color: lightblue;
      }
    
    .sidehint{
      flex: 1;
      background-color: lightgreen;
      }
    
    .footer-wrapper{
      background-color: lightpink;
      height: 10%;
      width: 100%;
      }
    
    @media all and (max-width: 640px){
    
      .maingrid-wrapper{
        flex-direction: column;
        background-color: lightgrey;
        }
        
    }
    <body>
      <main>
        <div class="maingrid-wrapper">
          <div class="image maingrid-content">A</div>
          <div class="sidehint maingrid-content" id="hint" style="display:none">B</div>
          <div class="footer-wrapper maingrid-content">
            <input class="bulb-input" id="hint-toggle" type="checkbox" onchange="visCheck()">C</div>
        </div>
      </main>
    </body>