I have a 3-column body with fixed width on the sides and the middle column filling the remaining width.
I need however to make all columns fill the entire height of the page.
I set the height of all parents to height: 100% and I don't want to use a workaround with huge margin or padding, as I'm using a scroll-bar.
#container {
width: 100%;
display: flex;
flex-direction: row;
justify-content: space-between;
height: 100%;
}
.col-side {
width: 240px;
height: 100%;
}
#col1 {
border-right: 2px solid rgba(0, 0, 0, 0.12);
}
#col3 {
border-left: 2px solid rgba(0, 0, 0, 0.12);
}
<div id="container">
<div class="col-side" id="col1">
Left
</div>
<div class="col" id="col2">
Center
</div>
<div class="col-side" id="col3">
Right
</div>
</div>
Small demo can be found here:
https://jsfiddle.net/ysn3q6aL/#&togetherjs=H9pEenhcqQ
When you create a flex container (display: flex or display: inline-flex), it automatically applies flex-direction: row and align-items: stretch (among other initial settings).
These default settings line up flex items in a row and give them each the full height of the container. However, if you set a height on a flex item, it overrides align-items. So remove any heights you've set on the items.
This should work for you:
#container {
display: flex;
justify-content: space-between;
height: 100vh;
}
.col-side {
flex: 0 0 240px;
}
#col2 { flex: 1; }
#container > div + div {
border-left: 2px solid rgba(0, 0, 0, 0.12);
}
#col1 { background-color: lightgreen; }
#col2 { background-color: tomato; }
#col3 { background-color: aqua; }
body { margin: 0; }
<div id="container">
<div class="col-side" id="col1">Left</div>
<div class="col" id="col2">Center</div>
<div class="col-side" id="col3">Right</div>
</div>
.col-side{
width: 240px;
height: 100%;
flex: 1 1 0;
}
might help. I was asking the same some time before, the flex: 1 1 0 part helped.
the defaults are 0 1 auto. The first param is flex grow, so you want them all to grow to the same height.
https://css-tricks.com/snippets/css/a-guide-to-flexbox/#article-header-id-13
Set the container height to 100vh.
That's all
#container{
width: 100%;
display: flex;
flex-direction: row;
justify-content: space-between;
height:100vh;
}
.col-side{
width: 240px;
height: 100%;
}
#col1{
border-right: 2px solid rgba(0, 0, 0, 0.12);
}
#col3{
border-left: 2px solid rgba(0, 0, 0, 0.12);
}
Related
I want to grow a container, but only when there is enough space to add a new element. Say my elements are 100px, this would mean the acceptable widths for my container would be 120, 230, 340, and so on.
Although I am demoing flex and margin-right: auto, I do not want the margins between the objects to be variable. I want only about 10 pixels between objects. I'm ok with there being a variable horizontal buffer for the container, if that is a solution.
I'm not certain I can do this using flex, so if there's a better way, I'd be grateful.
.container {
display: flex;
flex-wrap: wrap;
border: 3px solid rgb(0, 0, 0);
}
.panel {
height: 100px;
width: 100px;
border: 3px solid rgb(255, 0, 0);
margin: 10px 0px 0px 10px;
}
<div class="container">
<div class="panel"></div>
<div class="panel"></div>
<div class="panel"></div>
<div class="panel"></div>
</div>
There is the CSS code for the container element :
(added width: fit-content with a padding.)
.container {
display: flex;
flex-wrap: wrap;
width: fit-content;
border: 3px solid rgb(0, 0, 0);
padding : .5rem .5rem;
}
This markup should produce a 30px high box that is 600px width, centered. But instead it shrinks the box so it is no width (or if there is content, it shrinks to the minimum content width). Wondering how to make this so the centered box is 600px, but is responsive at smaller window sizes.
* {
position: relative;
box-sizing: border-box;
}
html, body {
height: 100%;
overflow: hidden;
}
div {
display: flex;
}
body > div {
align-items: center;
-webkit-box-pack: center;
-webkit-justify-content: center;
justify-content: center;
border: 1px solid orange;
}
body > div > div {
max-width: 600px;
border: 1px solid black;
}
body > div > div > div {
border: 1px solid blue;
background: red;
height: 30px;
}
<div>
<div>
<div></div>
</div>
</div>
Please try this. Give width:100% to body > div > div and body > div > div > div class.
* {
position: relative;
box-sizing: border-box;
}
html, body {
height: 100%;
overflow: hidden;
}
div {
display: flex;
}
body > div {
align-items: center;
-webkit-box-pack: center;
-webkit-justify-content: center;
justify-content: center;
border: 1px solid orange;
}
body > div > div {
max-width: 600px;
border: 1px solid black;
width:100%;
}
body > div > div > div {
border: 1px solid blue;
background: red;
height: 30px;
width:100%;
}
<div>
<div>
<div></div>
</div>
</div>
That is the default behavior of a flex item, being as wide as its content, similar to an inline block.
The reason is its default flex-grow value, which is 0 and tells it to not fill the remaining space.
Add flex-grow: 1 to every level of flex item that should fill its parent.
* {
position: relative;
box-sizing: border-box;
}
html, body {
height: 100%;
overflow: hidden;
}
div {
display: flex;
}
body > div {
align-items: center;
-webkit-box-pack: center;
-webkit-justify-content: center;
justify-content: center;
border: 1px solid orange;
}
body > div > div {
max-width: 600px;
border: 1px solid black;
flex-grow: 1; /* added */
}
body > div > div > div {
border: 1px solid blue;
background: red;
height: 30px;
flex-grow: 1; /* added */
}
<div>
<div>
<div></div>
</div>
</div>
Please allow me to simplify the code to its basic components. You have a div.container that is set as display:flex. Inside that you have a div which you want to adjust according to flex parameters. The inner div is set to grow and shrink according to its container:
flex: 1 1 auto; /* shorthand for flex-grow, flex-shrink, flex-basis */
It is also set to have a max-width:600px and centered in the page with margin-left and margin-right set to auto. I believe this construct meets your requirements.
div.container {
display: flex;
border: 1px solid orange;
}
div.container div {
flex: 1 1 auto;
border: 1px solid blue;
background: red;
height: 30px;
margin: 0 auto 0 auto;
max-width: 600px;
}
<div class="container">
<div></div>
</div>
I use a third-party component that occupies all the available space, i.e. width=100% and height=100%. I don't have control over it.
I'm trying to fit it in the following layout, but its height=100% doesn't work (I expect the third-party component to occupy all the green space).
Why? How would you fix that?
.container {
display: flex;
flex-direction: column;
width: 200px;
height: 100px;
}
.header {
display: flex;
background-color: rgba(255, 0, 0, 0.5);
}
.content {
flex-grow: 1;
background-color: rgba(0, 255, 0, 0.5);
}
.third-party-component {
height: 100%;
width: 100%;
background-color: rgba(0, 0, 255, 0.5);
}
<div class="container">
<div class="header">Header</div>
<div class="content">
<div class="third-party-component">
Third party component
</div>
</div>
</div>
In general, for an element using percent on height to pick up its parent's height, the parent need a height other than auto or being positioned absolute, or the height will be computed as auto.
Based on those 2 options, and as you mentioned in a comment, your own header is dynamic in height, you are left with absolute positioning.
The problem with adding absolute to the content, it will be taken out of flow and stop behaving as a normal flowed flex item, the good news, one can add a wrapper set to absolute.
Stack snippet
.container {
display: flex;
flex-direction: column;
width: 200px;
height: 100px;
}
.header {
display: flex;
background-color: rgba(255, 0, 0, 0.5);
}
.content {
position: relative; /* added */
flex-grow: 1;
background-color: rgba(0, 255, 0, 0.5);
}
.wrapper {
position: absolute; /* added */
left: 0; /* added */
top: 0; /* added */
right: 0; /* added */
bottom: 0; /* added */
}
.third-party-component {
height: 100%;
width: 100%;
background-color: rgba(0, 0, 255, 0.5);
}
<div class="container">
<div class="header">Header</div>
<div class="content">
<div class="wrapper">
<div class="third-party-component">
Third party component
</div>
</div>
</div>
</div>
Another option could be to update the Flexbox properties, to give the content a height, using flex: 1 1 100% and give header flex-shrink: 0; so it doesn't shrink (as content got 100%).
This might not work on Safari though, as I know it have had issues when the height property is not set, though can't test that now as I don't have access to Safari.
.container {
display: flex;
flex-direction: column;
width: 200px;
height: 100px;
}
.header {
display: flex;
flex-shrink: 0;
background-color: rgba(255, 0, 0, 0.5);
}
.content {
flex: 1 1 100%;
background-color: rgba(0, 255, 0, 0.5);
}
.third-party-component {
height: 100%;
width: 100%;
background-color: rgba(0, 0, 255, 0.5);
}
<div class="container">
<div class="header">Header</div>
<div class="content">
<div class="third-party-component">
Third party component
</div>
</div>
</div>
Because .content haven't height (height = 0px) and .third-party-component have 100% of 0px. You can add propety height : calc (100% - <height of .header>) into .content
.container {
display: flex;
flex-direction: column;
width: 200px;
height: 100px;
}
.header {
display: flex;
background-color: rgba(255, 0, 0, 0.5);
}
.content {
height: calc(100% - 18px);
flex-grow: 1;
background-color: rgba(0, 255, 0, 0.5);
}
.third-party-component {
height: 100%;
width: 100%;
background-color: rgba(0, 0, 255, 0.5);
}
<div class="container">
<div class="header">Header</div>
<div class="content">
<div class="third-party-component">
Third party component
</div>
</div>
</div>
You can simply use another flex container in the .content element:
.container {
display: flex;
flex-direction: column;
width: 200px;
height: 100px;
}
.header {
display: flex;
background-color: rgba(255, 0, 0, 0.5);
}
.content {
flex-grow: 1;
display: flex;
flex-direction: column;
background-color: rgba(0, 255, 0, 0.5);
}
.third-party-component {
flex-grow: 1;
height: 100%;
width: 100%;
background-color: rgba(0, 0, 255, 0.5);
}
<div class="container">
<div class="header">Header</div>
<div class="content">
<div class="third-party-component">
Third party component
</div>
</div>
</div>
I have an element with 2 children.
I'm trying to have:
div grow as much as it needs based on 1 of its children
the other always fit the parents height
Thus, I want to avoid setting a height on the parent.
The problem arises when trying to handle overflow of the second child.
Here's the code:
.banner {
display: flex;
background-color: lightblue;
overflow: auto;
border: 4px solid black;
//max-height: 120px; // 1) IF I'M NOT SET THE SCROLL WON'T WORK
}
.constant {
color: white;
flex: 0 0 auto;
width: 200px;
// height: 150px; 2) DISABLED FOR NOW
border: 4px solid yellow;
background-color: olive;
border: 2px solid red;
}
.container {
display: flex;
text-align: center;
}
.main {
max-height: 100%; // 3) I SHOULD STOP MYSELF FROM GROWING MORE THAN MY PARENT
flex: 1;
overflow-y: scroll;
border: 2px solid white;
display: flex;
flex-direction: row-reverse;
align-items: flex-end;
flex-wrap: wrap;
}
.main div {
text-align: center;
width: 200px;
height: 80px;
}
.main-side {
flex: 0 0 auto;
color: white;
background-color: grey;
border: 2px solid yellow;
}
html {
box-sizing: border-box;
}
*,
*:before,
*:after {
box-sizing: inherit;
background-repeat: no-repeat !important;
min-width: 0px;
min-height: 0px;
}
<div class="banner">
<div class="container">
<div class="main">
<div style="background-color:coral;">A</div>
<div style="background-color:lightgoldenrodyellow;">B</div>
<div style="background-color:khaki;">C</div>
<div style="background-color:pink;">D</div>
<div style="background-color:lightgrey;">E</div>
<div style="background-color:lightgreen;">F</div>
</div>
<div class="main-side">I've a fixed size</div>
</div>
<div class="constant">I can grow...and my parent should grow if I grow</div>
</div>
If I set a fixed height on .banner everything works out, but I would like to avoid doing so if possible.
jsfiddle
Thank you.
I would like a column of divs, of any number, each with width 100% and height 100% of their parent div, so one is visible initially, and the others overflow the parent downwards. I've set the divs to have flex: 0 0 100%;, inside a parent div with display: flex and flex-direction: column to achieve this.
The parent div is itself of unknown height, so it is also a child of a display: flex and flex-direction: column, set to flex: 1 0 0 to take remaining space in its container.
In Firefox the output is as I would like it:
However, not in Chrome:
How can I achieve the Firefox style in Chrome, without Javascript?
You can see this in action at http://plnkr.co/edit/WnAcmwAPnFaAhqqtwhLL?p=preview, as well as the corresponding version with flex-direction: row, which works consistently in both Firefox and Chrome.
For reference, the full CSS
.wrapper {
display: flex;
flex-direction: column;
height: 150px;
width: 200px;
border: 4px solid green;
margin-bottom: 20px;
}
.column-parent {
flex: 1 0 0;
display: flex;
flex-direction: column;
border: 2px solid blue;
}
.column-child {
flex: 0 0 100%;
border: 2px solid red;
}
and HTML
<div class="wrapper">
<p>Some content of unknown size</p>
<div class="column-parent">
<div class="column-child">
Should be inside green
</div>
<div class="column-child">
Should be outside green
</div>
</div>
</div>
This seems to be a bug with Chrome. Similar to the ones reported here (issue 428049) and perhaps related to (issue 346275).
This says:
- Browsers are supposed to resolve percentages on the flex item's child, *if* its flex-basis is definite.
- Gecko is *always* resolving percentages regardless of the flex-basis.
- Chrome is *never* resolving percentages, regardless of the flex-basis.
Summarily, Chrome is not resolving percent heights on flex-item's child (even if the child itself is a flex-item), while all other browsers do.
This can be demonstrated in the below snippet: (Fiddle here)
* { box-sizing: border-box; margin: 0; padding: 0; }
div.wrap {
height: 120px; width: 240px; margin: 0px 12px;
border: 1px solid blue; float: left;
display: flex; flex-direction: column;
}
div.parent {
flex: 0 0 100%;
border: 1px solid green;
display: flex; flex-direction: column;
}
div.item {
flex: 0 0 100%;
border: 1px solid red;
}
<div class="wrap">
<div class="item">a</div>
<div class="item">b</div>
<div class="item">c</div>
</div>
<div class="wrap">
<div class="parent">
<div class="item">a</div>
<div class="item">b</div>
<div class="item">c</div>
</div>
</div>
The second div should show the same behaviour as the first one. Other browsers (IE11, Edge, FF39) show it correctly. Chrome fails here and does not resolve div.item correctly. It needs a fixed height on its parent, without which it uses min-content as its height and thus does not overflow.
Whereas, in the first div, the div.items are correctly resolved and overflow accordingly. This is because there is a fixed height on the parent (i.e. div.wrap)
Possible Solution:
As a workaround, if you are sure to have only two elements (p and div) inside your wrapper, then you could give them a 50% height. You have to provide a height:50% to your .column-parent. Chrome needs a fixed height on parent as demonstrated above.
Then everything will work as you need to.
Demo Fiddle: http://jsfiddle.net/abhitalks/kqncm65n/
Relevant CSS:
.wrapper > p { flex: 0 0 50%; } /* this can be on flex-basis */
.column-parent {
flex: 1 0 auto; height: 50%; /* but, this needs to be fixed height */
display: flex; flex-direction: column;
border: 2px solid blue;
}
.column-child {
flex: 0 0 100%; /* this flex-basis is then enough */
border: 2px solid red;
}
PS: There also seem to be differences in the way jsfiddle and plnkr render. I don't know why, but sometimes I get different results!
As stated in Abhitalks response, there is a bug (or a different interpretation of the standard) in the way Chrome handles the height attribute here.
I have found a hack that is working both in Chrome FF and IE
The only issue is that you ned to have as many rules as posible children there are.
The trick is to set the flex-direction to row, set the flex-basis (that is now the width) to 100%, and then translate the elements
.container {
border: solid 2px blue;
height: 200px;
width: 200px;
display: flex;
flex-direction: column;
position: relative;
}
.filler {
border: solid 1px black;
flex: 0 0 80px;
background-color: lightgreen;
transition: flex 1s;
}
.container:hover .filler {
flex: 0 0 40px;
}
.test {
border: solid 1px red;
flex: 1 0 25px;
display: flex;
flex-direction: row;
position: relative;
}
.child {
background-color: rgba(200, 0, 0, 0.26);
flex: 0 0 100%;
}
.child:nth-child(2) {
background-color: rgba(255, 255, 0, 0.48);
transform: translateX(-100%) translateY(100%);
}
.child:nth-child(3) {
background-color: rgba(173, 216, 230, 0.28);
transform: translateX(-200%) translateY(200%);
}
<div class="container">
<div class="filler"></div>
<div class="filler"></div>
<div class="test">
<div class="child">1</div>
<div class="child">2</div>
<div class="child">3</div>
</div>
</div>
If there could be another child, you would need a nth-child(4) rule, and so on
I have added an hover effect to check how the size adapts
My previous answer is a hack that exploits a particular setup of the layout wanted.
An alternate way, more general, of getting around this Chrome bug is to use an intermediate element in the layout, and set this element size using top: 0px and bottom: 0px. (instead of height: 100%) There is still a bug in the way Chrome handles the calculus, that needs a fake animation to make it adjust properly
.container {
border: solid 2px blue;
height: 200px;
width: 200px;
display: flex;
flex-direction: column;
position: relative;
}
.filler {
border: solid 1px black;
flex: 0 0 94px;
background-color: lightgreen;
transition: 1s;
}
.container:hover .filler {
flex: 0 0 50px;
}
.test {
border: solid 1px red;
flex: 1 0 25px;
display: flex;
flex-direction: row;
position: relative;
}
#-webkit-keyframes adjust2 {
0% {flex-basis: 100%;}
100% {flex-basis: 100.1%;}
}
.child {
background-color: rgba(200, 0, 0, 0.26);
width: 100%;
height: 100%;
flex: 1 0 100%;
-webkit-animation: adjust2 1s infinite; /* only needed for webkit bug */
}
.intermediate {
width: 100%;
position: absolute;
top: 0px;
bottom: 0px;
display: flex;
flex-direction: column;
}
.child:nth-child(n+2) {
background-color: rgba(255, 255, 0, 0.48);
}
.child:nth-child(n+3) {
background-color: rgba(173, 216, 230, 0.28);
}
<div class="container">
<div class="filler"></div>
<div class="test">
<div class="intermediate">
<div class="child"></div>
<div class="child"></div>
<div class="child"></div>
</div>
</div>
</div>
What about adding 100% to the container:
.column-parent {
flex: 1 0 100%;
}
And flex-grow to 1 in the contained element without adjusting the flex basis:
.column-child {
flex: 1 0 0;
}
Here's how it would look: http://plnkr.co/edit/H25NQxLtbi65oaltNVax?p=preview