What are the differences between flex-grow and width?
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%
orflex-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
Difference between flex-grow = 1, width: auto and just width: 100%
Typically, width:auto
makes the element occupy all available space. At a basic level, if some space is occupied, it occupies the rest. width: 100%
on the other hand means that the element will occupy its entire parent.
Flex grow, however, says how much space an element occupies. If there are two child elements inside a parent, and you give one of them a flex-grow: 2
it will occupy twice as much space as the other
What are the differences between flex-basis and width?
Consider flex-direction
The first thing that comes to mind when reading your question is that flex-basis
doesn't always apply to width
.
When flex-direction
is row
, flex-basis
controls width.
But when flex-direction
is column
, flex-basis
controls height.
Key Differences
Here are some important differences between flex-basis
and width
/ height
:
flex-basis
applies only to flex items. Flex containers (that aren't also flex items) will ignoreflex-basis
but can usewidth
andheight
.flex-basis
works only on the main axis. For example, if you're inflex-direction: column
, thewidth
property would be needed for sizing flex items horizontally.flex-basis
has no effect on absolutely-positioned flex items.width
andheight
properties would be necessary. Absolutely-positioned flex items do not participate in flex layout.By using the
flex
property, three properties –flex-grow
,flex-shrink
andflex-basis
– can be neatly combined into one declaration. Usingwidth
, the same rule would require multiple lines of code.
Browser Behavior
In terms of how they are rendered, there should be no difference between flex-basis
and width
, unless flex-basis
is auto
or content
.
From the spec:
7.2.3. The
flex-basis
propertyFor all values other than
auto
andcontent
,flex-basis
is resolved the same way aswidth
in horizontal writing modes.
But the impact of auto
or content
may be minimal or nothing at all. More from the spec:
auto
When specified on a flex item, the
auto
keyword retrieves the value
of the main size property as the usedflex-basis
. If that value is
itselfauto
, then the used value iscontent
.
content
Indicates automatic sizing, based on the flex item’s content.
Note: This value was not present in the initial release of Flexible
Box Layout, and thus some older implementations will not support it.
The equivalent effect can be achieved by usingauto
together with a
main size (width
orheight
) ofauto
.
So, according to the spec, flex-basis
and width
resolve identically, unless flex-basis
is auto
or content
. In such cases, flex-basis
may use content width (which, presumably, the width
property would use, as well).
The flex-shrink
factor
It's important to remember the initial settings of a flex container. Some of these settings include:
flex-direction: row
- flex items will align horizontallyjustify-content: flex-start
- flex items will stack at the start of the line on the main axisalign-items: stretch
- flex items will expand to cover the cross-size of the containerflex-wrap: nowrap
- flex items are forced to stay in a single lineflex-shrink: 1
- a flex item is allowed to shrink
Note the last setting.
Because flex items are allowed to shrink by default (which prevents them from overflowing the container), the specified flex-basis
/ width
/ height
may be overridden.
For example, flex-basis: 100px
or width: 100px
, coupled with flex-shrink: 1
, will not necessarily be 100px.
To render the specified width – and keep it fixed – you will need to disable shrinking:
div {
width: 100px;
flex-shrink: 0;
}
OR
div {
flex-basis: 100px;
flex-shrink: 0;
}
OR, as recommended by the spec:
flex: 0 0 100px; /* don't grow, don't shrink, stay fixed at 100px */
7.2. Components of
FlexibilityAuthors are encouraged to control flexibility using the
flex
shorthand
rather than with its longhand properties directly, as the shorthand
correctly resets any unspecified components to accommodate common
uses.
Browser Bugs
Some browsers have trouble sizing flex items in nested flex containers.
flex-basis
ignored in a nested flex container. width
works.
When using flex-basis
, the container ignores the sizing of its children, and the children overflow the container. But with the width
property, the container respects the sizing of its children and expands accordingly.
References:
- Chrome does not expand flex parent according to children's content
- Flex item overflowing when using flex-basis
- Difference between width and flex-basis
- Flex-basis is being ignored when sizing nested flex containers.
- flex-basis:100px does something different from width:100px+flex-basis:auto
Examples:
- https://jsfiddle.net/t419zhra/ (source: @Dremora)
- https://codepen.io/anon/pen/NVxaoy (source @Daniel)
- https://jsfiddle.net/voc9grx6/ (source: Chromium Bugs)
- https://jsfiddle.net/qjpat9zk/ (source: Chromium Bugs)
flex items using flex-basis
and white-space: nowrap
overflow inline-flex
container. width
works.
It seems that a flex container set to inline-flex
doesn't recognize flex-basis
on a child when rendering a sibling with white-space: nowrap
(although it could just be an item with undefined width). The container doesn't expand to accommodate the items.
But when the width
property is used instead of flex-basis
, the container respects the sizing of its children and expands accordingly. This is not a problem in IE11 and Edge.
References:
- inline flex container width not growing
- Inline flex container (display: inline-flex) is expanding the full width of parent container
Example:
- https://jsfiddle.net/p18h0jxt/1/ (from first post above)
flex-basis
(and flex-grow
) not working on table element
References:
- Why does flex-box work with a div, but not a table?
- Why doesn't flex-grow: 1 work for a table in Safari? (and Edge)
flex-basis
fails in Chrome and Firefox when the grandparent container is a shrink-to-fit element. The set-up works fine in Edge.
- Absolutely positioned container not expanding width to fit flexbox content
Like in the example presented in the link above, involving position: absolute
, the use of float
and inline-block
, will also render the same flawed output (jsfiddle demo).
Bugs affecting IE 10 and 11:
flex
shorthand declarations with unitlessflex-basis
values are ignoredflex-basis
doesn't account forbox-sizing: border-box
flex-basis
doesn't supportcalc()
- Importance is ignored on
flex-basis
when usingflex
shorthand
Inconsistency between flex-grow and width on flex items
You need to set the flex-basis property on your flex-items to 0%
#flex-item-1 {
flex-basis: 0%;
flex-grow: 3;
background-color: tomato;
/* width: 75%; */
}
#flex-item-2 {
flex-basis: 0%;
flex-grow: 1;
background-color: pink;
/* width: 25%; */
}
It specifies the initial size of the flex item, before any available space is distributed according to the flex factors. When omitted from the flex shorthand, its specified value is the length zero. Source: mdn
Stackblitz example
How is element width calculated with flex-grow?
You will have 330px
of free space (900 - 450 - 120
). The first element will grow twice than the second one. The total grow factor is 3
(2+1
) so the first one will take 2/3*330 = 220px
and the second one 1/3*330px = 110px
and we will end with
article = 120px + 220px = 340px
aside = 450px + 110px = 560px
Inspect the below code to validate the values:
div {
width: 900px;
display: flex;
height: 50px;
}
article {
flex-grow: 2;
width: 120px;
background: red;
}
aside {
flex-grow: 1;
width: 450px;
background: green;
}
<div>
<article></article>
<aside></aside>
</div>
Understanding the difference between the flex and flex-grow properties
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 wasflex-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.
Difference between width and flex-basis
This seems to be a bug.
An element which is both flex container and flex item seems to be ignoring intrinsic dimensions of its children if they are set via flex-basis
, instead choosing to measure the width/height of contents of its children instead. It is ironic that IE11/Edge is the only browser implementing this correctly.
Chromium bug tracker
Flex-grow with width property on element
Simply because the flex-grow
will make the element to consume the free space. In your case the first element has 100px
of width and the other one is having width equal to its content so the free space is (width of container - 100px - content of box2)
. This free space will be split equally and added to both element and it's logical that the first one will be bigger since initially it was already bigger.
In your example, the second element is about 29px
and if we fix the width of the container to 600px
for example, we will have a free space equal to 471px
so both elements will end with 335.5px
and 264.5px
of width.
.wrapper { display: flex; width:600px;}
.box1 { background: red; width: 100px; flex-grow: 1;}
.box2 { background: green; flex-grow: 1;}
<div class="wrapper"> <div class="box1">One</div> <div class="box2">Two</div></div>
Related Topics
How to Add a Box-Shadow on One Side of an Element
How to Make an Inline-Block Element Fill the Remainder of the Line
Angular 2: How to Style Host Element of the Component
Float Right and Position Absolute Doesn't Work Together
Deprecated Smil Svg Animation Replaced with CSS or Web Animations Effects (Hover, Click)
Position: Absolute Without Setting Top/Left/Bottom/Right
How to Override the Properties of a CSS Class Using Another CSS Class
What Is the Value of the CSS 'Ex' Unit
Fill Background Color Left to Right CSS
Add a CSS Class to a Field in Wtform
How to Center an Image If It's Wider Than Its Container
Filter: Blur(1Px); Doesn't Work in Firefox, Internet Explorer, and Opera
How to Include View/Partial Specific Styling in Angularjs
Webkit CSS Animation Issue - Persisting the End State of the Animation