I have this layout:
A row flex container with a definite size, e.g. width: 175px
A flex item
With an indefinite flex-basis, e.g. flex-basis: content
Which is inflexible, e.g. flex: none.
Whose max-content size is larger than the available space
Whose min-content size is smaller than the available space
.flex-container {
display: flex;
width: 175px;
border: 3px solid black;
margin-bottom: 10px;
}
.flex-item {
flex: none;
border: 3px solid blue;
margin: 3px;
}
.box {
display: inline-block;
vertical-align: middle;
width: 100px;
height: 100px;
border: 3px solid red;
margin: 3px;
}
<div class="flex-container">
<div class="flex-item">
<div class="box"></div>
<div class="box"></div>
</div>
</div>
As expected, Firefox breaks lines inside the flex item and sets its width to the available space.
However, Chrome doesn't break lines and thus the flex item overflows the flex container:
Who is right? How can I fix this?
This is what happens:
The Line Length Determination algorithm determines that the flex base size of the flex item is its max-content
Size the item into the available space using its used flex
basis in place of its main size, treating a value of
content as max-content. [...] The flex base size is
the item’s resulting main size.
Since there are no min nor max size constraints, the hypothetical main size of the flex item is the same value
The hypothetical main size is the item’s flex base size
clamped according to its min and max main size properties.
The Resolving Flexible Lengths algorithm freezes the inflexible flex item and sets its target main size to its hypothetical main size
Size inflexible items. Freeze, setting its target main size to its
hypothetical main size any item that has a flex factor of zero
Finally, the main size is that value too:
Set each item’s used main size to its target main size.
Therefore, your flex item should be sized as if it had flex-basis: max-content. Chrome, Edge and IE do it correctly.
Instead, Firefox seems to size as if it had flex-basis: fit-content. IMO this is more reasonable, but it's not standard. Bug 876985 should fix this.
Meanwhile, to achieve the standard behavior on Firefox you can use
flex-basis: -moz-max-content;
.flex-container {
display: flex;
width: 175px;
border: 3px solid black;
margin-bottom: 10px;
}
.flex-item {
flex: none;
flex-basis: -moz-max-content;
border: 3px solid blue;
margin: 3px;
}
.box {
display: inline-block;
vertical-align: middle;
width: 100px;
height: 100px;
border: 3px solid red;
margin: 3px;
}
<div class="flex-container">
<div class="flex-item">
<div class="box"></div>
<div class="box"></div>
</div>
</div>
Instead, if you want Firefox's behavior on other browsers, it's not that easy.
Chrome doesn't support fit-content on flex-basis, but it does on width (prefixed)
flex-basis: auto;
width: -webkit-fit-content;
width: fit-content;
.flex-container {
display: flex;
width: 175px;
border: 3px solid black;
margin-bottom: 10px;
}
.flex-item {
flex: none;
width: -webkit-fit-content;
width: fit-content;
border: 3px solid blue;
margin: 3px;
}
.box {
display: inline-block;
vertical-align: middle;
width: 100px;
height: 100px;
border: 3px solid red;
margin: 3px;
}
<div class="flex-container">
<div class="flex-item">
<div class="box"></div>
<div class="box"></div>
</div>
</div>
However, IE/Edge doesn't support fit-content anywhere. But a max constraint should work on all browsers
max-width: 100%;
box-sizing: border-box; /* Include paddings and borders */
Note the constraint won't include margins, so you may need to correct the percentage using calc, e.g. max-width: calc(100% - 6px).
.flex-container {
display: flex;
width: 175px;
border: 3px solid black;
margin-bottom: 10px;
}
.flex-item {
flex: none;
max-width: calc(100% - 6px);
box-sizing: border-box;
border: 3px solid blue;
margin: 3px;
}
.box {
display: inline-block;
vertical-align: middle;
width: 100px;
height: 100px;
border: 3px solid red;
margin: 3px;
}
<div class="flex-container">
<div class="flex-item">
<div class="box"></div>
<div class="box"></div>
</div>
</div>
Related
This question already has answers here:
Equal space between flex items
(6 answers)
Closed 3 years ago.
The community reviewed whether to reopen this question last month and left it closed:
Original close reason(s) were not resolved
I am creating a flexbox layout. I want two flex containers to be displayed inline and have an equal amount of space between them and back sides of the screen (that is, equal margin-left of the first one and margin-right of the second one).
Now all I know about CSS flexboxes is display: flex and display: inline-flex, so I would want to avoid solution paths that include advanced flexbox properties.
To do so, I set the document's margin and padding to 0, box-sizing to border-box to prevent the containers from changing their original width, set the display property to inline-flex, gave both containers equal measurements.
.item1 {
display: inline-flex;
margin-top: 5vh;
background-color: #ff8000;
border: 3px solid transparent;
height: 30vh;
width: 40vw;
/*margin-left: 9vw;*/
}
.item2 {
margin-top: 5vh;
display: inline-flex;
background-color: #ff8000;
border: 3px solid transparent;
height: 30vh;
width: 40vw;
/*margin-right: 9vw;*/
}
<div class="item1"></div>
<div class="item2"></div>
I also set margin-left of the first item equal to the margin-right of the second one, but they're blatantly different visually.
In this situation, you want to use the flex property justify-content: space-evenly;. What this will do, is spacing all the elements evenly, including the right and left margins.
But for that, you need to create a container with the items you want inside. Look at the following example:
.flex{
display: flex;
justify-content: space-evenly;
}
.item {
margin-top: 5vh;
background-color: #ff8000;
border: 3px solid transparent;
height: 30vh;
width:20vw;
}
<div class="flex">
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
</div>
Check this Example:
.flex {
display: flex;
}
.center {
margin: auto;d
}
.item1 {
display: inline-flex;
margin-top: 5vh;
background-color: #ff8000;
border: 3px solid transparent;
height: 30vh;
width: 40vw;
/*margin-left: 9vw;*/
}
.item2 {
margin-top: 5vh;
display: inline-flex;
background-color: #ff8000;
border: 3px solid transparent;
height: 30vh;
width: 40vw;
/*margin-right: 9vw;*/
}
<!-- display: flex to center it's content-->
<div class="flex">
<!-- margin: auto to to be centered -->
<div class="center">
<div class="item1"></div>
<div class="item2"></div>
</div>
</div>
I have a flex grid with equal columns, but in some of them i have some padding. It appears that this breaks the columns width.
I tried to add the padding to an inner wrapper, but this won't work for me as its percent based.
.grid{
width: 100%;
display: flex;
flex-direction: row;
}
.column {
flex: 1 1 100%;
display: block;
height: 200px;
background-color: #e5e5e5;
border: 1px solid #999999;
&.padd{
padding: 0 5%;
}
}
https://jsfiddle.net/heyapo/8qntbj3c/
Any ideas?
Quite simply flex-grow or flex-basis do not equal width.
Detailed explanation here: by Michael_B.
Padding will add to the dimensions of the element receiving it and the other elements will resolve their sizes accordingly.
If you want to use width...use width (and box-sizing).
.grid {
width: 100%;
display: flex;
flex-direction: row;
}
.column {
width: calc(100% / 3);
display: block;
height: 200px;
background-color: #e5e5e5;
border: 1px solid #999999;
}
padd {
padding: 0 20px;
}
<div class="grid">
<div class="column"></div>
<div class="column"></div>
<div class="column padd"></div>
</div>
I am trying to make my site IE9 compatible but I am using flex boxes in lots of places so I need an alternate method for evenly spacing child elements.
My design is responsive so I need the same effect as flexbox where I can evenly space elements but I am not sure how to do it.
Here is a snippet to show how I am using flexbox in my layout.
#container{
width: 500px;
height: 700px;
border: 1px solid #000;
padding: 10px;
display: flex;
flex-direction: column;
justify-content: space-around;
}
.ele1, .ele2, .ele3{
flex: 0 0 auto;
}
.ele1{
height: 200px;
background-color: red;
}
.ele2{
height: 50px;
background-color: blue;
}
.ele3{
height: 100px;
background-color: green;
}
<div id="container">
<div class="ele1"></div>
<div class="ele2"></div>
<div class="ele3"></div>
</div>
How do I do this without flexbox?
You could use Masonry which is a pure JavaScript (it also supports jQuery), as there are no CSS equivalent, if you do/can not use flexbox.
Use margin-top and margin-bottom in percentages. The distribution is roughly dependant upon how tall each box is. I estimated that there's a total of 10% vertical space inside the container that comprises of padding and borders. That leaves 90% to distribute between the inside walls of the container and between themselves.
#container{
width: 500px;
height: 700px;
border: 1px solid #000;
padding: 10px;
/*display: flex;
flex-direction: column;
justify-content: space-around;*/
}
.ele1, .ele2, .ele3{
/*flex: 0 0 auto;*/
}
.ele1{
height: 200px;
background-color: red;
margin: 10% 0 15%;
}
.ele2{
height: 50px;
background-color: blue;
margin: 25% 0 15%;
}
.ele3{
height: 100px;
background-color: green;
margin: 25% 0 0;
}
<div id="container">
<div class="ele1"></div>
<div class="ele2"></div>
<div class="ele3"></div>
</div>
I discovered a flex box polyfil https://github.com/10up/flexibility
This question concerns a browser with full css3 support including flexbox.
I have a flex container with some items in it. They are all justified to flex-start but I want the last .end item to be justified to flex-end. Is there a good way to do this without modifying the HTML and without resorting to absolute positioning?
.container {
display: flex;
flex-direction: column;
outline: 1px solid green;
min-height: 400px;
width: 100px;
justify-content: flex-start;
}
p {
height: 50px;
background-color: blue;
margin: 5px;
}
<div class="container">
<p></p>
<p></p>
<p></p>
<p class="end"></p>
</div>
Flexible Box Layout Module - 8.1. Aligning with auto margins
Auto margins on flex items have an effect very similar to auto margins in block flow:
During calculations of flex bases and flexible lengths, auto margins are treated as 0.
Prior to alignment via justify-content and align-self, any positive free space is distributed to auto margins in that dimension.
Therefore you could use margin-top: auto to distribute the space between the other elements and the last element.
This will position the last element at the bottom.
p:last-of-type {
margin-top: auto;
}
.container {
display: flex;
flex-direction: column;
border: 1px solid #000;
min-height: 200px;
width: 100px;
}
p {
height: 30px;
background-color: blue;
margin: 5px;
}
p:last-of-type {
margin-top: auto;
}
<div class="container">
<p></p>
<p></p>
<p></p>
</div>
Likewise, you can also use margin-left: auto or margin-right: auto for the same alignment horizontally.
p:last-of-type {
margin-left: auto;
}
.container {
display: flex;
width: 100%;
border: 1px solid #000;
}
p {
height: 50px;
width: 50px;
background-color: blue;
margin: 5px;
}
p:last-of-type {
margin-left: auto;
}
<div class="container">
<p></p>
<p></p>
<p></p>
<p></p>
</div>
This flexbox principle also works horizontally
During calculations of flex bases and flexible lengths, auto margins
are treated as 0. Prior to alignment via justify-content and
align-self, any positive free space is distributed to auto margins in
that dimension.
Setting an automatic left margin for the Last Item will do the work.
.last-item {
margin-left: auto;
}
Code Example:
.container {
display: flex;
width: 400px;
outline: 1px solid black;
}
p {
height: 50px;
width: 50px;
margin: 5px;
background-color: blue;
}
.last-item {
margin-left: auto;
}
<div class="container">
<p></p>
<p></p>
<p></p>
<p class="last-item"></p>
</div>
Codepen Snippet
This can be very useful for Desktop Footers.
As Envato did here with the company logo.
Codepen Snippet
I use to play with both display: flex and margin: auto to have this kind of layouts:
This works well on every browser supporting Flexbox, even IE.
However, it would have been too easy if there hadn't had a little exception: min-height.
You can find a simple working example here. When using min-height on my wrapper, the last element is not pushed to the bottom of this wrapper (IE only).
I can't get this to works, do you girls/guys have any idea? Thanks.
Testing on IE11
.wrapper {
display: flex;
flex-direction: column;
min-height: 300px;
border: 1px solid grey;
padding: 5px;
}
.element {
height: 35px;
border: 1px solid grey;
margin: 5px;
}
.element:last-child {
margin-top: auto;
}
<div class="wrapper">
<div class="element"></div>
<div class="element"></div>
<div class="element"></div>
<div class="element"></div>
</div>
This is a bug in IE's flexbox implementation:
In all other browsers that support flexbox, a flex-direction:column based flex container will honor the containers min-height to calculate flex-grow lengths. In IE10 & 11-preview it only seems to work with an explicit height value.
Bug report - (https://connect.microsoft.com/IE/feedback/details/802625/min-height-and-flexbox-flex-direction-column-dont-work-together-in-ie-10-11-preview#tabs)
It appears that this is on Microsoft's radar and will be fixed some point in the future:
Unfortunately, we are not able to address this feedback in our upcoming release. We will consider your feedback for a future release. We will keep this connect feedback bug active to track this request.
Reply from Microsoft - (https://connect.microsoft.com/IE/feedback/details/802625/min-height-and-flexbox-flex-direction-column-dont-work-together-in-ie-10-11-preview#tabs)
For now the simple solution is to use height:
.wrapper {
border: 1px solid grey;
box-sizing: border-box;
display: flex;
flex-direction: column;
height: 300px;
padding: 5px;
}
.element {
border: 1px solid grey;
height: 35px;
margin: 5px;
}
.element:last-child {
margin-top: auto;
}
<div class="wrapper">
<div class="element"></div>
<div class="element"></div>
<div class="element"></div>
<div class="element"></div>
</div>
But this has the limitation that the box wont grow if more .elements are added so probably isn't what you are after.
There does appear to be a somewhat hacky way of achieving this although it does require an extra containing element:
.container {
display: table;
min-height: 300px;
width: 100%;
}
.wrapper {
border: 1px solid grey;
box-sizing: border-box;
display: flex;
flex-direction: column;
height: 100%;
min-height: 300px;
padding: 5px;
}
.element {
border: 1px solid grey;
height: 35px;
margin: 5px;
}
.element:last-child {
margin-top: auto;
}
<div class="container">
<div class="wrapper">
<div class="element"></div>
<div class="element"></div>
<div class="element"></div>
<div class="element"></div>
</div>
</div>
This adds a container (.container), sets it to display: table; and gives it max-height: 300px;. height: 100%; is then added to .wrapper to get it to fit the full height of .container (effectively 300px) thus making IE behave the same as other browsers.
Compliant browsers ignore this and will continue to follow the min-height: 300px; rule set on .wrapper.
Here's another solution:
Adding an additional container with 2 elements:
an element with an height of "300px"
your ".wrapper"
.container {
display: flex;
}
.min-height-fix {
flex: 0 0 auto;
height: 300px; /* the "min-height" */
width: 1px; /* DEBUG */
background: red; /* DEBUG */
}
.wrapper {
flex: 1 1 auto;
display: flex;
flex-direction: column;
/*min-height: 300px;*/
border: 1px solid grey;
padding: 5px;
flex-wrap: wrap;
}
.element {
height: 35px;
border: 1px solid grey;
margin: 5px;
}
.element:last-child {
margin-top: auto;
}
<div class="container">
<div class="min-height-fix">
</div>
<div class="wrapper">
<div class="element"></div>
<div class="element"></div>
<div class="element"></div>
<div class="element"></div>
</div>
</div>