Search code examples
htmlcssvue.jsvue-componentcss-grid

How to account for dynamic rows in a CSS Grid setup?


My home dashboard has a general structure of div elements piled one on top of each other (each of them is screen-wide and provides different kind of information).

I manage the height of the blocks though CSS Grid: the whole application is min-height: 100vh; and the rows are auto except for one which is 1fr. It works great.

I am now faced with the case where one of the lines is dynamically present or absent. This is because it is actually a Vue component, displayed conditionally with v-if. The problem is that the CSS part is not aware of its presence and grid-template-rows is fixed. This leads to the wrong rows being auto and 1fr when it is toggled.

How to fix that?

One way I can think of would be to force the presence of the component in a way where CSS would count it as a row. Right now I see this element as <!----> == $0 in Dev Tools when it is off.

Another one would be to "describe" the columns template rather than have a fixed list. Something along the lines of "use auto as much as possible, then 1fr and one auto"


The two code fragments below simulate my problem.

The first one is the case where all elements are visible

#app {
  display: grid;
  min-height: 100vh;
  grid-template-rows: auto auto 1fr;
}

#footer {
  align-self: end;
}

div {
  border-style: dashed;
  border-width: 1px;
}
<div id="app">
  <div>this line is always visible</div>
  <div>this one is toggled - here it is visible</div>
  <div id="footer">this is the footer</div>
</div>

The one below is the same code, but with the second line toggled (commented out here, disabled via v-if in the real code). See how it affect the footer which is not at the bottom anymore because the CSS has not changed (= did not adapt to a dissapearing row)

#app {
  display: grid;
  min-height: 100vh;
  grid-template-rows: auto auto 1fr;
}

#footer {
  align-self: end;
}

div {
  border-style: dashed;
  border-width: 1px;
}
<div id="app">
  <div>this line is always visible</div>
  <!-- <div>this one is toggled - here it is not visible anymore </div> -->
  <div id="footer">this is the footer</div>
</div>


Solution

  • One idea is to explicitely define the row for the footer to always use the last one:

    #app {
      display: grid;
      min-height: 100vh;
      grid-template-rows: auto auto 1fr;
    }
    
    #footer {
      align-self: end;
      grid-row:-1;
    }
    
    div {
      border-style: dashed;
      border-width: 1px;
    }
    <div id="app">
      <div>this line is always visible</div>
      <div>this one is toggled - here it is visible</div>
      <div id="footer">this is the footer</div>
    </div>
    
    <div id="app">
      <div>this line is always visible</div>
      <!--<div>this one is toggled - here it is visible</div>-->
      <div id="footer">this is the footer</div>
    </div>