Flexbox many nested children - html

I've read many posts on flexbox but still have an issue that bugs me.
I want to have a sticky footer using flexbox as per this guide.
But then, inside my page content I would like to have as many nested divs I like and have them taking the same height of the parent.
The problem is, setting height: 100% on each child (as I would do in a non-flexbox scenario) works differently when flexbox is enabled. This results in the children getting more height (overflow the parent).
To make this more clear here's a codepen without flexbox
and a codepen with flexbox
You can see in the flexbox scenario the footer gets the green bakground even if I don't want that.
HTML:
<div class="sticky-footer-container">
<div class="sticky-footer-content">
<div class="page-container">
<div class="main-menu">
<div class="main-menu-selection">
<div class="main-menu-selection-text">
<div class="some-other-class">
Some text
</div>
</div>
</div>
<div class="main-menu-selection">
<div class="main-menu-selection-text">
<div class="some-other-class">
Some text
</div>
</div>
</div>
</div>
</div>
</div>
<div class="sticky-footer">
Some footer content
</div>
</div>
SCSS:
* {
box-sizing: border-box;
}
html,
body {
height: 100%;
background: silver;
padding: 0;
margin: 0;
}
.sticky-footer-container {
height: 100%;
display: flex;
flex-direction: column;
.sticky-footer-content {
height: 100%;
background: blue;
flex: 1;
div {
height: 100%;
}
.main-menu-selection {
height: 50%;
}
}
}
.some-other-class {
background: green;
}
In order to solve this, ANY nested div has to become a flex-container ?
In other words, is there any way to "stop the flex propagation" at some point of the tree, so all the divs gets the parent height without overflow?

display:flexbox is not really a valid value :)
you need to set height as well and eventually inherit it from html :
.sticky-footer-container {
display: flex;
flex-direction: column;
}
.sticky-footer-content {
flex: 1;
}
/* let's inherit some height to pull the footer down */
html,
body,
.sticky-footer-container {
height: 100%;
margin: 0;
}
.sticky-footer {
display: flex;/* flex item can be flexboxes as well */
background: turquoise;
align-items: center;
justify-content: center;
min-height: 3em;
}
<div class="sticky-footer-container">
<div class="sticky-footer-content">
<div class="page-container">
<div class="main-menu">
<div class="main-menu-selection">
<div class="main-menu-selection-text">
<div class="some-other-class">
Some text
</div>
</div>
</div>
<div class="main-menu-selection">
<div class="main-menu-selection-text">
<div class="some-other-class">
Some text
</div>
</div>
</div>
</div>
</div>
</div>
<div class="sticky-footer">
Here my footer
</div>
</div>

Related

Flexbox resize and scrollable overflow [duplicate]

This question already has answers here:
Why don't flex items shrink past content size?
(5 answers)
Closed 3 years ago.
I have content that I am resizing, and I want to have a fixed heading that doesn't grow/shrink and is not part of the scrollable content. With the content below becoming scrollable if there is not enough space.
The content outer wrapper (flexGrowWrapper) has a flex-grow: 1 and the inner wrapper has height: 100%; overflow-y: auto. The thought process here is that flexGrowWrapper will fill up any remaining space within the resize div, the inner wrapper will then take the full height of the flexGrowWrapper and if there is overflow, it should scroll.
What is happening is that flexGrowWrapper does grow to fill the resize area, but it seems that it's content is dictating it's min-height.
How can I make flexGrowWrapper never go beyond the resize area height?
$("button").click(function() {
$(".resize").toggleClass("small");
});
.resize {
height: 200px;
display: flex;
flex-direction: column;
overflow-y: hidden;
width: 300px;
}
.resize.small {
height: 100px;
}
.heading {
flex: 0 0 auto;
}
.flexGrowWrapper {
border: 2px solid red;
flex-grow: 1;
}
.wrapper {
height: 100%;
overflow-y: auto;
}
.content {
display: flex;
flex-direction: row;
clear: both;
}
<button>
Resize
</button>
<div class="resize">
<div class="heading">
<label>Some heading that wont scroll</label>
</div>
<div class="flexGrowWrapper">
<div class="wrapper">
<div class="content">
content
</div>
<div class="content">
content
</div>
<div class="content">
content
</div>
<div class="content">
content
</div>
<div class="content">
content
</div>
<div class="content">
content
</div>
<div class="content">
content
</div>
</div>
</div>
</div>
<div>
Something else here
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
Note: I looked at the this similar question, but it seems to have some differences, and I couldn't get the solutions to work for me.
Add min-height: 0 to .flexGrowWrapper - see demo below:
$("button").click(function() {
$(".resize").toggleClass("small");
});
.resize {
height: 200px;
display: flex;
flex-direction: column;
overflow-y: hidden;
width: 300px;
}
.resize.small {
height: 100px;
}
.heading {
flex: 0 0 auto;
}
.flexGrowWrapper {
border: 2px solid red;
flex-grow: 1;
min-height: 0; /* ADDED */
}
.wrapper {
height: 100%;
overflow-y: auto;
}
.content {
display: flex;
flex-direction: row;
clear: both;
}
<button>
Resize
</button>
<div class="resize">
<div class="heading">
<label>Some heading that wont scroll</label>
</div>
<div class="flexGrowWrapper">
<div class="wrapper">
<div class="content">
content
</div>
<div class="content">
content
</div>
<div class="content">
content
</div>
<div class="content">
content
</div>
<div class="content">
content
</div>
<div class="content">
content
</div>
<div class="content">
content
</div>
</div>
</div>
</div>
<div>
Something else here
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
Why this works
Note that this is because for a column flexbox the default min-height value is auto (along the flex axis). You can see some examples of this behaviour below:
Flexbox affects overflow-wrap behavior
Why don't flex items shrink past content size?

Flex grandchildren doesn't expand to immediate parent's height

I have the following layout (simplified version). .account is the flex-container and .card-two holds the actual table. When there is a lot of content, everything works fine, but when .card-two doesn't have enough content (when showing error messages), it does not fill the height of its parent .content. the cards have a background color set, so the entire effect looks quite ugly.
How do I make the card behave and stretch to fill its container? I tried setting height on .account, setting flex-basis:1 0 0, but it doesn't work. setting height:100% to .card-two just makes it massively overflow its parent. Note: I do not have a lot of control on the HTML.
HTML code:
<div class="container">
<div class="account">
<div class="sidebar">This is a sidebar aka the first column</div>
<div class="content">
<div class="card-one">this is card number one. full width of the parent</div>
<div class="card-two">this card should have a lot of content. but sometimes it doesn't.</div>
</div>
</div>
</div>
CSS (without the changes I have tried):
.container{
// just a generic container.
width:1140px; margin:auto;
}
.account{
display: flex;
}
.sidebar{
width: 25%;
}
.content{
width: 75%;
}
here's a codepen (with some comments as to what I have tried): https://codepen.io/samia92/full/MVJqwQ
any help is much appreciated.
You need to add flex to .content then only card-two can have flexbox properties.
.container {
width: 600px;
margin: auto;
box-sizing: border-box;
}
.account {
display: flex;
height: 400px;
}
.card {
background: #ddd;
box-shadow: 1px 2px 2px rgba(0, 0, 0, 0.5);
padding: 15px;
}
.sidebar {
width: 25%;
margin-right: 10px;
}
.content {
width: 75%;
display: flex; /*Addded*/
flex-direction: column; /*Addded*/
}
.card-one {
margin-bottom: 20px;
}
.card-two {
flex: 1; /*Addded*/
}
<div class="container">
<div class="account">
<div class="sidebar card">
This is a sidebar aka the first column
</div>
<div class="content">
<div class="card-one card">
<p>this is card number one. full width of the parent</p></div>
<div class="card-two card"><p>this card should have a lot of content. but sometimes it doesn't.</p>
<p>I want it to expand to it's parent, which has appropriate height</p>
<p>There You go.</p>
</div>
</div>
</div>
</div>

How to use flexbox inside a fixed container?

I have a div that is position: fixed; within the viewport. Within this are a series of child elements that use display: flex; and I need a scrollable element to fill 100% of the height of the flexed element. The problem I am having is that because done of the parent elements of the scrollable element have a fixed height, so the scrollable element just pushed the bottom of the flexed element rather than scroll.
Please see the following JSBin example. In this example, the blue block needs to extend to 100% the height of the red block, with the contents of the blue block still being scrollable. Needs to work in IE10+, latest Firefox and Chrome:
https://jsbin.com/terimim/edit?html,css,output
There are two primary issues causing the layout problem. They are each explained here:
Why doesn't flex item shrink past content size?
Chrome / Safari not filling 100% height of flex parent
revised demo
* {
box-sizing: border-box;
min-height: 0;
}
body {
background-color: #eaeaea;
}
#menu {
background-color: #fff;
position: fixed;
top: 20px;
right: 20px;
left: 20px;
bottom: 20px;
padding: 0;
z-index: 12;
height: calc(100vh - 40px);
}
#menu-contents {
display: flex;
flex-direction: column;
height: 100%;
}
#menu-pane-wrapper {
display: flex;
flex: 1;
background-color: #eeffcc;
}
#menu-panes {
flex: 1;
display: flex;
}
.menu-pane {
box-sizing: border-box;
background-color: #ff0000;
width: 20%;
padding: 10px;
display: flex;
}
.menu-pane-overflow {
flex: 1;
overflow-x: hidden;
overflow-y: scroll;
background-color: aqua;
}
.menu-item {
padding: 5px;
}
<div id="menu">
<div id="menu-contents">
<div id="menu-header">HEADER</div>
<div id="menu-pane-wrapper">
<div id="menu-panes">
<div class="menu-pane">
<div class="menu-pane-overflow">
<div class="menu-pane-scroll">
<div class="menu-item">1</div>
<div class="menu-item">2</div>
<div class="menu-item">3</div>
<div class="menu-item">4</div>
<div class="menu-item">5</div>
<div class="menu-item">6</div>
<div class="menu-item">7</div>
<div class="menu-item">8</div>
<div class="menu-item">9</div>
<div class="menu-item">10</div>
<div class="menu-item">11</div>
<div class="menu-item">12</div>
<div class="menu-item">13</div>
<div class="menu-item">14</div>
<div class="menu-item">15</div>
<div class="menu-item">16</div>
<div class="menu-item">17</div>
<div class="menu-item">18</div>
<div class="menu-item">19</div>
<div class="menu-item">20</div>
<div class="menu-item">21</div>
<div class="menu-item">22</div>
<div class="menu-item">23</div>
<div class="menu-item">24</div>
<div class="menu-item">25</div>
<div class="menu-item">26</div>
<div class="menu-item">27</div>
<div class="menu-item">28</div>
<div class="menu-item">29</div>
<div class="menu-item">30</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>

Control width of flex items arranged vertically in a flex container

I'm trying to achieve the effect where the boxes labeled "HALF", take up only 50% of the width (aka they share the first row evenly).
The base requirement is that they remain in a single container. Is this possible to achieve using flexbox?
I've tried playing around with flex-grow, flex-shrink, and flex-basis but I'm afraid I'm not understanding how to make it work, or if it's even possible, given the single container requirement.
Consider this fiddle: http://jsfiddle.net/GyXxT/270/
div {
border: 1px solid;
}
.container {
width: 400px;
display: flex;
flex-direction: column;
}
.child {
height: 200px;
}
.child.half {
flex: 1 1 10em;
color: green;
}
.child:not(.half) {
flex-shrink: 2;
flex-basis: 50%;
color: purple;
}
<div class="container">
<div class="child half">
HALF
</div>
<div class="child half">
HALF
</div>
<div class="child">
FULL
</div>
<div class="child">
FULL
</div>
<div class="child">
FULL
</div>
<div class="child">
FULL
</div>
</div>
Instead of flex-direction: column, you can try a wrapping flexbox using flex-wrap: wrap; and you can set:
flex-basis: 50% for the half width divs
flex-basis: 100% for the full width divs
See that I have thrown in box-sizing: border-box to adjust for the widths when using flex-basis.
See demo below:
div {
border: 1px solid;
box-sizing: border-box;
}
.container {
width: 400px;
display: flex;
flex-wrap: wrap;
}
.child {
height: 200px;
}
.child.half {
flex-basis: 50%;
color: green;
}
.child:not(.half) {
flex-basis: 100%;
color: purple;
}
<div class="container">
<div class="child half">
HALF
</div>
<div class="child half">
HALF
</div>
<div class="child">
FULL
</div>
<div class="child">
FULL
</div>
<div class="child">
FULL
</div>
<div class="child">
FULL
</div>
</div>
The flex sizing properties -- flex-grow, flex-shrink, flex-basis and flex -- work only along the main axis of the flex container.
Since your container is flex-direction: column, the main axis is vertical, and these properties are controlling height, not width.
For sizing flex items horizontally in a column-direction container you'll need the width property.
(Here's a more detailed explanation: What are the differences between flex-basis and width?)
To achieve your layout with a single container, see another answer to this question.
If you want to stay in column-direction, you'll need to wrap the .half elements in their own container.
.container {
display: flex;
flex-direction: column;
width: 400px;
}
.container > div:first-child {
display: flex;
}
.child.half {
flex: 1 1 10em;
color: green;
width: 50%;
}
.child {
height: 200px;
width: 100%;
border: 1px solid;
}
* {
box-sizing: border-box;
}
<div class="container">
<div><!-- nested flex container for half elements -->
<div class="child half">HALF</div>
<div class="child half">HALF</div>
</div>
<div class="child">FULL</div>
<div class="child">FULL</div>
<div class="child">FULL</div>
<div class="child">FULL</div>
</div>
The base requirement is that they remain in a single container.
That can also be done without flexbox, by simply float the 2 half elements
div {
border: 1px solid;
box-sizing: border-box;
}
.container {
width: 400px;
}
.child {
height: 200px;
}
.child.half {
float: left;
width: 50%;
color: green;
}
.child:not(.half) {
width: 100%;
color: purple;
}
<div class="container">
<div class="child half">
HALF
</div>
<div class="child half">
HALF
</div>
<div class="child">
FULL
</div>
<div class="child">
FULL
</div>
<div class="child">
FULL
</div>
<div class="child">
FULL
</div>
</div>
If the purpose is to hardcode the size in CSS units, or in percentages (which was mentioned the question), #kukkuz's solution is good as it is.
If you want to size element widths according to their own individual contents, then align-tems: flex-start or similar could do the job. It's possible to deal with the dimension perpendicular to that of the flex layout itself. See a tester on the bottom of the doc page
(Old question, but previous answers were incomplete, some are misleading)

Style one single column with flexbox

Maybe I want something impossible.
I want a website with only a single column styled with flexbox. The purpose is that only one column stretches its height to the footer regardless the size of the content of the column. Something like below structure:
I try to reach that with this code (I am using bootstrap):
<div class="container-fluid">
<div class="row">
<header class="col-md-12">
stuff...
</header>
<div class="col-md-1 col-a">
stuff...
</div>
<div class="col-md-10 col-b">
Stuff...
</div>
<div class="col-md-1 col-c">
<div class="col-c-child">
Stuff..
</div>
</div>
<footer class="col-md-12">
Stuff
</footer>
</div>
</div>
And then adding in the CSS this specific for the col-c and col-c-child:
.col-c {
display: flex;
flex-direction: column;
height: 100%;
}
.col-c-child {
flex: 1;
}
But is not working.
Any idea?
THE SOLUTION:
Create a row for the header, other for the content and other for the footer, that is - don't have everything in the same row.
Build a div-wrapper englobing col-a, col-b and col-c with display:flex and flex-direction: row;
get rid of col-c-child
col-c with flex: 1;
Thanks to #jelleB who elucidated me for part of it.
Put the header and the footer in different rows.
You should build a div below col-a (without content)
Use min-height: 100% on the row where you put col-a/col-b/col-c in
Give this a shot
I suspect your problem lies in the height:100%
If I am not mistaken, you cannot do that unless the parent container has its height defined. If the parent container's height is also defined as a percentage then the parent's parent container's height must also be defined. This hierarchy continues up to the body tag.
If you are able to wrap your middle divs, you can do the following:
html,
body {
height: 100%;
padding: 0;
margin: 0;
}
.container {
display: flex;
flex-direction: column;
height: 100%;
width: 100%;
}
.container #body {
display: flex;
flex-direction: row;
flex-grow: 1;
}
header,
footer {
width: 100%;
}
.left,
.right {
width: 100px; /*change to whatever width you want*/
}
.center {
flex-grow: 1;
}
/*styles for demo*/
header,
footer {
height: 50px;
background: blue;
}
.left,
.right {
background: green;
}
.center {
background: red
}
<div class="container">
<header></header>
<div id="body">
<div class="left"></div>
<div class="center"></div>
<div class="right"></div>
</div>
<footer></footer>
</div>