In the following example, the flex-basis: 30px and width: 30px of a flex item will result in different container width(flex-basis is shorter).
How does flex-basis affect its parent width in the following example:
.flex-container {
padding: 0;
margin: 0;
display: flex;
border: 1px solid blue;
}
.grand {
display: flex;
border: 1px solid green;
}
.flex-item {
background: tomato;
padding: 10px;
border: 1px solid red;
color: white;
font-size: 2em;
}
.flex1 {
flex-shrink: 0; /* added according to Michael_B's answer */
flex-basis: 100px;
}
<div class="grand">
<div class="flex-container">
<div class="flex-item flex1">1</div>
<div class="flex-item flex2">22222 222222222</div>
</div>
</div>
The is the expected behavior:
.flex-container {
padding: 0;
margin: 0;
display: flex;
border: 1px solid blue;
}
.grand {
display: flex;
border: 1px solid green;
}
.flex-item {
background: tomato;
padding: 10px;
border: 1px solid red;
color: white;
font-size: 2em;
}
.flex1 {
/* flex-basis: 100px; */
width: 100px;
}
<div class="grand">
<div class="flex-container">
<div class="flex-item flex1">1</div>
<div class="flex-item flex2">22222 222222222</div>
</div>
</div>
In the flex-basis version, the flex2 item will wrap the text, while the width version will not. How did that happen.
Related
I'm using align-items and justify-content to center the elements, my html is:
<div class="flex-container">
<div class="item-1">div</div>
<div class="item-2">w=250px</div>
<div class="item-3">h=250px</div>
<div class="item-4">w/h=300px</div>
<div class="item-5">w=350px</div>
<div class="item-6">w=350px</div>
</div>
my css code is something like:
.flex-container {
display: flex;
flex-direction: row;
flex-wrap: wrap;
align-items: center;
justify-content: center;
align-content: center;
}
(I leave out some unimportant css code.)
so the result will be like:
but if I shrink the browser window, it will be like:
I don't understand why there is so much space between two lines (I know using align-content: center; can fix, but I want to know how those excess space is there in the first place)
* {
box-sizing: border-box;
font-size: 1.5rem;
}
html {
background: #b3b3b3;
padding: 5px;
}
body {
background: #b3b3b3;
padding: 5px;
margin: 0;
}
.flex-container {
background: white;
padding: 10px;
border: 5px solid black;
height: 800px;
display: flex;
flex-direction: row;
flex-wrap: wrap;
align-items: center;
justify-content: center;
}
.item-1 {
background: #ff7300;
color: white;
padding: 10px;
border: 5px solid black;
margin: 10px;
}
.item-2 {
background: #ff9640;
color: white;
padding: 10px;
border: 5px solid black;
margin: 10px;
width: 250px;
/* font-size: 1.8rem; */
}
.item-3 {
background: #ff9640;
color: white;
padding: 10px;
border: 5px solid black;
margin: 10px;
height: 250px;
}
.item-4 {
background: #f5c096;
color: white;
padding: 10px;
border: 5px solid black;
margin: 10px;
width: 300px;
height: 300px;
}
.item-5 {
background: #d3c0b1;
color: white;
padding: 10px;
border: 5px solid black;
margin: 10px;
width: 350px;
}
.item-6 {
background: #d3c0b1;
color: white;
padding: 10px;
border: 5px solid black;
margin: 10px;
width: 350px;
}
<div class="flex-container">
<div class="item-1">div</div>
<div class="item-2">w=250px</div>
<div class="item-3">h=250px</div>
<div class="item-4">w/h=300px</div>
<div class="item-5">w=350px</div>
<div class="item-6">w=350px</div>
</div>
and if I shrink the browser window more, then there is no such excess space:
align-content
Note that align-content: stretch is also in play here.
The align-content property distributes free space among flex lines. It's default value is stretch.
So when your items wrap to two lines, align-content: stretch distributes free space equally across lines.
align-items
Remove align-items: center from the container. You'll then notice that when items wrap, there is no gap between lines (or "rows", in this case). demo
Line heights are set by align-content, the height of the items, and the content of the items.
align-content and align-items working together
Restore align-items: center. Now when items wrap, there is a visible gap between lines.
This is because align-items: center positions the items in the vertical center of the line, based on line heights established by align-content: stretch, item heights, and item content.
The line heights are set here (with align-content: stretch and align-items: stretch):
... and continue here (with align-content: stretch and align-items: center):
align-items is having no effect on the height of the flex line. That job is andled by align-content.
However, by changing the value of align-content (to flex-start, flex-end, space-between, center, etc.), you pack the flex lines, squeezing out the free space, and hence removing the gaps.
Why is the first row taller than the second row with align-content: stretch?
The container is set to height: 800px.
There are two items with defined heights:
.item-3 { height: 250px }
.item-4 { height: 300px }
When .item-5 and .item-6 form the second row, the free space in the container is, in its simplest form, 500px (800px - 300px).
So, in a container with two rows and align-content: stretch, 250px is distributed to the height of each row.
first row is 300px (defined height) plus 250px (free space)
second row is 250px (free space)
That's why the first row is taller.
Just note that the free space calculation above is slightly off in the actual layout. That's because there is text in the items, which consumes free space. You can factor in the height of the text to get the precise figures, or remove the text altogether to see the calculations above fall into place.
More details:
How does flex-wrap work with align-self, align-items and align-content?
Equal height rows in a flex container
To make it easy, I will reduce the code so we can better understand the behavior.
Let's consider this initial code:
* {
box-sizing: border-box;
font-size: 1.5rem;
}
html {
background: #b3b3b3;
padding: 5px;
}
body {
background: #b3b3b3;
padding: 5px;
margin: 0;
}
.flex-container {
background: white;
padding: 10px;
border: 5px solid black;
height: 400px;
display: flex;
flex-direction: row;
flex-wrap:wrap;
}
.item-1 {
background: #ff7300;
color: white;
padding: 10px;
border: 5px solid black;
margin: 10px;
}
.item-2 {
background: #ff9640;
color: white;
padding: 10px;
border: 5px solid black;
margin: 10px;
width: 250px;
}
.item-3 {
background: #ff9640;
color: white;
padding: 10px;
border: 5px solid black;
margin: 10px;
height: 150px;
}
<div class="flex-container">
<div class="item-1">div</div>
<div class="item-2">w=250px</div>
<div class="item-3">h=150px</div>
</div>
The container has a fixed height and only one element has a fixed height and the other will be stretched to fill the parent height since by default align-items is stretch.
Now let's decrease the width of the container in order to make the third element in the second row:
* {
box-sizing: border-box;
font-size: 1.5rem;
}
html {
background: #b3b3b3;
padding: 5px;
}
body {
background: #b3b3b3;
padding: 5px;
margin: 0;
}
.flex-container {
background: white;
padding: 10px;
border: 5px solid black;
height: 400px;
display: flex;
flex-direction: row;
flex-wrap:wrap;
width:500px;
}
.item-1 {
background: #ff7300;
color: white;
padding: 10px;
border: 5px solid black;
margin: 10px;
}
.item-2 {
background: #ff9640;
color: white;
padding: 10px;
border: 5px solid black;
margin: 10px;
width: 250px;
}
.item-3 {
background: #ff9640;
color: white;
padding: 10px;
border: 5px solid black;
margin: 10px;
height: 150px;
}
<div class="flex-container">
<div class="item-1">div</div>
<div class="item-2">w=250px</div>
<div class="item-3">h=150px</div>
</div>
Here we have a complex behavior where we have a multiline flex container where item1 and item2 belong to the first line and item3 to the second line. I cannot explain very well how the height of each line is defined (the complex part). After this each flex item will stretch to fill the height of its line unless it has a fixed height like item3 or we change the alignment.
Now, if we change align-items to something different than stretch we will have the gap:
* {
box-sizing: border-box;
font-size: 1.5rem;
}
html {
background: #b3b3b3;
padding: 5px;
}
body {
background: #b3b3b3;
padding: 5px;
margin: 0;
}
.flex-container {
background: white;
padding: 10px;
border: 5px solid black;
height: 400px;
display: flex;
flex-direction: row;
flex-wrap:wrap;
width:500px;
align-items:flex-start;
}
.item-1 {
background: #ff7300;
color: white;
padding: 10px;
border: 5px solid black;
margin: 10px;
}
.item-2 {
background: #ff9640;
color: white;
padding: 10px;
border: 5px solid black;
margin: 10px;
width: 250px;
}
.item-3 {
background: #ff9640;
color: white;
padding: 10px;
border: 5px solid black;
margin: 10px;
height: 150px;
}
<div class="flex-container">
<div class="item-1">div</div>
<div class="item-2">w=250px</div>
<div class="item-3">h=150px</div>
</div>
If we compare the above code with the previous one we can see that item3 kept his place and only the height of item1 and item2 have changed. This explain that align-items will align items inside their lines that was previously defined due to wrapping.
In other words, when we have a multiline flex container we first define the lines (considering the height of the container, the height of elements and other flexbox properties) then we align the items inside their line and the gap we have is due to how the alignment is done.
Here is a better example to show different cases:
.flex-container {
background: white;
padding: 10px;
border: 5px solid black;
height: 200px;
display: inline-flex;
vertical-align:top;
flex-direction: row;
flex-wrap:wrap;
width:100px;
}
.item-1 {
background: #ff7300;
color: white;
border: 1px solid black;
margin: 2px;
}
.item-2 {
background: #ff9640;
color: white;
border: 1px solid black;
margin: 2px;
width: 70px;
}
.item-3 {
background: #ff9640;
color: white;
border: 1px solid black;
margin: 2px;
height: 50px;
}
<div class="flex-container">
<div class="item-1">A</div>
<div class="item-2">B</div>
<div class="item-3">C</div>
</div>
<div class="flex-container" style="align-items:flex-start;">
<div class="item-1">A</div>
<div class="item-2">B</div>
<div class="item-3">C</div>
</div>
<div class="flex-container" style="align-items:center;">
<div class="item-1">A</div>
<div class="item-2">B</div>
<div class="item-3">C</div>
</div>
<div class="flex-container" style="align-items:flex-end;">
<div class="item-1">A</div>
<div class="item-2">B</div>
<div class="item-3">C</div>
</div>
<div class="flex-container" style="align-items:flex-end;">
<div class="item-1">A</div>
<div class="item-2">B</div>
<div class="item-3" style="margin-bottom:auto;">C</div>
</div>
<div class="flex-container">
<div class="item-1" style="margin-top:auto;">A</div>
<div class="item-2">B</div>
<div class="item-3" >C</div>
</div>
We can clearly notice that we have the same lines accross all the container and only the alignment is changing which create different gaps.
In case there is no element with a fixed height, the lines will have the same height, so the container will be splitted equally.
.flex-container {
background: white;
padding: 10px;
border: 5px solid black;
height: 200px;
display: inline-flex;
vertical-align:top;
flex-direction: row;
flex-wrap:wrap;
width:100px;
}
.item-1 {
background: #ff7300;
color: white;
border: 1px solid black;
margin: 2px;
}
.item-2 {
background: #ff9640;
color: white;
border: 1px solid black;
margin: 2px;
width: 70px;
}
.item-3 {
background: #ff9640;
color: white;
border: 1px solid black;
margin: 2px;
}
<div class="flex-container">
<div class="item-1">A</div>
<div class="item-2">B</div>
<div class="item-3">C</div>
</div>
<div class="flex-container" style="align-items:flex-start;">
<div class="item-1">A</div>
<div class="item-2">B</div>
<div class="item-3">C</div>
</div>
<div class="flex-container" style="align-items:center;">
<div class="item-1">A</div>
<div class="item-2">B</div>
<div class="item-3">C</div>
</div>
<div class="flex-container" style="align-items:flex-end;">
<div class="item-1">A</div>
<div class="item-2">B</div>
<div class="item-3">C</div>
</div>
<div class="flex-container" style="align-items:flex-end;">
<div class="item-1">A</div>
<div class="item-2">B</div>
<div class="item-3" style="margin-bottom:auto;">C</div>
</div>
<div class="flex-container">
<div class="item-1" style="margin-top:auto;">A</div>
<div class="item-2">B</div>
<div class="item-3" >C</div>
</div>
By changing align-content we will change how the lines are created before considering align-items to align the items inside their lines:
.flex-container {
background: white;
padding: 10px;
border: 5px solid black;
height: 200px;
display: inline-flex;
vertical-align:top;
flex-direction: row;
flex-wrap:wrap;
width:100px;
}
.item-1 {
background: #ff7300;
color: white;
border: 1px solid black;
margin: 2px;
}
.item-2 {
background: #ff9640;
color: white;
border: 1px solid black;
margin: 2px;
width: 70px;
}
.item-3 {
background: #ff9640;
color: white;
border: 1px solid black;
margin: 2px;
height:50px;
}
<div class="flex-container">
<div class="item-1">A</div>
<div class="item-2">B</div>
<div class="item-3">C</div>
</div>
<div class="flex-container" style="align-content:flex-start;">
<div class="item-1">A</div>
<div class="item-2">B</div>
<div class="item-3">C</div>
</div>
<div class="flex-container" style="align-content:center;">
<div class="item-1">A</div>
<div class="item-2">B</div>
<div class="item-3">C</div>
</div>
<div class="flex-container" style="align-content:flex-end;">
<div class="item-1">A</div>
<div class="item-2">B</div>
<div class="item-3">C</div>
</div>
In order to understand the complex part of this answer (how lines are defined) you can refer to the specification : https://www.w3.org/TR/css-flexbox-1/#layout-algorithm
I'm using flexbox to create a two-columns layout with a header row.
* {
box-sizing: border-box;
position: relative;
}
.container {
border: 2px solid gray;
display: flex;
flex-wrap: wrap;
height: 300px;
}
.header {
flex-basis: 100%;
border: 2px solid magenta;
height: 50px;
line-height: 50px;
text-align: center;
}
.column1 {
flex-basis: 150px;
/* height: calc(100% - 50px); */
border: 2px solid green;
}
.column2 {
/* height: calc(100% - 70px); */
flex: 1;
border: 2px solid orange;
}
<div class='container'>
<div class='header'>it's a header</div>
<div class='column1'>column 1</div>
<div class='column2'>column 2</div>
</div>
Feel free to see the full example here.
As you can see in the example there is a gap between columns and header. My aim is to stretch columns vertically to fill whole empty space in the container.
I can achieve it by setting height property like calc(100% - <header-height>). Is it the correct way?
I just tried to use "flex" style and set align-items: stretch to the container and align-self: stretch to columns but without success. Did I probably miss something trying to implement it this way?
I think specifying flex-direction as column is appropriate in this case.
The second row is itself a flex element with the flex-direction: row. You can fill the rest of the remaining space using flex: 1, which is equivalent to flex-grow: 1.
* {
box-sizing: border-box;
}
.container {
border: 2px solid gray;
display: flex;
flex-direction: column;
flex-wrap: wrap;
height: 300px;
}
.header {
border: 2px solid magenta;
height: 50px;
line-height: 50px;
text-align: center;
}
.subcontainer {
display: flex;
flex-direction: row;
flex: 1;
}
.column1 {
flex-basis: 150px;
border: 2px solid green;
}
.column2 {
flex: 1;
border: 2px solid orange;
}
<div class='container'>
<div class='header'>it's a header</div>
<div class="subcontainer">
<div class='column1'>column 1</div>
<div class='column2'>column 2</div>
</div>
</div>
Do it like shown below
* {
box-sizing: border-box;
}
body,
html {
height: 100%;
}
.container {
border: 2px solid gray;
display: flex;
flex-direction: column;
height: 100%;
}
.header {
width: 100%;
border: 2px solid magenta;
height: 50px;
line-height: 50px;
text-align: center;
}
.body-container {
display: flex;
width: 100%;
flex: 1;
}
.column1 {
width: 50%;
border: 2px solid green;
}
.column2 {
width: 50%;
border: 2px solid orange;
}
<div class='container'>
<div class='header'>it's a header</div>
<div class="body-container">
<div class='column1'>column 1</div>
<div class='column2'>column 2</div>
</div>
</div>
If you have multiple containers with 1px border, all containers next to each other generate a 2px border. So in order to get rid of that you always set e.g. border-right: none; and then add border-right: 1px; to the last child to make all containers have 1px border in all sides.
But if you use flexbox flex-basis rule to break containers into next line, it breaks whole border-right idea, the last container in the line before the break always stays left out with no border.
e.g. in this example I have 5 containers, but I want 4 per line and when it breaks into new line, you can see the border-right issue:
.wrapper {
display: flex;
flex-wrap: wrap;
width: 400px;
}
.container {
flex-basis: 20%;
border: 1px solid #000;
border-right: none;
margin-bottom: 1px;
min-height: 100px;
width: 100px;
display: flex;
justify-content: center;
align-items: center;
}
.container:last-child {
border-right: 1px solid #000;
}
<div class="wrapper">
<div class="container">1</div>
<div class="container">2</div>
<div class="container">3</div>
<div class="container">4</div>
<div class="container">5</div>
</div>
https://jsfiddle.net/45kngj9p/
Since you know how many flex items there are in each row, you can use the :nth-child() selector to apply borders to items missed by the main rule.
.wrapper {
display: flex;
flex-wrap: wrap;
width: 400px;
}
.container {
flex-basis: 20%;
border-top: 1px solid #000;
border-bottom: 1px solid #000;
border-right: 1px solid #000;
margin-bottom: 1px;
min-height: 100px;
display: flex;
justify-content: center;
align-items: center;
}
.container:nth-child(4n + 1) { /* add border to first child in each row */
border-left: 1px solid red;
}
<div class="wrapper">
<div class="container">1</div>
<div class="container">2</div>
<div class="container">3</div>
<div class="container">4</div>
<div class="container">5</div>
</div>
<hr>
<div class="wrapper">
<div class="container">1</div>
<div class="container">2</div>
<div class="container">3</div>
</div>
<hr>
<div class="wrapper">
<div class="container">1</div>
<div class="container">2</div>
<div class="container">3</div>
<div class="container">4</div>
<div class="container">5</div>
<div class="container">6</div>
<div class="container">7</div>
<div class="container">8</div>
<div class="container">9</div>
<div class="container">10</div>
</div>
Remove Border:none; and add margin-left:-1px;
.container {
flex-basis: 20%;
border: 1px solid #000;
margin-left:-1px;
margin-bottom: 1px;
min-height: 100px;
width: 100px;
display: flex;
justify-content: center;
align-items: center;
}
That's it!
You can try these solutions:
1
Here you don't need the .container:last-child styles.
.container {
flex-basis: 20%;
border: 1px solid #000;
margin-bottom: 1px;
margin-right: -1px;
min-height: 100px;
width: 100px;
display: flex;
justify-content: center;
align-items: center;
}
2
This one works for boxes number 4, 8, 12, etc.
.container {
flex-basis: 20%;
border: 1px solid #000;
border-right: none;
margin-bottom: 1px;
min-height: 100px;
width: 100px;
display: flex;
justify-content: center;
align-items: center;
}
.container:last-child,
.container:nth-child(4n) {
border-right: 1px solid #000;
}
I have the following layout:
.main {
height: 200px;
width: 300px;
border: 1px solid black;
background-color: rgba(255, 46, 0, 0.5);
}
.container {
height: 200px;
width: 200px;
margin: auto;
border: 1px solid black;
z-index: 2;
background-color: white;
display: flex;
align-items: stretch;
justify-content: center;
}
.text1 {
border: 1px solid red;
flex-wrap: nowrap;
flex-grow: 1;
}
.text2 {
border: 1px solid blue;
flex-wrap: nowrap;
flex-grow: 2;
}
<div class="main">
<div class="container">
<div class="text1">Lorem impsum pimpsum</div>
<div class="text2">Tex2</div>
</div>
</div>
I would like my text to wrap inside the div .text1 and .text2 without disturbing the flexgrow. In other words, is there any way to force flexbox to stay at the same size no matter the text in it?
I'm using Chrome. Codepen link: https://codepen.io/Konrad29/pen/Oxbmqx
By setting the flex-basis to 0, you control the width (distribute the space) with flex-grow
Update these rules
.text1{
border: 1px solid red;
flex-wrap:nowrap;
flex:1 1 0; /* updated */
min-width: 0; /* might be needed as well */
}
.text2{
border: 1px solid blue;
flex-wrap:nowrap;
flex:2 2 0; /* updated */
min-width: 0; /* might be needed as well */
}
This will make the text1 to take 1/3 of the available space and the text2 2/3.
Based on what content you will put in each text1/2, you might also need to set min-width, which defaults to auto, to 0 to allow it the be smaller than its content
Updated codepen
Stack snippet
.main{
height: 200px;
width: 300px;
border: 1px solid black;
background-color :rgba(255, 46, 0, 0.5);
}
.container{
height: 200px;
width: 200px;
margin: auto;
border: 1px solid black;
z-index:2;
background-color: white;
display: flex;
align-items: stretch;
justify-content:center;
}
.text1{
border: 1px solid red;
flex-wrap:nowrap;
flex:1 1 0;
}
.text2{
border: 1px solid blue;
flex-wrap:nowrap;
flex:2 2 0;
}
<div class="main">
<div class="container">
<div class="text1">Lorem impsum pimpsum</div>
<div class="text2">Tex2</div>
</div>
</div>
I have a simple site layout of Header and a 3 columns main section. The middle column should contain a lengthy content so I would like it to scroll, I can't make it happen.
Here is a prototype of the problem:
http://codepen.io/ValYouW/pen/GZxKBa
UPDATE: Sorry for not mentioning, but I meant for horizontal-scroll, not vertical...
html, body {
height: 100%;
}
body {
margin: 0;
padding: 0;
display: flex;
box-sizing: border-box;
}
#layout {
display: flex;
flex: 1;
flex-direction: column;
border: 4px solid red;
}
#header {
border: 2px solid yellow;
}
#main {
border: 2px solid green;
display: flex;
flex: 1;
flex-direction: row;
}
#facets{
border: 2px solid pink;
display: flex;
width: 100px;
}
#report {
border: 2px solid pink;
display: flex;
flex: 1;
flex-direction: column;
}
#rightside {
border: 2px solid pink;
display: flex;
width: 100px;
}
#chips {
border: 2px solid orange;
}
#leads-grid {
border: 4px solid orange;
display: flex;
flex: 1;
overflow: auto;
}
#grid1 {
border: 2px solid black;
width: 1000px;
}
<div id="layout">
<div id="header">Header</div>
<div id="main">
<div id="facets">Facets</div>
<div id="report">
<div id="chips">Chips</div>
<div id="leads-grid">
<div id="grid1">How to make my parent (#leads-grid) scroll?</div>
</div>
</div>
<div id="rightside">Right side</div>
</div>
<div>
Any ideas how to make #leads-grid to scroll?
Thx.
for the leads-grid have scroll his son (grid1) needs to surpass the content. try to put a lot of br's into the content of grid1 and leads-grid will create a scroll.
Your #leads-grid is scrolling already.
You just need to add more content to #leads-grid.
See code below. I have added height: 5000px to #grid1 as inline style. Scroll appears.
html,
body {
height: 100%;
}
body {
margin: 0;
padding: 0;
display: flex;
box-sizing: border-box;
}
#layout {
display: flex;
flex: 1;
flex-direction: column;
border: 4px solid red;
}
#header {
border: 2px solid yellow;
}
#main {
border: 2px solid green;
display: flex;
flex: 1;
flex-direction: row;
}
#facets {
border: 2px solid pink;
display: flex;
width: 100px;
}
#report {
border: 2px solid pink;
display: flex;
flex: 1;
flex-direction: column;
}
#rightside {
border: 2px solid pink;
display: flex;
width: 100px;
}
#chips {
border: 2px solid orange;
}
#leads-grid {
border: 4px solid orange;
display: flex;
flex: 1;
overflow: auto;
}
#grid1 {
border: 2px solid black;
width: 1000px;
}
<div id="layout">
<div id="header">Header</div>
<div id="main">
<div id="facets">Facets</div>
<div id="report">
<div id="chips">Chips</div>
<div id="leads-grid">
<div id="grid1" style="height: 5000px;">How to make my parent (#leads-grid) scroll?</div>
</div>
</div>
<div id="rightside">Right side</div>
</div>
<div>