Reputation: 53758
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?
Upvotes: 2
Views: 12266
Reputation: 58432
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>
Upvotes: 1
Reputation: 5350
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>
Upvotes: 1