Force flexbox element not to take all vertical space

11,228

Solution 1

I would do it like this (comments in css as to what I have changed):

* {
    box-sizing: border-box;
}

body {
  margin: 0;
  padding: 0;
}

#container {
  padding: 10px;
  background: #fefefe;
  display: flex;
  flex-direction: column;
  max-height: 100vh;
  overflow: hidden;
  /*remove flex grow and shrink - as parent is not flex, these have no effect*/
}

#header {
  padding: 10px;
  background: #e1eaec;
}

#items {
  flex-grow: 1;     /* change the width and height for flex grow */
  background: #eee;
  padding: 10px;
  overflow: auto;
}

.item {
  background: lightyellow;
  padding: 20px;
}

/* New */

#main {
  display: flex;
  flex-direction: row;
  flex-grow: 1;            /* remove flex-shrink and set grow to 1 */
  /* height: 300px; */
}

#sidebar {
  flex-basis: 20%;
  padding: 10px;
}
<div id='container'>
  <div id='header'>
    <h1>Header</h1>
  </div>
  <div id='main'>
    <div id='items'>
      <div class='item'>Lorem Ipsum</div>
      <div class='item'>Lorem Ipsum</div>
      <div class='item'>Lorem Ipsum</div>
      <div class='item'>Lorem Ipsum</div>
      <div class='item'>Lorem Ipsum</div>
      <div class='item'>Lorem Ipsum</div>
      <div class='item'>Lorem Ipsum</div>
      <div class='item'>Lorem Ipsum</div>
      <div class='item'>Lorem Ipsum</div>
      <div class='item'>Lorem Ipsum</div>
      <div class='item'>Lorem Ipsum</div>
      <div class='item'>Lorem Ipsum</div>
    </div>
    <div id='sidebar'>
      Sidebar
    </div>
  </div>
</div>

Solution 2

You can use code below if you want to have sidebar with full available height, fixed header and scrollable content.

body {
    margin: 0;
}

section {
  display: flex;
  flex-direction: column;
  height: 100vh;
}

header {
  flex: 0 0 auto;
  background: red;
  font-size: 2em;
  padding: .5em;
}

main {
  display: flex;
  flex: 1 1 auto;
}

content {
  flex: 1 1 auto;
  overflow-y: scroll;
}

aside {
  flex: 0 0 auto;
  padding: 20px;
  background: green;
}

div {
  border: 1px solid red;
  padding: 1em;
}
<section>
  <header>header</header>
  <main>
    <content>
      <div>div</div>
      <div>div</div>
      <div>div</div>
      <div>div</div>
      <div>div</div>
      <div>div</div>
      <div>div</div>
      <div>div</div>
      <div>div</div>
      <div>div</div>
      <div>div</div>
      <div>div</div>
      <div>div</div>
      <div>div</div>
      <div>div</div>
      <div>div</div>
      <div>div</div>
      <div>div</div>
      <div>div</div>
      <div>div</div>
      <div>div</div>
      <div>div</div>
      <div>div</div>
      <div>div</div>
      <div>div</div>
      <div>div</div>
      <div>div</div>
      <div>div</div>
      <div>div</div>
    </content>
    <aside>sidebar</aside>
  </main>  
</section>

Share:
11,228
Maxim
Author by

Maxim

Software Engineer at Google.

Updated on June 04, 2022

Comments

  • Maxim
    Maxim almost 2 years

    TL;DR: flex element with flex-direction: row takes all vertical space and prevents the scrollbar in its child.


    The first fiddle shows what kind of UI I'd like to achieve: it's a page that stretches to the whole screen, both horizontally and vertically. It contains a header and a main <div>, which is a scrollable list of items. The container is thus a column flexbox. Note that it's width and height are just fine.

    Now I want to add a sidebar to the main content, and flexbox seems to be perfect for this as well. I simply add one more <div id='main'> with flex-direction: row: see the second fiddle. The sidebar is shown fine, but here is a problem. The new <div id='main'> takes all vertical space, as a result, the items list never gets a scrollbar.

    I have tried to limit the height <div id='main'> and it seems to work. But it's pretty inconvenient in terms of code, because the header is a separate component, so in general its height is unknown to the main component and I have calculate it before setting height: calc(100vh - ...).

    Is there a pure CSS way to tell a flexbox container not to grow vertically? Or should I go back to good old table html?

    • Xoog
      Xoog over 6 years
      Adding overflow-y: auto; to main will show the scrollbar. Is this what you're after? Apologies if I've missed the mark here.
    • Admin
      Admin over 6 years
      Your #container has overflow hidden. Your .items has the height it should have (of all items) but #containers overflow hidden cuts it. That means you have to change the height of .items
    • Admin
      Admin over 6 years
      @sconner87 doesn't work for me
  • Maxim
    Maxim over 6 years
    Perfect! I feel like I tried this variant, but #items got height:100% from one of the classes and I didn't pay attention to it. Your solution made me think about: it turns out the crucial rule is height: initial; Thanks!