Search code examples
htmlcsslayoutflexboxgrid

How to implement a flexbox-based list that scrolls once it reaches its parents size


Im trying to implement a list of items, that correctly fits into my layout. I'd like the list to be scrollable if its intrinsic content size exceeds its parent element's dimensions. As you can see in the snippet below, instead of scrolling my list resizes hence ignoring the overflow: scroll rule. So far I've tried to manipulate the overflow(-y), maxHeight, height, flex-grow, shrink and basis properties but did not manage to solve my problem. Im may be only one style-rule but so far I did not manage to prevent the list from overgrowing and thereby destroying the layout.

Any help would be highly appreciated. Thanks!

.layout {
  display: grid; 
  grid-template-columns: 1fr 3fr; 
  grid-template-rows: 1fr 1fr; 
  column-gap: 10px; 
  row-gap: 10px; 
  padding: 15px;
  position: absolute;
  left: 0px;
  top: 0px;
  right: 0px;
  bottom: 0px;
}

.container {
  background-color: lightGrey;
  border-radius: 15px;
}

.leading-upper {
  grid-column-start: 1; 
  grid-column-end: 2; 
  grid-row-start: 1; 
  grid-row-end: 2;
}

.leading-lower {
  grid-column-start: 1; 
  grid-column-end: 2; 
  grid-row-start: 2; 
  grid-row-end: 3;
}

.trailing {
  grid-column-start: 2; 
  grid-column-end: 3; 
  grid-row-start: 1; 
  grid-row-end: 3; 
}

.header {
  padding-left: 20px;
  border-bottom: 1px solid;
}

.list {
  overflow: scroll;
  display: flex; 
  flex-flow: column nowrap; 
  row-gap: 10px; 
  padding: 10px; 
  overflow: scroll;
}

.item {
  height: 50px;
  background-color: red;
  border-radius: 10px;
}
<div class="layout">
  <div class="container leading-upper"></div>
  <div class="container leading-lower"></div>
  <div class="container trailing">
    <div class="header">
      <h1>Title</h1>
    </div>
    <div class="list">
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
    </div>
  </div>
</div>


Solution

  • The trailing class should be the flexbox container and not the list class. Just put the following three lines in the trailing class and it almost works.

    display: flex;
    flex-direction: column;
    row-gap: 10px;
    

    In the list class, remove one overflow: scroll and change the other to overflow-y: scroll as horizontal scrolling is not required.

    There is no gap between item's so add margin-bottom: 10px;, for example.

    .layout {
      display: grid;
      grid-template-columns: 1fr 3fr;
      grid-template-rows: 1fr 1fr;
      column-gap: 10px;
      row-gap: 10px;
      padding: 15px;
      position: absolute;
      left: 0px;
      top: 0px;
      right: 0px;
      bottom: 0px;
    }
    
    .container {
      background-color: lightGrey;
      border-radius: 15px;
    }
    
    .leading-upper {
      grid-column-start: 1;
      grid-column-end: 2;
      grid-row-start: 1;
      grid-row-end: 2;
    }
    
    .leading-lower {
      grid-column-start: 1;
      grid-column-end: 2;
      grid-row-start: 2;
      grid-row-end: 3;
    }
    
    .trailing {
      grid-column-start: 2;
      grid-column-end: 3;
      grid-row-start: 1;
      grid-row-end: 3;
      display: flex;
      flex-direction: column;
      row-gap: 10px;
    }
    
    .header {
      padding-left: 20px;
      border-bottom: 1px solid;
    }
    
    .list {
      padding: 10px;
      overflow-y: scroll;
    }
    
    .item {
      height: 50px;
      background-color: red;
      border-radius: 10px;
      margin-bottom: 10px;
    }
    <div class="layout">
      <div class="container leading-upper"></div>
      <div class="container leading-lower"></div>
      <div class="container trailing">
        <div class="header">
          <h1>Title</h1>
        </div>
        <div class="list">
          <div class="item"></div>
          <div class="item"></div>
          <div class="item"></div>
          <div class="item"></div>
          <div class="item"></div>
          <div class="item"></div>
          <div class="item"></div>
          <div class="item"></div>
          <div class="item"></div>
          <div class="item"></div>
          <div class="item"></div>
          <div class="item"></div>
          <div class="item"></div>
          <div class="item"></div>
          <div class="item"></div>
          <div class="item"></div>
          <div class="item"></div>
          <div class="item"></div>
          <div class="item"></div>
          <div class="item"></div>
          <div class="item"></div>
          <div class="item"></div>
          <div class="item"></div>
          <div class="item"></div>
          <div class="item"></div>
          <div class="item"></div>
          <div class="item"></div>
          <div class="item"></div>
          <div class="item"></div>
          <div class="item"></div>
          <div class="item"></div>
          <div class="item"></div>
          <div class="item"></div>
          <div class="item"></div>
          <div class="item"></div>
          <div class="item"></div>
        </div>
      </div>
    </div>