Clouddie
Clouddie

Reputation: 103

Flexbox child overflow auto to respect parent height

I would like a grandchild from a flex container to have its max height contained by the total height of container (100%) minus the other child height, and then have scrollbars appear when the grandchild has reached its max size.

Here is a fiddle to show it, basically I do not want the list items to overflow the green container.

https://jsfiddle.net/gcdzL3jn/2/

body {
  display: flex;
  flex-direction: column;
  height: 80vh;
}

#header {
  background-color: red;
  height: 30px;
}

#main {
  background-color: green;
  display: flex;
  height: 100%;
  flex-direction: column;
}

#panel {
  height: 100%;
}

#panel-top {
  height: 80px;
  border-style: solid;
}

#panel-bottom-overflow {
  border-style: solid;
  overflow-y: auto;
}

#footer {
  background-color: yellow;
  height: 30px;
}
<body>
  <div id="header">
  </div>
  <div id="main">
    <div id="panel">
      <div id="panel-top">
        Top Panel
      </div>
      <div id="panel-bottom-overflow">
        <ul>
          <li>List item</li>
          <li>List item</li>
          <li>List item</li>
          <li>List item</li>
          <li>List item</li>
          <li>List item</li>
          <li>List item</li>
          <li>List item</li>
          <li>List item</li>
          <li>List item</li>
          <li>List item</li>
          <li>List item</li>
          <li>List item</li>
          <li>List item</li>
          <li>List item</li>
          <li>List item</li>
          <li>List item</li>
          <li>List item</li>
        </ul>
      </div>
    </div>
  </div>
  <div id="footer">
  </div>
</body>

Upvotes: 1

Views: 6640

Answers (2)

Asons
Asons

Reputation: 87191

By giving main wrappers, body, #main, #panel, display: flex; with column direction, the children that should take the remaining space (#main, #panel, #panel-bottom-overflow) flex: 1 and finally add an extra wrapper for the scrolling, your will end up with this.

The extra scroller overcomes the issue where the overflowing element needs a height by using absolute positioning.

Note, this solution also makes it possible to drop the fixed height on both header, panel and footer (which I did, but you can of course add them back) and let it size by its content, and it will still work.

body, #main, #panel {
  display: flex;
  flex-direction: column;
}
#main, #panel, #panel-bottom-overflow {
  flex: 1;
}

body {
  height: 80vh;
}
#header {
  background-color: red;
  padding: 5px;
}
#main {
  background-color: green;
}
#panel-top {
  border-style: solid;
  padding: 30px 5px;
}
#panel-bottom-overflow {
  position: relative;
  border-style: solid;
}
#panel-bottom-overflow .scroller {
  position: absolute;
  top: 0; left: 0;
  right: 0; bottom: 0;
  overflow: auto;
}
#footer {
  background-color: yellow;
  padding: 5px;
}
<div id="header">
  Header
</div>
<div id="main">
  <div id="panel">
    <div id="panel-top">
      Top Panel
    </div>
    <div id="panel-bottom-overflow">
      <div class="scroller">
        <ul>
          <li>List item</li>
          <li>List item</li>
          <li>List item</li>
          <li>List item</li>
          <li>List item</li>
          <li>List item</li>
          <li>List item</li>
          <li>List item</li>
          <li>List item</li>
          <li>List item</li>
          <li>List item</li>
          <li>List item</li>
          <li>List item</li>
          <li>List item</li>
          <li>List item</li>
          <li>List item</li>
          <li>List item</li>
          <li>List item</li>
        </ul>
      </div>
    </div>
  </div>
</div>
<div id="footer">Footer
</div>

Upvotes: 6

Michael Benjamin
Michael Benjamin

Reputation: 371301

You need to define a height for the overflowing element. With a height limit in place, the overflow property can be triggered. Add this to your code:

#panel-bottom-overflow { height: calc(100% - 80px); }

Your green container (#main) has one child (#panel). Both elements are set to height: 100%.

The child element has two children: #panel-top and #panel-bottom-overflow.

#panel-top is set to height: 80px.

Without a height limit on the sibling, content can visibly overflow (overflow: visible is the default setting), but overflow: auto needs a set height or max-height for scrollbars to work.

revised fiddle

body {
  display: flex;
  flex-direction: column;
  height: 80vh;
}

#header {
  background-color: red;
  height: 30px;
}

#main {
  background-color: green;
  display: flex;
  height: 100%;
  flex-direction: column;
}

#panel {
  height: 100%;
}

#panel-top {
  height: 80px;
  border-style: solid;
}

#panel-bottom-overflow {
  border-style: solid;
  overflow-y: auto;
  height: calc(100% - 80px);  /* NEW */
}

* { box-sizing: border-box; } /* NEW */

#footer {
  background-color: yellow;
  height: 30px;
}
<body>
  <div id="header">
  </div>
  <div id="main">
    <div id="panel">
      <div id="panel-top">
        Top Panel
      </div>
      <div id="panel-bottom-overflow">
        <ul>
          <li>List item</li>
          <li>List item</li>
          <li>List item</li>
          <li>List item</li>
          <li>List item</li>
          <li>List item</li>
          <li>List item</li>
          <li>List item</li>
          <li>List item</li>
          <li>List item</li>
          <li>List item</li>
          <li>List item</li>
          <li>List item</li>
          <li>List item</li>
          <li>List item</li>
          <li>List item</li>
          <li>List item</li>
          <li>List item</li>
        </ul>
      </div>
    </div>
  </div>
  <div id="footer">
  </div>
</body>

Upvotes: 2

Related Questions