I have been studying flex box layout method for the last week but I feel I can't get my head around. I'm going straight to the point.
Let's look at this scenario
.container{
display:flex;
}
.container div{
border:2px solid red;
background: peachpuff;
height:50px;
flex: 1;
}
<div class="container">
<div class="one"></div>
<div class="two"></div>
<div class="three"></div>
</div>
Here, we have 3 divs items inside of a div container. We applied some height to them and a flex: 1 property, which means that items will grow inside their container, with the 50px height and they will start from a flex-basis of 0.
Let's say now that we change the .container rule to:
.container{
display:flex;
flex-direction: column;
}
.container div{
border:2px solid red;
background: peachpuff;
height:50px;
flex: 1;
<div class="container">
<div class="one"></div>
<div class="two"></div>
<div class="three"></div>
</div>
We added the flex-direction: column; property, but we won't change anything on the other rule, meaning that the same height is applied and the flex:1 property still is applied. Now our divs will collapse, because even thought the flex-grow factor is 1, the flex-basis is set to 0.
There is the think I don't understand, in both case scenario we had empty divs and in both cases we applied the same flex: 1 property, which automatically sets the flex-basis to 0. In the first example however 3 boxes will be created and they will share the same amout of space in the container (even thought they have no HTML content), while in the second example the boxes will collapse and we will just see the border.
The only explanation I could come up with is that those divs (that got no content) items are treated (somehow?) as block-level elements and their content-box width is given a value which is not 0 (and will be taken as the starting basis for the flex-grow), but the height value is set to 0 (and hence will be taken as the starting basis for the flex-grow property, making everything collapse).
However, how can the items be at a flex-level and at a block-level at the same time? If they were at a block-level, then why with if we create this code:
.container{
display:flex;
}
.container div{
border:2px solid red;
background: peachpuff;
height:50px;
}
<div class="container">
<div class="one">one</div>
<div class="two">two</div>
<div class="three">three</div>
</div>
Those items will not be treated as block-level items because no new line will be created between them and they don't extend their width to their container.
I apologize for the long question, I hope I was clear enough and I hope somebody can clarify my dobuts!
Related
I have 2 divs side-by-side in a flexbox. The right hand one should always be the same width, and I want the left hand one to just grab the remaining space. But it won't unless I specifically set its width.
So at the moment, it's set to 96% which looks OK until you really squash the screen - then the right hand div gets a bit starved of the space it needs.
I guess I could leave it as it is but it feels wrong - like there has to be a way to say:
the right one is always the same; you on the left - you get everything that's left
.ar-course-nav {
cursor: pointer;
padding: 8px 12px 8px 12px;
border-radius: 8px;
}
.ar-course-nav:hover {
background-color: rgba(0, 0, 0, 0.1);
}
<br/>
<br/>
<div class="ar-course-nav" style="display:flex; justify-content:space-between;">
<div style="width:96%;">
<div style="overflow:hidden; white-space:nowrap; text-overflow:ellipsis;">
<strong title="Course Name Which is Really Quite Long And Does Go On a Bit But Then When You Think it's Stopped it Keeps on Going for even longer!">
Course Name Which is Really Quite Long And Does Go On a Bit But Then When You Think it's Stopped it Keeps on Going for even longer!
</strong>
</div>
<div style="width:100%; display:flex; justify-content:space-between;">
<div style="color:#555555; margin-right:8px; overflow:hidden; white-space:nowrap; text-overflow:ellipsis;" title="A really really really really really really really really really really really long department name">
A really really really really really really really really really really really long department name
</div>
<div style="color:#555555; text-align:right; white-space:nowrap;">
Created: 21 September 2016
</div>
</div>
</div>
<div style="margin-left:8px;">
<strong>></strong>
</div>
</div>
Use the flex-grow property to make a flex item consume free space on the main axis.
This property will expand the item as much as possible, adjusting the length to dynamic environments, such as screen re-sizing or the addition / removal of other items.
A common example is flex-grow: 1 or, using the shorthand property, flex: 1.
Hence, instead of width: 96% on your div, use flex: 1.
You wrote:
So at the moment, it's set to 96% which looks OK until you really squash the screen - then the right hand div gets a bit starved of the space it needs.
The squashing of the fixed-width div is related to another flex property: flex-shrink
By default, flex items are set to flex-shrink: 1 which enables them to shrink in order to prevent overflow of the container.
To disable this feature use flex-shrink: 0.
For more details see The flex-shrink factor section in the answer here:
What are the differences between flex-basis and width?
Learn more about flex alignment along the main axis here:
In CSS Flexbox, why are there no "justify-items" and "justify-self" properties?
Learn more about flex alignment along the cross axis here:
How does flex-wrap work with align-self, align-items and align-content?
Basically I was trying to get my code to have a middle section on a 'row' to auto-adjust to the content on both sides (in my case, a dotted line separator). Like #Michael_B suggested, the key is using display:flex on the row container and at least making sure your middle container on the row has a flex-grow value of at least 1 higher than the outer containers (if outer containers don't have any flex-grow properties applied, middle container only needs 1 for flex-grow).
Here's a pic of what I was trying to do and sample code for how I solved it.
.row {
background: lightgray;
height: 30px;
width: 100%;
display: flex;
align-items:flex-end;
margin-top:5px;
}
.left {
background:lightblue;
}
.separator{
flex-grow:1;
border-bottom:dotted 2px black;
}
.right {
background:coral;
}
<div class="row">
<div class="left">Left</div>
<div class="separator"></div>
<div class="right">Right With Text</div>
</div>
<div class="row">
<div class="left">Left With More Text</div>
<div class="separator"></div>
<div class="right">Right</div>
</div>
<div class="row">
<div class="left">Left With Text</div>
<div class="separator"></div>
<div class="right">Right With More Text</div>
</div>
I have 2 divs side-by-side in a flexbox. The right hand one should always be the same width, and I want the left hand one to just grab the remaining space. But it won't unless I specifically set its width.
So at the moment, it's set to 96% which looks OK until you really squash the screen - then the right hand div gets a bit starved of the space it needs.
I guess I could leave it as it is but it feels wrong - like there has to be a way to say:
the right one is always the same; you on the left - you get everything that's left
.ar-course-nav {
cursor: pointer;
padding: 8px 12px 8px 12px;
border-radius: 8px;
}
.ar-course-nav:hover {
background-color: rgba(0, 0, 0, 0.1);
}
<br/>
<br/>
<div class="ar-course-nav" style="display:flex; justify-content:space-between;">
<div style="width:96%;">
<div style="overflow:hidden; white-space:nowrap; text-overflow:ellipsis;">
<strong title="Course Name Which is Really Quite Long And Does Go On a Bit But Then When You Think it's Stopped it Keeps on Going for even longer!">
Course Name Which is Really Quite Long And Does Go On a Bit But Then When You Think it's Stopped it Keeps on Going for even longer!
</strong>
</div>
<div style="width:100%; display:flex; justify-content:space-between;">
<div style="color:#555555; margin-right:8px; overflow:hidden; white-space:nowrap; text-overflow:ellipsis;" title="A really really really really really really really really really really really long department name">
A really really really really really really really really really really really long department name
</div>
<div style="color:#555555; text-align:right; white-space:nowrap;">
Created: 21 September 2016
</div>
</div>
</div>
<div style="margin-left:8px;">
<strong>></strong>
</div>
</div>
Use the flex-grow property to make a flex item consume free space on the main axis.
This property will expand the item as much as possible, adjusting the length to dynamic environments, such as screen re-sizing or the addition / removal of other items.
A common example is flex-grow: 1 or, using the shorthand property, flex: 1.
Hence, instead of width: 96% on your div, use flex: 1.
You wrote:
So at the moment, it's set to 96% which looks OK until you really squash the screen - then the right hand div gets a bit starved of the space it needs.
The squashing of the fixed-width div is related to another flex property: flex-shrink
By default, flex items are set to flex-shrink: 1 which enables them to shrink in order to prevent overflow of the container.
To disable this feature use flex-shrink: 0.
For more details see The flex-shrink factor section in the answer here:
What are the differences between flex-basis and width?
Learn more about flex alignment along the main axis here:
In CSS Flexbox, why are there no "justify-items" and "justify-self" properties?
Learn more about flex alignment along the cross axis here:
How does flex-wrap work with align-self, align-items and align-content?
Basically I was trying to get my code to have a middle section on a 'row' to auto-adjust to the content on both sides (in my case, a dotted line separator). Like #Michael_B suggested, the key is using display:flex on the row container and at least making sure your middle container on the row has a flex-grow value of at least 1 higher than the outer containers (if outer containers don't have any flex-grow properties applied, middle container only needs 1 for flex-grow).
Here's a pic of what I was trying to do and sample code for how I solved it.
.row {
background: lightgray;
height: 30px;
width: 100%;
display: flex;
align-items:flex-end;
margin-top:5px;
}
.left {
background:lightblue;
}
.separator{
flex-grow:1;
border-bottom:dotted 2px black;
}
.right {
background:coral;
}
<div class="row">
<div class="left">Left</div>
<div class="separator"></div>
<div class="right">Right With Text</div>
</div>
<div class="row">
<div class="left">Left With More Text</div>
<div class="separator"></div>
<div class="right">Right</div>
</div>
<div class="row">
<div class="left">Left With Text</div>
<div class="separator"></div>
<div class="right">Right With More Text</div>
</div>
I am using ZURB foundation 6 with XY grid and have run into a little problem and most likely something I'm doing wrong.
I want to center elements vertically so I use
<div class="flex-container">
<div class="grid-x grid-padding-x align-middle">
<div class="small-6 cell">Vertically Centered Left Column</div>
<div class="small-6 cell">Vertically Centered Left Column</div>
</div>
</div>
And using jQuery I set the height of flex-container by using windowHeight = $(window).innerHeight();
Voila the items are vertically aligned... However two issues arise from this:
small-6 cell has a width of 50% that is not being respected and shrinks down to the approx length of the text.
flex-container unlike grid-container does not have a width or padding.
To resolve the issue I added some CSS like so:
.flex-container .align-middle {
max-width: 62.5rem;
margin: 0 auto;
width: 100%;
}
So while I've patched the issue I can't help thinking that there must be an easier way, a proper way using just classes. It seems odd that grid-container is setup to do so but flex-container is not.
The main problem here is that with flex-container, the grid-x element will, along being a flex container of its own, also become a flex row item, having the default flex item value 0 1 auto.
This means the grid-x won't grow wider than its content, hence width: 50% won't work on its children (small-6), as their parent doesn't have a width set.
By adding e.g. flex-child-grow or cell to the grid-x element, it will fill its parent's width, and the inner flex items will start behave as expected.
Note 1: With grid-container this is not needed since it is not a flex container, where the grid-x is a normal div, displayed as flex, which, like a block element, by default take full width of its parent.
Note 2: Both flex-container and grid-container does have a default width of 100%, it is the grid-x, when being a flex item, that cause the issue not taking its parent's width by default.
Stack snippet
/* for demo purpose */
body { margin: 0; }
.flex-container { height: 100vh; }
.grid-x { border: 1px solid red; }
.small-6 { border: 1px solid blue; }
<link href="https://cdnjs.cloudflare.com/ajax/libs/foundation/6.4.3/css/foundation.css" rel="stylesheet"/>
<div class="flex-container">
<div class="flex-child-grow grid-x grid-padding-x align-middle">
<div class="small-6 cell">Vertically Centered Left Column</div>
<div class="small-6 cell">Vertically Centered Left Column</div>
</div>
</div>
This question already has answers here:
Make flex items take content width, not width of parent container
(3 answers)
Closed 5 years ago.
See attached snippet.
I need each item to take width space, with respect to content.
flex-items need to be stacked vertically, like in the example.
how to achieve it?
how to do that?
.container {
display:flex;
flex-direction:column;
}
.green {
background-color:green;
}
.red {
background-color:red;
}
<div class="container">
<div class="green"> hello world</div>
<div class="red"> hello world2</div>
</div>
Assuming they still should stack vertically, use display: inline-flex and they will size equally by the content of the widest item.
For each row to collapse to their individual content, use i.e. align-items: flex-start, and note, this will make them collapse when using display: flex too.
Why they stretch to equal width, is because align-items defaults to stretch, so by using any other value they will size by content
.container {
display: inline-flex;
flex-direction:column;
align-items: flex-start;
}
.green {
background-color:green;
}
.red {
background-color:red;
}
<div class="container">
<div class="green"> hello world</div>
<div class="red"> hello world2</div>
</div>
I have a scenario, where I have a container div and inside 2 children div. The children div's would have rows inside and data would be dynamic. So, the height of those could vary. The container height is fixed.
What i want is:
1) If child1 has less data, then it should take height as required and rest height should be taken up by child2 (provided it has enough data) and vice versa, with auto vertical scrollbar
2) If both have less data, then both should occupy 50% height
3) If both have huge data, then also, both should occupy 50% height with vertical scrollbar in each
HTML:
<div class="parent">
<div class="child1">
<div style="height:30px; width:100%;background:red;"></div>
<div class="inner-child">
child1<br>child1<br>child1<br>child1<br>child1<br>child1<br>child1<br>child1<br>
</div>
</div>
<div class="child2">
<div style="height:30px; width:100%;background:red;"></div>
<div class="inner-child">
child2<br>child2<br>child2<br>child2<br>child2<br>child2<br>child2<br>child2<br>
</div>
</div>
</div>
CSS
*{ box-sizing:border-box;}
.parent{display:flex; flex-direction:column; width:800px; height:300px; border:2px solid red;}
.child1{flex-grow:1; width:600px; border:1px solid yellow;}
.child2{flex-grow:1; width:600px; border:1px solid green; }
.inner-child {overflow-y:auto; }
JSFiddle
https://jsfiddle.net/mqa4g74s/2/
I am just not able to fix this. Have tried different approaches, but all in vain. Any help would be appreciated.
With display: flexbox.
DEMO
flex-direction: column sets children placement to the vertical axis
flex-grow: 1 lets children grow equally to the given space
Read more about flexbox in this wonderful article
/edit
Updated Demo