skip to Main Content

I have a side panel that should be exactly the height of its content, up to some maximum height. Inside is a gallery of components which should scroll if it overflows. I can’t get it to scroll with max-height on the parent container. If I set a some value on the height property, it scrolls, but then it doesn’t shrink with its content.

Here’s a repro of the problem, with the left container being an example of the case that should scroll, and the right container being an example of the case that shrinks to fit the content:

* {
  box-sizing: border-box;
}

.parent-container {
  width: 250px;
  border: 1px solid black;
  display: inline-block;
  max-height: 500px;
}

.flex-container {
  height: 100%;
  display: flex;
  flex-direction: column;
}

.scrolling-container {
  flex: 1;
  overflow-y: auto;
}

.item {
  height: 100px;
  width: 100px;
  background: red;
  margin: 5px;
}
<div class="parent-container">
  <div class="flex-container">
    <div>
      This box should hit the max height and start scrolling the inner div
    </div>
    <div class="scrolling-container">
      <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>This div stays on bottom</div>
  </div>
</div>

<div class="parent-container">
  <div class="flex-container">
    <div>
      This container shouldn't scroll and should only be as tall as the content
    </div>
    <div class="scrolling-container">
      <div class="item"></div>
      <div class="item"></div>
    </div>
    <div>This div stays on bottom</div>
  </div>
</div>

If you throw height: 500px on parent-container, you can see the scrolling behavior that I’m going for.

Is there any way to do this with just CSS, or do I need to use JavaScript?

2

Answers


  1. The max-height property needs to be applied to the container you want to scroll. In order to keep it consistent to the ancestor’s max-height, you can put max-height: inherit on all the child containers that are ancestors of the scrolling container.

    * {
      box-sizing: border-box;
    }
    
    .parent-container {
      width: 250px;
      border: 1px solid black;
      display: inline-block;
      max-height: 500px;
    }
    
    .flex-container {
      height: 100%;
      display: flex;
      flex-direction: column;
      max-height: inherit;
    }
    
    .scrolling-container {
      flex: 1;
      overflow-y: auto;
      max-height:inherit;
    }
    
    .item {
      height: 100px;
      width: 100px;
      background: red;
      margin: 5px;
    }
    <div class="parent-container">
      <div class="flex-container">
        <div>
          This box should hit the max height and start scrolling the inner div
        </div>
        <div class="scrolling-container">
          <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>This div stays on bottom</div>
      </div>
    </div>
    
    <div class="parent-container">
      <div class="flex-container">
        <div>
          This container shouldn't scroll and should only be as tall as the content
        </div>
        <div class="scrolling-container">
          <div class="item"></div>
          <div class="item"></div>
        </div>
        <div>This div stays on bottom</div>
      </div>
    </div>
    Login or Signup to reply.
  2. PsiKai’s answer is awesome. I wanted to offer an alternative that requires less wrappers too. This approach uses grid and min-content

    * {
      box-sizing: border-box;
    }
    
    body {
      font-family: sans-serif;
    }
    
    .parent-container {
      width: 20rem;
      border: 1px solid;
      max-height: 20rem;
      
      /* 
        grid with 3 rows
        header and footer rows will 
        have height of their content
        scroll-container will grow
        to fill the remainder
      */
      display: grid;
      grid-template-rows: min-content 1fr min-content;
    }
    
    .scrolling-container {
      overflow-y: auto;
      
      /*
        could be flex here, but then
        you have to set the direction
        and the items may need flex 
        setting adjustments
      */
      display: grid;
      gap: .5rem;
    }
    
    .item {
      height: 10rem;
      background-color: red;
    }
    
    header, 
    footer {
      padding: 1rem;
    }
    <section class="parent-container">
        <header>
          This parent-container hits the max height of 500px and starts scrolling the scrolling-container
        </header>
        <div class="scrolling-container">
          <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>
        <footer>This div stays on bottom</footer>
    </section>

    :

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search