Search code examples
csslayoutflexboxscrollbarcss-grid

Element's height should depend on other element while keeping min-height and show an optional scrollbar in CSS


I need help to style the blue container in following design. The blue container should have a min-height of 400px, an optional vertical scrollbar and automatically grow if the green container is taller than the red and blue container combined.

Examples with small or tall image

  • If the green container is small (left example), the blue container should be 400px tall and show an optional scrollbar.
  • If the green container is tall (right example), the blue container should grow, so the red and blue container combined are the same height as the green container. If necessary, a scrollbar should be shown.

It's important that the blue container should have a min-height of 400px and only grow to fit the height of the green container. It should not grow if the inner content itself is tall but should just show a scrollbar then.

If this isn't possible with pure CSS, please let me know, then I'll try it with JavaScript. However, I would prefer CSS because the content of all three containers (red, blue, green) are completely variable and can change dynamically.


I tried to implement it with grid and flex but wasn't able to meet all my requirements. Especially if there was a lot of content in the blue container, either the container itself was just 400px tall or was 100% tall without showing any scrollbar. To start, here is a template you can use. Even though it grows correctly, it doesn't shrink the blue container to min-height nor does it show the optional scrollbar if you add more lines to it:

<style>
  .content {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    grid-template-rows: auto 1fr;
    grid-template-areas:
    "red green green"
    "blue green green"
  }

  .red {
    grid-area: red;
    background-color: lightsalmon;
  }

  .blue {
    grid-area: blue;
    background-color: lightblue;
    min-height: 400px;
    overflow-y: auto;
  }

  .green {
    grid-area: green;
    background-color: lightgreen;
    aspect-ratio: 2/1;
  }
</style>

<div class="content">
  <div class="red">variable content</div>
  <div class="blue">
    <div>min-height 400px</div>
    <div>auto scrollbar</div>
    <div>auto grow if image is taller</div>
    <div>line</div>
    <div>...</div>
  </div>
  <div class="green">image</div>
</div>

Solution

  • Consider using a vertical flex direction for the left column, such that the blue area has a flex-basis of 400px to fulfil the minimum height stipulation. The flex-grow: 1 then enables the blue area to fill any extra empty space if the parent is taller.

    The parent maintains the same height of the green area due to the implicit align-items: stretch value of its own parent horizontal flex layout. align-self: start overrides the align-items: stretch on the green element so that it can shrink smaller than the left side.

    .content {
      display: flex;
    }
    
    .left {
      display: flex;
      flex-direction: column;
      flex-basis: 33%;
    }
    
    .red {
      background-color: lightsalmon;
    }
    
    .blue {
      background-color: lightblue;
      flex: 1 0 400px;
      overflow-y: auto;
    }
    
    .green {
      background-color: lightgreen;
      aspect-ratio: 2/1;
      flex-basis: 67%;
      align-self: start;
    }
    <div class="content">
      <div class="left">
        <div class="red">variable content</div>
        <div class="blue">
          <div>min-height 400px</div>
          <div>auto scrollbar</div>
          <div>auto grow if image is taller</div>
          <div>line</div>
          <div>...</div>
        </div>
      </div>
      <div class="green">image</div>
    </div>