I need an image in nested flex containers to have width 100%, but this doesn´t work in IE11 when the container has flex-direction: column. I tried:
img {
width: 100%;
max-width: calc( 100% - 0.1px );
}
but this also doesn't work. Any ideas?
section, .articles-wrapper, .article-wrapper {
display: flex;
}
.article-wrapper {
flex-direction: column;
}
img {
width: 100%;
}
html:
<section>
<div class="articles-wrapper">
<div class="article-wrapper">
<img src="http://via.placeholder.com/600x150">
</div>
</div>
</section>
Have you inspected the page to see how the elements are laid out?
The image actually is taking up 100% of it's parent's width, because by default flex-items are not allowed to grow to fill the flex container but expand only enough to display their content.
Both the .articles-wrapper and .article-wrapper elements need to be explicitly allowed to grow, either by specifying flex-grow: 1; or using the shorthand property flex with one of several values:
.articles-wrapper, .article-wrapper {
flex: auto; /* shorthand for flex: 1 1 auto; */
}
OR
.articles-wrapper, .article-wrapper {
flex: 1; /* shorthand for flex: 1 1 0%; */
}
As you get deeper into using flexbox, I recommend keeping Philip Walton's Flexbugs repo at hand which lists common bugs for all browsers as well as workarounds for each.
EDIT Michiel: flex: 1 works in IE11, except that the aspect ratio is not maintained when the window is scaled to a smaller size than the image size. This 'feature' is documented in Flexbugs #5, and can be solved by adding a non-flex wrapper:
<section>
<div class="articles-wrapper">
<div class="article-wrapper">
<div> <!-- ADDED NON-FLEX WRAPPER -->
<img src="http://via.placeholder.com/600x150">
</div>
</div>
</div>
</section>
This question already has answers here:
One flex/grid item sets the size limit for siblings
(6 answers)
Closed 5 years ago.
With flexbox, the childs by default resize according to the widest element.
Is there some way to define that a particular child will control the width, even if it's smaller? With selectors maybe?
Codepen: https://codepen.io/dsomekh/pen/rwEYYE
Code:
.center {
display: flex;
align-items: center;
justify-content: center;
}
.first {
border: 1px solid red;
margin-bottom: 0.5vw;
}
.second {
border: 1px solid red;
}
.wrapper {
font-family: Calibri;
display: flex;
flex-direction: column;
}
<html>
<div class="center">
<div class="wrapper">
<div class="first">This DIV is bigger. However, can it shrink according to it's brother?</div>
<div class="second">This div is smaller.Can it control the width?</div>
</div>
</div>
</html>
Here's the important CSS rule to know:
flex: {number} {number} {number};
The third number is the default size of a flex-item (width, if the flex item is in a row). By default it is auto meaning a flex-item's default size is dictated by it's content.
The first and second numbers are proportionally how much it can grow or shrink by, respectively, compared to other flex items if there is room along the main axis (again, width if this flex item is in a row).
So, you cannot set the default size of a flex-item to be relative to a sibling's intrinsic size - i.e. that which is dictated by it's content - but you can set the default size of a flex-item (and it's sibling items) to all be the same and let them grow or shrink.
I find myself often doing the following:
flex: 1 0 0
on flex items which cause siblings to all be the same size.
All flex-items start out with a default size of 0 and they all grow equally - as given by the first number being the same for all flex items (here it's a one, but it could be any positive number as long as it's the same for every sibling) - as they need to.
Best flexbox learning around is here: https://css-tricks.com/snippets/css/a-guide-to-flexbox/
EDIT
If you knew, in advance, which item was going to be intrinsically bigger, you could probably do it by setting that item to flex: 0 0 auto and letting all other flex-item's grow from flex: 1 0 0, but I have a feeling you don't know in advance which one is bigger.
.wrapper { display: flex; }
.wrapper>div { border: 1px solid #000; }
.first { flex: 1 0 0; }
.second { flex: 0 1 auto; }
<div class="center">
<div class="wrapper">
<div class="first">This DIV is bigger. However, can it shrink according to it's brother?</div>
<div class="second">This div is smaller.Can it control the width?</div>
</div>
</div>
I'm using flex for layout purposes, but the browser does not spread the width equally between items.
.parent {
display: flex;
width: 200px;
}
.btn1 {
flex: 1 1 auto;
}
<div class="parent">
<div class="btn1">
<button align="left" style="width:100%">Ok</button>
</div>
<button align="left" class="btn1">Cancel</button>
<div>
Now, I want the buttons to split the container length 50% / 50%.
But that's not what's happening. I tried using flex: 1 1 auto and flex: 1 1 0 but with no success.
I know that I can use the OK button directly and it will solve my problem, but in my particular scenario it's important to wrap it with a div.
Now, as I understand it, flex should be able to spread the width equally and that's my goal here.
One more thing though, I noticed that the button content seems to have an effect on the width and I want to ignore this effect somehow.
Thanks!
JSFiddle example:
https://jsfiddle.net/edismutko/cvytLkyp/3/
flex-basis: auto vs flex-basis: 0
You're sizing your flex items with flex: 1 1 auto.
However, if you want to distribute space evenly among items, you need to use flex: 1 1 0.
The difference is the flex-basis component.
With flex-basis: 0, every item is considered to have a zero width and flex-grow distributes container space equally among them. This results in all items having the same length.
With flex-basis: auto, the size of the item is factored into the flex-grow calculation and container space is distributed proportionally among items.
So when you want equal length items use flex: 1 1 0, which is the same as flex: 1.
Here's a more detailed explanation: Make flex-grow expand items based on their original size
Default rules on button elements
Browsers apply styles to elements by default. For instance, Chrome adds padding and border widths to button elements.
Reset those defaults.
Now you have two equal width flex items. (Additional styling is up to you.)
.parent {
display: flex;
width: 200px;
}
.btn1 {
flex: 1;
}
button {
padding: 1px 0;
border-left-width: 0;
border-right-width: 0;
}
<div class="parent">
<div class="btn1">
<button align="left" style="width:100%">Ok</button>
</div>
<button align="left" class="btn1">Cancel</button>
<div>
box-sizing: border-box
Something else to consider is including the padding and border lengths in the width / flex-basis calculation. Why are borders causing div to overflow container?
I have 3 divs and if I give flex: 0.5 to first two divs, the last div should move to the next line if I have given flex-wrap: wrap. Please correct if I am wrong.
Following is my html / css:
.parent {
display: flex;
height: 100px;
background-color: red;
flex-wrap: wrap;
}
.child-1 {
background-color: green;
flex: 0.5;
}
.child-2 {
background-color: yellow;
flex: 0.5;
}
.child-3 {
background-color: pink;
}
<div class="parent">
<div class="child-1">LOREN IPSUM LOREN IPSUM</div>
<div class="child-2">LOREN IPSUMLOREN IPSUMLOREN IPSUM</div>
<div class="child-3">LOREN IPSUMLOREN IPSUM</div>
</div>
Please check JSFiddle for this.
Thanks in advance.
The flex-grow property is designed to distribute free space in the container among flex items.
It is not intended for directly or precisely sizing flex items.
From the spec:
flex-grow ... determines how much the flex item will grow relative
to the rest of the flex items in the flex container when positive free
space is distributed.
Hence, flex-grow will not force items to wrap. Here's your example with flex-grow: 1000: demo
To define a length of a flex item use width, height or flex-basis.
Explaining flex-grow: 0.5
When you apply flex:0.5, you're using the flex shorthand property to say this:
flex-grow: 0.5
flex-shrink: 1
flex-basis: 0
The flex-grow component represents a proportion. In this case, it's telling flex items to consume half of the available space in the container relative to the flex-grow factor of its siblings.
So, for instance, if the container were width: 600px and the total width of the three divs was 450px, this would leave 150px in free space (demo).
If each item had flex-grow: 1, then each item would consume 50px of the extra space, and each item would compute to width: 200px (demo).
But in your code, two items have flex-grow: 0.5, and the last item has flex-grow: 0, so here's how it breaks down:
div#1 will get 75px (half of the available space)
div#2 will get 75px (half of the available space)
div#3 will get 0 (because its flex-grow is 0)
These are the computed values now:
div#1 = width: 225px
div#2 = width: 225px
div#3 = width: 150px
demo
.parent {
display: flex;
flex-wrap: wrap;
height: 100px;
background-color: red;
width: 600px;
}
.parent > div {
flex-basis: 150px;
}
.child-1 {
flex: 0.5;
background-color: green;
}
.child-2 {
flex: 0.5;
background-color: yellow;
}
.child-3 {
background-color: pink;
}
<div class="parent">
<div class="child-1">LOREN IPSUM LOREN IPSUM</div>
<div class="child-2">LOREN IPSUMLOREN IPSUMLOREN IPSUM</div>
<div class="child-3"> LOREN IPSUMLOREN IPSUM</div>
</div>
NOTE: The truth of the matter is, because divs #1 and #2 have the same flex-grow factor, and div #3 has a factor of 0, the value is irrelevant. You could use any number to replace 0.5. As long as it's the same in both divs, the items will compute to 225px, because the proportions will be the same.
More information:
flex-grow not sizing flex items as expected
How to get flexbox to include padding in calculations?
What are the differences between flex-basis and width?
Flex = 0.5 means, you have flex-grow = 0.5, flex-shrink = 1 and flex-basis = 0
you are allocating the available space to flex items.
Let's just say, you have a container (Assuming div element) of width: 100vw with two flexible items(div elements) of each 40vw in it. So the total width consumed by your two div elements will be equals to 80vw and the left over available space would be 20vw. Now, You have set the flex = 0.5 for each of the two div elements. so, Each div element will grow up by 20vw/2 = 10vw in order to fully occupy the free space of the container.
Consider one more scenario with 3 div elements, div1 of width = 30vw, div2 of width = 10vw and div3 of width = 25vw.
Total width consumed by 3 div elements = 30 + 10 + 25 = 65vw.
Total available space = 100 - 65 = 35vw.
Now, Each div element is set to flex = 0.3, so each will grow up by 35/3 =~ 11.66vw
I have a fixed-width container into which several variable-width elements must appear in a row, which can spill over into additional rows as necessary.
However, the beginning of each element must be aligned with the one on top of it, so in ASCII art it would look like so (say, padding of 1):
/----------------------------------\
| |
| # One # Two # Three # Four |
| # Five # Six |
| |
\----------------------------------/
In other words:
The first element of every row must be left-aligned
The last element of every row (except for the final row) must be right-aligned
Every element must be left-aligned to the element above it
I'm trying to use flexbox for this without success.
This is the best I've come so far, using flex-wrap: wrap for the container and flex-grow: 1 for the elements.
Problem is that the last row fills out to the edge.
justify-content: flex-start; // this does nothing
If I take away flow-grow: 1 then the elements aren't distributed equally. I also tried fiddling around with last-of-type on the elements but it's also not enough.
Is this even possible with flexbox, or am I going about it the wrong way?
After trying the suggestions here (thanks!) and searching the web long and wide, I've reached the conclusion that this is simply not possible with flexbox. Any by that I mean that others have reached this conclusion while I stubbornly tried to make it work anyway, until finally giving up and accepting the wisdom of wiser people.
There are a couple of links I came across that might explain it better, or different aspects of the requirements, so I'm posting them here for... posterity.
How to keep wrapped flex-items the same width as the elements on the previous row?
http://fourkitchens.com/blog/article/responsive-multi-column-lists-flexbox
There is no easy way to do this with flexbox. But if you are willing to sacrifice IE then you can do it with css grid, add this to the container:
display: grid;
grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
And if you want to have some space between the elements then add
grid-gap: 10px;
I know I am kind of late, but I have been looking for solution for this in past hour or so, and I think I sort of figured it out. Put empty div on the end of your container, and set flex-grow: 1 to it, and nothing else. Also set justify-content: space-between on container, and don't use flex-grow on other items. This will always make last line align left because this div will stretch through all remaining space.
However the problem of this is that it ALWAYS makes last line align left - even if it is the only line, which makes this solution unusable for me, but it might be usable for someone who can expect more than one line of items.
If the width of your items is fixed, you can add several empty divs to the end of your list of items:
<div class="item">meaningful content</div>
<div class="item">meaningful content</div>
<div class="item">meaningful content</div>
<div class="empty-div"></div>
<div class="empty-div"></div>
<div class="empty-div"></div>
and then:
.item, .empty-div{ width: 150px; } // make them the same width
Works perfectly well.
I was able to achieve the desired result with a combination of positive and negative margins.
If each element in the container defines a margin to create a space between them:
.container .element {
flex: 1;
margin: 0px 5px;
}
recover the pixels from the edges of each row in the container with a negative margin of the same amount:
.container {
display: flex;
flex-direction: row;
flex-wrap: wrap;
margin: 0px -5px;
}
This should result in 10px between each element in the row with the first and last of each row at the edge of the container.
One solution that will work in many cases is simply applying padding to the items. Then you can use flex-start, and get spacing in between the cards.
For example
.container {
display: flex;
justify-content: center;
}
.parent {
width: 420px;
display: flex;
flex-wrap: wrap;
flex-direction: row;
justify-content: flex-start;
}
.child {
flex: 0 30%;
min-width: 100px;
padding-left: 10px;
margin-bottom: 10px;
}
.child-content {
background-color: yellow;
border: 1px solid black;
height: 100px;
}
<div class="container">
<div class="parent">
<div class="child">
<div class="child-content">
Box
</div>
</div>
<div class="child">
<div class="child-content">
Box
</div>
</div>
<div class="child">
<div class="child-content">
Box
</div>
</div>
<div class="child">
<div class="child-content">
Box
</div>
</div>
<div class="child">
<div class="child-content">
Box
</div>
</div>
</div>
</div>
CSS Flex 4 columns always starting at left. I cant see wy this is impossible? If the columns should be equal in with, this working for us using calc() and relative units:
/* parent */
.ua-flex {
display: flex;
flex-wrap: wrap;
justify-content: start;
}
/* children */
.ua-flex > * {
flex: 0 0 calc(25% - 1em);
margin: 1em 0 0 0;
}
.ua-flex > :not(:nth-child(4n+4)) {
margin-right: 1.333333em;
}
Im I missing something here? Its all abouth math, the subtracted calc() in this case 1em, gives 3 space of gap 1.333em with margin-right on 3 of 4 columns, and 0.5em subtracted calc() should give 0.666em gap with margin-right on 3 of 4 columns.
Hope this can be useful...
I just stumbled across the same problem and came up with another solution. I can't decide whether it feels kind of dirty or elegant, but decide for yourself.
Add as many empty divs as your maximum number of items per row to the container, assign them the same class as row items but remove any margin or padding from them (basically anything which gives them a height). That'll result in the row behaving as expected because after the last row item, there'll always be enough invisible "spacers" to pad the row. Those being wrapped to the next row have no height, so they shouldn't affect the rest of your page.
Example here:
https://jsfiddle.net/amknwjmj/
.products {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
}
.product {
/* set top and bottom margin only, as left and right
will be handled by space-between */
margin: 0.25rem 0;
/* account your desired margin two times and substract
it from the base width of the row item */
flex-basis: calc(25% - (0.25rem * 2));
}
.product.spacer {
/* remove all properties increasing the element height
from the spacers to avoid them being visible */
margin: 0;
padding: 0;
height: initial;
}
/* start demo styles (purely eye-candy not required for this to work) */
* {
box-sizing: border-box;
font-family: sans-serif;
}
.products {
padding: .25rem .5rem;
background: powderblue;
}
.product {
height: 75px;
line-height: 75px;
padding: .25rem;
text-align: center;
background: steelblue;
color: #fff;
}
.product.spacer {
background: none;
/* of course, spacers should NOT have a border
but they are helpful to illstrate what's going on. */
border: 1px dashed gray;
}
/* end demo styles */
<div class="products">
<article id="product-1" class="product">P1</article>
<article id="product-2" class="product">P2</article>
<article id="product-3" class="product">P3</article>
<article id="product-4" class="product">P4</article>
<article id="product-5" class="product">P5</article>
<div class="product spacer"></div>
<div class="product spacer"></div>
<div class="product spacer"></div>
<div class="product spacer"></div>
</div>
so, you have a container and some stuff inside?
<div class="container">
<span>msg1</span>
<span>msg1</span>
<span>msg1</span>
<span>msg1</span>
<span>msg1</span>
</div>
This is how it works, when you declare display: flex for your container all of its direct children will become flex too, with some default config (align-items:strech).
I guess you already got that, so, maybe you can try using justify-content: space-between which will align your items in the row leaving them equally spaced plus flex-basis: 25% (to certify that there will be always 4 items in a row, change de % as you wish) that is supposed to work for all your lines except the last one. For the last one you can use a css selector (like last-child) and set its property to flex-grow: 0 / flex-shrink:0 (solving one of your problems, if you used flex: 1 1 25% instead of flex-basis) and also align-self: flex-start or whatever you like
You could try it with a fixed-with-pseudo-element:
.container {
display:flex;
justify-content:space-between;
}
.container:after {
content: '';
flex-grow: 0;
width: 25%;
}
.container .element {
width: 25%;
}
You can specify margin-right on every item except the last one in the row of flex-wrap by doing the following:
.item:not(:nth-child(4n)) {
margin-right: 20px;
}
I was facing the same issue and in fact it's really simple. No need to put some
SCSS and or jQuery.
You just need to specify a maximum number of "square", and make a modulo to know if that match with your maxNumber. If its not, you just have to define a quick function that increment your number until that modulo return 0.
When you have your number you just have to loop your html.
For me I was coding on ReactNative:
const RenderInvisibleSquare = (nb) => {
let tab = [];
let i = 1;
for (; (nb + i) % 3 !== 0; i++) {}
for (let n = 0; n < i; n++) {
tab.push(<View style={{ width: 120, height: 120, backgroundColor: 'red' }}/>);
}
return tab;
};
<ScrollView>
{
data.map(item => (
<View>
<View style={{ marginVertical: 5 }}>
<Text style={{ textAlign: 'center', color: '#7E8BF5' }}>{item.title}</Text>
</View>
<View style={{ flex: 1, flexWrap: 'wrap', alignItems: 'center', justifyContent: 'space-around', flexDirection: 'row' }}>
{
item.data.map(elem => (
<View style={{ width: 120, height: 120, marginBottom: 10, backgroundColor: 'red' }} />
))
}
{ item.data.length % 3 !== 0 && RenderInvisibleSquare(item.data.length)}
</View>
</View>
))
}
</ScrollView>
If you dont want content (backgroundColor: 'red') in my case you juste have to make it 'transparent'.