I've reordered some elements in my html using flexbox in the responsive design of a website which works fine but the elements then won't resize properly.
At a breakpoint I have applied a class of flex to the home-promos div and reordered the elements. This works correctly.
The problem then arises when I try to resize the div's to percentage widths. They will only resize up to a certain point, such as 50% and then won't get any bigger.
Is anyone who is better with flexbox than myself able to tell me what the issue is?
.home-promos {
display: flex;
}
.home-promo-center {
order: 1;
}
.home-promo-left {
order: 2;
}
.home-promo-right {
order: 3;
}
<div class="home-promos">
<div class="home-promo-left">
<div class="promo-left-content">
*content*
</div>
</div>
<div class="home-promo-center">
<div class="promo-center-content">
*content*
</div>
</div>
<div class="home-promo-right">
<div class="promo-right-content">
*content*
</div>
</div>
</div>
When you create a flex container (display: flex or display: inline-flex), it comes with several default settings. Among them are:
flex-direction: row - flex items will align horizontally
justify-content: flex-start - flex items will stack at the start of the line
flex-wrap: nowrap - flex items are forced to stay in a single line
flex-shrink: 1 - flex items are allowed to shrink
Note the last two settings.
Your three divs are forced to remain in a single line. Hence, their combined width is limited to the width of the container.
Also, they are allowed to shrink, which prevents them from overflowing the container. This also limits their width.
To apply whatever width you want to each flex item you can override these initial settings with:
flex-wrap: wrap - now there's more space because flex items can break to new lines
flex-shrink: 0 - now there's more space because flex items will not shrink and can overflow their container if necessary
Related
.parent {
background-color: yellow;
display: flex;
justify-content: space-evenly;
}
.parent > div {
background-color: lightblue;
flex: 1;
margin: 5px;
}
<div class="parent">
<div>Child #1</div>
<div>Child #2</div>
<div>Child #3</div>
</div>
In the above simple example, there is a parent div with 3 children divs. All the children have a flex: 1 property and so they are all distributed equally inside their parent. At this point, does the property justify-content: space-evenly of the parent actually count? No matter what value I insert, the result is always the same. Could it be deleted at all?
The justify-content property aligns flex items along the main axis of the current line of the flex container. This is done after any flexible lengths and any auto margins have been resolved. Typically it helps distribute extra free space leftover when either all the flex items on a line are inflexible, or are flexible but have reached their maximum size. It also exerts some control over the alignment of items when they overflow the line.ref
If you have no extra space then you can safely omit the property and nothing will change.
It can make a difference in two situations:
Your layout is dynamic and your item may have a reduced size and a free space is created
You are using justify-content:inherit inside a flex item to get the parent value (not a very common situation by the way)
I am having a chrome specific issue with removing elements from a flexbox item from a height specified flexbox container. This is causing strange display issues for another scrollable flexbox item within that container. It seems that the scrollable item is not properly refresh/repainting, while it is growing.
This is a fairly specific question that's easier to see in the example.
https://jsfiddle.net/gajv6snz/
Note: This is not specific to removing the elements using javascript. Manually deleting them in DevTools causes this also.
<div id="container">
<div id="box1"></div>
<div id="box2"></div>
</div>
#container {
height: 300px;
display: flex;
flex-direction: column;
}
/* Removing elements from #box1 causes display issues with box2 */
#box2 {
overflow-y: scroll;
}
I expect that bottom scrollable flexbox item to take over the full container once the top flexbox item has been emptied. I want the container to remain the same size throughout.
As can be seen in this JS-Fiddle, I basically try to use this CSS to create two divs that should fullfill these requirements:
If twice the space of the wider item is available, both should use 50% width (that works)
If not enough space for both items is available, they should wrap (that works)
If enough space is available for both items, but less than twice the width of the wider one, the narrower item should shrink (that does NOT work, it wraps)
I don't understand this behavior, because I have set flex-shrink for the flex items, so they should be able to shrink - but they don't: If the narrower item would be less than 50% wide, it wraps.
.m {
display: flex;
flex-wrap: wrap;
}
.l_1 {
background-color: red;
flex: 1 1 50%;
}
.r_1 {
background-color: yellow;
flex: 1 1 50%;
}
<div class=m>
<div class=l_1>
left_______________________________________________X
</div>
<div class=r_1>
right
</div>
</div>
(Tested on Firefox and Chrome)
The problem is not flex-shrink. The problem is flex-basis. You have it set to 50%.
This means that flex-grow will add free space to the flex-basis, and each item will wrap quickly, before it has an opportunity to shrink.
Switch from flex-basis: 50% to flex-basis: 0.
More specifically, instead of flex: 1 1 50% use flex: 1, which breaks down to this:
flex-grow: 1
flex-shrink: 1
flex-basis: 0
Now flex-grow distributes free space equally – not proportionally – to both items, and they can shrink before they wrap.
(Here's a more in-depth explanation: Make flex-grow expand items based on their original size)
.m {
display: flex;
flex-wrap: wrap;
}
.l_1 {
background-color: red;
flex: 1;
}
.r_1 {
background-color: yellow;
flex: 1;
}
<div class=m>
<div class=l_1>left_______________________________________________X</div>
<div class=r_1>right</div>
</div>
revised fiddle
When wrapping is enabled, it takes the place of shrinking, so where there is a condition that would trigger shrinking, it wraps instead - until there is only one item in the row, and if that's still bigger than the container, then it will shrink.
So, you need to set flex-basis for all boxes to the minimum size that block should be before wrapping. Note: a box will never shrink further than its minimum content width, meaning you can set flex-basis to 0 and it will go by the minimum content width of each box.
Then, if you want the boxes to expand to fill the available space, then use the flex-grow property (first value in flex) to control the relative amount by which each one should grow.
Flex-shrink will not apply with flex-wrap: wrap also applied. It will line wrap instead.
The only exception to this is when you only have one flex item in the row. Then it should allow for flex-shrink to apply.
Perhaps the appropriate fix is to only apply the flex-wrap within a media query, so it only happens in smaller viewports?
I have a container with display: flex and flex-direction: row.
In that container there is a sub-container also with display: flex but with flex-direction: column.
The problem is if I add an input in the sub-container, the min-width of that input will be ignored.
This is the code where I tried several cases of input in flexbox:
form {
margin: 100px;
}
div.flex_ctn {
display: flex;
}
input {
flex: 1;
min-width: 40px;
}
div.column {
flex-direction: column;
}
div.row {
flex-direction: row;
}
div.sub_ctn {
flex: 1;
/*min-width:40px;*/
}
<form>
<div class="flex_ctn row">
<input />
</div>
<div class="flex_ctn column">
<input />
</div>
<div class="flex_ctn row">
<div class="flex_ctn column sub_ctn">
<input />
</div>
</div>
<div class="flex_ctn column">
<div class="flex_ctn row sub_ctn">
<input />
</div>
</div>
</form>
https://fiddle.jshell.net/s3gu32ku/2/
If you reduce the screen size, the 3rd line doesn't react like the others.
In the css you will see that the last line is set as comment. When that part is enabled you just have to reload and the issue disappears. So, perfect ! I have got the solution!
But that bothers me to use something that I don't understand ^^.
This would be great if someone can explain to me why that error occurs, why that line fix it, and also if there a better way to avoid that issue.
Generally speaking, flex items, by default, cannot be smaller than the size of their content.
More specifically, these are initial settings of flex items:
min-width: auto (applies in flex-direction: row)
min-height: auto (applies in flex-direction: column)
Even more specifically, take a look at the spec language:
4.5. Implied Minimum Size of Flex
Items
To provide a more reasonable default minimum size for flex items, this
specification introduces a new auto value as the initial value of
the min-width and min-height properties defined in CSS 2.1.
auto
On a flex item whose overflow is visible in the main axis, when
specified on the flex item's main-axis min-size property, specifies an
automatic minimum size. It otherwise computes to 0.
In other words, the minimum sizing algorithm applies only on the main axis.
Your input elements in column-direction containers don't get min-width: auto – because the main axis is vertical in those cases – so they shrink and won't overflow the container. You can see this behavior play out on your second input element. Reduce the screen size while viewing this demo.
The same thing happens with the third input, which is a child of a nested flex container with flex-direction: column... EXCEPT, this column-direction container is also a flex item of larger container with flex-direction: row.
This means the main axis of the nested container is horizontal and min-width: auto applies. As a result, this flex item will not shrink below the intrinsic width of the input. For an illustration, see the same demo from above.
Therefore, you need to override this default with min-width: 0 or overflow: hidden (demo).
And for the reasons explained above, the fourth input, contained in a nested row-direction flex container, will also need to have min-width: auto overridden (demo).
Related: Why doesn't flex item shrink past content size?
When using css flexbox the three main browsers appear to behave entirely differently in certain areas.
In this case I am trying to create a grid of images:
<div class="container">
<div class="photo"></div>
<div class="photo"></div>
<div class="photo"></div>
<div class="photo"></div>
<div class="photo"></div>
<div class="photo"></div>
</div>
.container {
display:inline-flex;
flex-flow : column wrap;
align-content : flex-start;
height : 100%;
}
In this example I need a container, itself containing several div elements set up to flow from top to bottom and wrapping when they reach the bottom. Ultimately providing me with columns of photos.
However I need the container to expand horizontally to accommodate the wrapped elements:
Here is a quick jsFiddle to demonstrate.
The behaviour is as follows:
IE 11 - Correct, the container stretches horizontally to wrap each column of wrapped elements
Firefox - The container only wraps the first column of elements, with the rest overflow out.
Chrome - The container always stretches to fill the width of its parent, whatever that may be.
In this instance I would like to achieve the behaviour of IE11 in the other two browsers. Therefore my question is, how can I make a flexbox container expand horizontally to match its column wrap contents.
Thanks in advance.
It's curious that most browsers haven't implemented column flex containers correctly, but the support for writing modes is reasonably good.
Therefore, you can use a row flex container with a vertical writing mode. This will swap the block direction with the inline direction, and thus the flex items will flow vertically. Then you only need to restore the horizontal writing mode inside the flex items.
.container {
display: inline-flex;
writing-mode: vertical-lr;
flex-wrap: wrap;
align-content: flex-start;
height: 350px;
background: blue;
}
.photo {
writing-mode: horizontal-tb;
width: 150px;
height: 100px;
background: red;
margin: 2px;
}
<div class="container">
<div class="photo">1</div>
<div class="photo">2</div>
<div class="photo">3</div>
<div class="photo">4</div>
<div class="photo">5</div>
<div class="photo">6</div>
<div class="photo">7</div>
<div class="photo">8</div>
<div class="photo">9</div>
</div>
This approach may have its own bugs in edge cases, especially if you mix advanced layout techniques like floats and nested flexboxs. But for most cases it seems to work properly.
The spec says that what you're doing should work, but it's implemented incorrectly in every major browser besides Internet Explorer / Edge, making multi-line inline-flex column layouts useless at present for most developers. Here's a Chromium bug report providing an example that is effectively identical to yours, and noting that it renders incorrectly in Chrome, Safari, and Firefox.
The argument from spec is more complicated than I'm able to understand, but the key point is that Flexible Box Layout Module Level 1 spec defines the intrinsic cross-size of a flex container (that is, the intrinsic height of a flex-direction: row flex container or the intrinsic width of a flex-direction: column flex container) in the section Flex Container Intrinsic Cross Size. There, it is stated:
For a multi-line flex container, the min-content/max-content cross size is the sum of the flex line cross sizes
That is, the intrinsic width of a flex-direction: column flex container should be the sum of the widths of its columns, as you'd expect. (There is more complexity than this, and I don't understand it all, but I believe the above to be broadly true.) However, Chrome, Firefox, and Safari all calculate this width incorrectly; setting width: min-content or width: max-content on a column wrap flex box in Chrome, you can clearly see that the width is set to the width of the widest single element.
A silly Chrome-specific workaround exists, but is probably best avoided. Until the bug is fixed, this part of the Flexbox model simply doesn't work as designed and there's no clean solution available.
It seems this issue cannot be solved only with CSS, so I propose you a JQuery solution
container width = position of the last child - position of the container + width of the last child (including margin)
Code :
$(document).ready(function() {
$('.container').each(function( index ) {
var lastChild = $(this).children().last();
var newWidth = lastChild.position().left - $(this).position().left + lastChild.outerWidth(true);
$(this).width(newWidth);
})
});
Demo :
http://jsfiddle.net/qzea320L/
You have a column layout distribution with a fixed height container.
When you set the flex-direction to column you define the Vertical axis as the main axis.
In flexbox that means it will fill up the available height and then create a new column.
In this JSBIN I use javascript to change the container's height and, because of that, you will see the child items move.
PS: you shouldn't rely on IE behavior since their flex support is recent.
Another possible approach:
.container {
column-count: 2; /*or whatever */
}
.container > div {
display: inline-block;
}
https://developer.mozilla.org/en-US/docs/Web/CSS/column-count
You may also need to adjust margin-top of .container > div:first-child if they don't align to the top.