Understanding the difference between the flex and flex-grow properties - css

What is the difference in effect between setting flex: 1; and setting flex-grow: 1;? When I set the former in my code, the two columns I have display with equal width, while they do not do so when I set the latter.
This is strange, as I assumed that setting flex: 1; only affects the flex-grow property.

flex is a shorthand property of flex-grow, flex-shrink and flex-basis.
In this case, flex: 1 sets
flex-grow: 1
flex-shrink: 1
flex-basis: 0 (in old spec drafts it was flex-basis: 0%)
If you only use flex-grow: 1, you will have
flex-grow: 1
flex-shrink: 1
flex-basis: auto
Then, the difference is that the flex base size will be 0 in the first case, so the flex items will have the same size after distributing free space.
In the second case each flex item will start with the size given by its content, and then will grow or shrink according to free space. Most probably the sizes will end up being different.

Related

Difference between flex: 0 0 33% and flex 0 1 33%

What's the difference between those to flex-items properties and which one I should use in order to build a grid system ?
For example bootstrap system and ant-design uses flex: 0 0 33 and max-width: 33% (as an example). Why the dont use flex: 0 1 33 for example.
/* Three values: flex-grow | flex-shrink | flex-basis */
flex: 0 0 33%;
The flex-grow CSS property sets the flex grow factor of a flex item's main size.
The flex-shrink CSS property sets the flex shrink factor of a flex item. If the size of all flex items is larger than the flex container, items shrink to fit according to flex-shrink.
The flex-basis CSS property sets the initial main size of a flex item. It sets the size of the content box unless otherwise set with box-sizing.
To answer you question, the reason they use that property is to maintain consistence of rows and columns, it means they will have a max with of 33% and will neither shrink nor grow as opposed to yours where you have a flex-shrink of 1.
This will cause the item to collapse incase the contents are bigger than the parent element.

How do I control the order in which flexbox items grow/shrink?

I have a flex container with three children. Each child has a min and max width and I would like to have them grow/shrink in a specific order. So, as the window width decreases, Item1 should shrink to its min width, and then Item2 should decrease to its min width, followed by Item3. Can someone help me figure out what I'm doing wrong? I've tried to discern from the documentation how to get the order set up, but I'm just not understanding.
<div className="MainContainer">
<div className="Item1">
I should shrink first/expand last!
</div>
<div className="Item2">
I should shrink & expand second!
</div>
<div className="Item3">
I should shrink last/expand first!
</div>
</div>
And my CSS:
.MainContainer {
display: flex;
flex-direction: row;
justify-content: center;
padding-left: 15px;
padding-right: 15px;
}
//Should shrink first/expand last
.Item1{
min-width: 350px;
max-width: 816px;
flex: 1;
flex-grow: 0;
}
//Should shrink/expand second
.Item2{
max-width: 816px;
flex: 1;
flex-grow: 1;
}
//Should shrink last/expand first
.Item3{
min-width: 300px;
max-width: 224px;
flex: 1;
flex-grow: 2;
}
That's not the way flexbox works, you can't say "shrink last" - all you can say is "shrink/grow at a rate in proportion to other items shrink/growth rates"
I imagine you're also generally setting too many widths and confusing yourself about which properties are actually taking effect. Just let things happen naturally and see where they end up.
This is an example with commentary that will hopefully paint a clearer picture:
.Item1{
flex-grow: 1;
flex-shrink: 0;
flex-basis: 350px;
// this means it will not shrink, have a min width of 350px, and grow at a rate of "1" (proportional to the other children in it's container) to fill up the remaining space
// flex: 1 0 350px; <- the above is the same as this
}
//Should shrink/expand second
.Item2{
flex-grow: 1;
flex-shrink: 0;
flex-basis: auto; // this means it will not shrink, have a min width of it's "intrinsic size" and grow AT THE SAME RATE (1) as Item1 to fill up the remaining space
// flex: 1; <- this is the shorthand for the above
}
The best reference on the internet for flexbox is https://css-tricks.com/snippets/css/a-guide-to-flexbox/
Using this SO question as a starting point, I was able to achieve my goal.
I have slightly simplified the sizes to make it easier to read, but I have gotten my project working in the same way.
Check out this codesandbox to see my fully working implementation using React and TypeScript (popping the preview out to a new window will help see what's going on). I have created a custom component that will show the current size of each element as the window is resized. This is not necessary for doing this yourself, of course.
The main thing to look at is the wrappers that hold my resizing elements and the styles in the scss, specifically how the 'first-to-shrink' and 'second-to-shrink' classes are combined with the max-width, min-width, and flex-basis set on individual components. One other 'gotcha' is that I had to set the flex-basis of the container that housed two elements as the sum of the children's max-widths.
I have 3 objects that need to shrink/expand in a specific order. In display order, they are:
Secondary Document - Primary Document - Answer Pane
Secondary Document has a min width of 250px, a max width of 500px, and should shrink first.
Primary Document has a min width of 250px, a max width of 500px, and should shrink last.
Answer Pane has a min width of 150px, a max width of 300px, and should shrink second.
After all 3 objects have shrunk to their minimum, there is overflow that happens, but that is ok with my implementation.
The 'trick' here is that I had to use wrapper/container objects in twos:
SecondaryDocument-container houses the Secondary Document while PrimaryDocument-AnswerPane-container houses both the Primary Document and Answer Pane.

What does flex: 1 mean?

As we all know, the flex property is a shorthand for the flex-grow, flex-shrink, and the flex-basis properties. Its default value is 0 1 auto, which means
flex-grow: 0;
flex-shrink: 1;
flex-basis: auto;
but I've noticed, in many places flex: 1 is used. Is it shorthand for 1 1 auto or 1 0 auto? I can't understand what it means and I get nothing when I google.
flex: 1 means the following:
flex-grow : 1; ➜ The div will grow in same proportion as the window-size
flex-shrink : 1; ➜ The div will shrink in same proportion as the window-size
flex-basis : 0; ➜ The div does not have a starting value as such and will
take up screen as per the screen size available for
e.g:- if 3 divs are in the wrapper then each div will take 33%.
Here is the explanation:
https://www.w3.org/TR/css-flexbox-1/#flex-common
flex: <positive-number>
Equivalent to flex: <positive-number> 1 0. Makes the flex item flexible and sets the flex basis to zero, resulting in an item that
receives the specified proportion of the free space in the flex
container. If all items in the flex container use this pattern, their
sizes will be proportional to the specified flex factor.
Therefore flex:1 is equivalent to flex: 1 1 0
BE CAREFUL
In some browsers:
flex:1; does not equal flex:1 1 0;
flex:1; = flex:1 1 0n; (where n is a length unit).
flex-grow: A number specifying how much the item will grow relative to the rest of the flexible items.
flex-shrink A number specifying how much the item will shrink relative to the rest of the flexible items
flex-basis The length of the item. Legal values: "auto", "inherit", or a number followed by "%", "px", "em" or any other length unit.
The key point here is that flex-basis requires a length unit.
In Chrome for example flex:1 and flex:1 1 0 produce different results. In most circumstances it may appear that flex:1 1 0; is working but let's examine what really happens:
EXAMPLE
Flex basis is ignored and only flex-grow and flex-shrink are applied.
flex:1 1 0; = flex:1 1; = flex:1;
This may at first glance appear ok however if the applied unit of the container is nested; expect the unexpected!
Try this example in CHROME
.Wrap{
padding:10px;
background: #333;
}
.Flex110x, .Flex1, .Flex110, .Wrap {
display: -webkit-flex;
display: flex;
-webkit-flex-direction: column;
flex-direction: column;
}
.Flex110 {
-webkit-flex: 1 1 0;
flex: 1 1 0;
}
.Flex1 {
-webkit-flex: 1;
flex: 1;
}
.Flex110x{
-webkit-flex: 1 1 0%;
flex: 1 1 0%;
}
FLEX 1 1 0
<div class="Wrap">
<div class="Flex110">
<input type="submit" name="test1" value="TEST 1">
</div>
</div>
FLEX 1
<div class="Wrap">
<div class="Flex1">
<input type="submit" name="test2" value="TEST 2">
</div>
</div>
FLEX 1 1 0%
<div class="Wrap">
<div class="Flex110x">
<input type="submit" name="test3" value="TEST 3">
</div>
</div>
UPDATE 2021
The latest versions of all major browsers appear to implement flex: 1 and conform to W3C standard. This was verified on Chrome, Opera, Edge, Firefox, Safari, Chromium and a few Chromium variants like Brave on macOS, Windows, Linux, iOS, and Android. When attempting to test in Internet Explorer the Edge browser was force-loaded on Windows 10.
If you expect
users to still implement older versions of browser then adding units is a safer bet.
I was also confused with flex: 1, so I will share here my way of understanding this property :)
To understand the concept of flex: 1, first we have to make sure the parent element has a display property set to flex i.e., display: flex. Now, the nested flexed elements inside the parent can make use of flex: 1.
Ok now the question is what will this do to the flexed element? If an element has flex: 1, this means the size of all of the other elements will have the same width as their content, but the element with flex: 1 will have the remaining full space given to it. See the illustration below.
In Chrome Ver 84, flex: 1 is equivalent to flex: 1 1 0%. The followings are a bunch of screenshots.
The default values are set to 1 1 0% (which are the shorthand values for flex-grow flex-shrink flex-basis respectively) probably because these are the values that make the most sense for "flex" items. Here are what exactly those values mean:
flex-basis: It specifies the ideal size for the items. Ideal means "assuming there is neither any extra space, nor any shortages of the space". 0% means we have no ideal size for them, we want them to be sized truely flexibly. We want them to be sized automatically(thus the word "flexible") based on the available space.
flex-grow: After taking the flex-basis into consideration, if there's remaining extra space, it specifies how "that extra space"(notice we're not talking about the whole space) must be divided between the items. The ones with higher flex-grow will eat up more of the extra space. It makes sense to use an equal flex-grow on all items by default so that all items will have the same share of the extra space. When flex-basis is 0%, a flex-grow of 1 on all items makes them divide "the whole space of the container"(since flex-basis used no space, the extra space equals the whole space of the container).
flex-shrink: After taking the flex-basis into consideration, if the available space is not enough, it specifies how "the shortage of space"(and again, not the whole space) must be divided(imposed on) among the items. The ones with higher flex-shrink will have to "endure" more of that shortage.
Examples:
flex-basis A flex-basis of 400px on 3 items, means that we'd rather have 3 items of 400px wide each. Now, what will happen:
If we have extra space? Let's say the container width is 1500 pixels wide. The 3 items will take up 1200 pixels, what should happen to that extra 300 pixels?
If we have shortage of space in the container? E.g., If there are 5 items of 400 pixels each in a 1500px container (shortage = |1500px - 5 * 400px| = 500px).
The answer to the two questions above are flex-grow(answer to the 1st question) and flex-shrink(answer to the 2nd question).
E.g., what if one of the three items had a flex-grow of 5 and the other ones were still on their default values(i.e., 1)? Then the one with the flex-grow of 5 would get (300px / (1+1+5)) * 3 of the extra space.
Another useful example is, if you have a flex container and you want each of the children to take exactly the full width of the parent(e.g., an image carousel), in that case you may use a flex: 0 0 100% on all children so that items will have a flex-basis of taking the full-width of the parent, and turning their growing/shrinking off.
flex: 1 sets flex-grow to 1 (whereas the default value is 0).
What this does:
If all items have flex-grow set to 1, the remaining space in the
container will be distributed equally to all children. If one of the
children has a value of 2, the remaining space would take up twice as
much space as the others (or it will try to, at least).
(Source: CSS Tricks)
In the case of a one-value flex syntax with a unitless number (rather than a value for flex-basis, the other option),
...it is interpreted as flex: <number> 1 0; the
flex-shrink value is assumed to be 1 and the flex-basis value is
assumed to be 0.
(Source: MDN)
Flex: 1 is equivalent to Flex: 1 0 0 and Flex: 1 1 0
Please see the images I took showing the output, respectively, for Flex: 1 and Flex: 1 0 0 and Flex: 1 1 0 below
Flex: 1
Flex: 1 0 0
Flex: 1 1 0

What are the differences between flex-grow and width?

I've started using the flexbox recently and there often comes the situation where I need to distribute space on the main axis between elements.
I often hesitate between width and flex-grow. For example, if I want one item to measure 2 measures, and the other 1 measure, adding up to 100%, I have two choices. I can either set width: 66.6% and width: 33.3%, or flex-grow: 2 and flex-grow: 1.
Sometimes if I want one element to grow the rest of the space, I can either do width: 100% or flex-grow: 1.
How do I choose? What are the differences/considerations in using width vs. flex-grow?
width and flex-grow are two entirely different CSS properties.
The width property is used for defining the width of elements.
The flex-grow property is used for distributing free space in a flex container. This property doesn't apply a specific length to an element, like the width property. It simply allows a flex item to consume whatever space may be available.
Sometimes if I want one element to grow the rest of the space, I can either do width: 100% or flex-grow: 1. How do I choose?
Yes, if there is one element in the row, width: 100% and flex-grow: 1 may have the same effect (depending on padding, border and box-sizing settings).
But what if there are two elements, and you want the second one to take the remaining space? With a sibling in the container, width: 100% causes an overflow. I guess you can do something like this:
width: calc(100% - width of sibling);
But what if the sibling's width is dynamic or unknown? calc is no longer an option.
The quick and easy solution is flex-grow: 1.
While width and flex-grow are apples-to-oranges, width and flex-basis are apples-to-apples.
The flex-basis property sets the initial main size of a flex item and is similar to width.
What are the differences between flex-basis and width?
For the differences between flex-basis and flex-grow see:
flex-grow not sizing flex items as expected

flex: 0 0 using new css flexbox

In chrome I set an a child element of a display: flex element as flex: 0 0. I took this to mean no stretching or shrinking, however it shrinks to 0 pixels. Does 0 have a different meaning for stretch and shrink, or is this a bug in chrome?
EDIT Here's a fiddle http://jsfiddle.net/BPk4Q/
You want flex: none (which is a special value that's equivalent to flex: 0 0 auto).
The value you're currently using, flex: 0 0 (without the 'auto'), implies a flex-basis of 0%, which indeed tends to make things 0-sized (given that the flex-grow value is also 0). Quoting the flexbox spec about the flex shorthand:
<‘flex-basis’>
[...] When omitted from the flex shorthand, its specified value is 0%.
http://www.w3.org/TR/css3-flexbox/#flex-property
So, anyway, it sounds like you want flex: none.

Resources