CSS grid: content to use free space but scroll when bigger

waterproof picture waterproof · Apr 11, 2017 · Viewed 22.9k times · Source

I've been working with CSS Grid Layouts for the first time and they're awesome. Right now, however, I'm having trouble keeping one of my grid cells under control.

What I want is to have an element that takes up the existing free space and no more, scrolling when the content gets too big. My understanding is that a grid size of 1fr takes up a uniform amount of the available space after everything else is calculated. I've tried various sizes such as minmax(auto, 1fr) but to no avail - 1fr seems to expand to fit the content which is not what I want. Setting a maximum size size like 100px is also no good because I want the size to be determined by other elements in the grid.

Here's the example:

What grid declaration (if any) can I use to let the "problem child" scroll on overflow rather than expanding?

Answer

G-Cyrillus picture G-Cyrillus · Apr 11, 2017

You can use max-height:100%; and also min-height to leave enough heights to show a proper scrollbar.(firefox will do, chrome will not at this time)

.container {
  display: grid;
  grid-template-rows: auto minmax(1fr, 25vh) auto;
  grid-template-columns: 1fr 1fr;
}

.container>div {
  border: 1px solid blue;
  border-radius: 5px;
}

.left {
  grid-column: 1;
  grid-row: 1/4;
}

.header {
  grid-column: 2;
  grid-row: 1;
}

.problem-child {
  grid-column: 2;
  grid-row: 2;
  min-height:4em;
  max-height:100%;
  overflow-y: auto;
}

.footer {
  grid-column: 2;
  grid-row: 3;
}
<div class="container">
  <div class="left">left<br>I don't want this one to scroll<br>this should<br>determine<br>the height of the whole grid container</div>
  <div class="header">column header</div>
  <div class="problem-child">problem child:<br>I<br>want<br>this<br>to<br>scroll<br>rather<br>than<br>making<br>everything<br>tall</div>
  <div class="footer">column footer</div>
</div>


As a work around, you can also use an extra wrapper in absolute position to take it off the flow and size it to the row's height: (both cases require a min-height to show properly the scrollbar when needed)

.container {
  display: grid;
  grid-template-rows: auto 1fr auto;
  grid-template-columns: 1fr 1fr;
}

.container>div {
  border: 1px solid blue;
  border-radius: 5px;
}

.left {
  grid-column: 1;
  grid-row: 1/4;
}

.header {
  grid-column: 2;
  grid-row: 1;
}

.problem-child {
  grid-column: 2;
  grid-row: 2;
  position:relative;
  min-height:4em;
  }

.problem-child >div {
  position:absolute;
  top:0;
  left:0;
  right:0;
  max-height:100%;
  overflow:auto ;
}

.footer {
  grid-column: 2;
  grid-row: 3;
}
<div class="container">
  <div class="left">left<br>I don't want this one to scroll<br>this should<br>determine<br>the height of the whole grid container</div>
  <div class="header">column header</div>
  <div class="problem-child">
    <div>problem child:<br>I<br>want<br>this<br>to<br>scroll<br>rather<br>than<br>making<br>everything<br>tall</div>
  </div>
  <div class="footer">column footer</div>
</div>