Specifing Width of a Flexbox Flex Item: Width or Basis

Specifing width of a flexbox flex item: width or basis?

The bottom statement is equivalent to:

.half {
flex-grow: 0;
flex-shrink: 0;
flex-basis: 50%;
}

Which, in this case, would be equivalent as the box is not allowed to flex and therefore retains the initial width set by flex-basis.

Flex-basis defines the default size of an element before the remaining space is distributed so if the element were allowed to flex (grow/shrink) it may not be 50% of the width of the page.

I've found that I regularly return to https://css-tricks.com/snippets/css/a-guide-to-flexbox/ for help regarding flexbox :)

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 ignore flex-basis but can use width and height.

  • flex-basis works only on the main axis. For example, if you're in flex-direction: column, the width property would be needed for sizing flex items horizontally.

  • flex-basis has no effect on absolutely-positioned flex items. width and height 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 and flex-basis – can be neatly combined into one declaration. Using width, 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 property

For all values other than auto and content, flex-basis is resolved the same way as width 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 used flex-basis. If that value is
itself auto, then the used value is content.

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 using auto together with a
main size (width or height) of auto.

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 horizontally
  • justify-content: flex-start - flex items will stack at the start of the line on the main axis
  • align-items: stretch - flex items will expand to cover the cross-size of the container
  • flex-wrap: nowrap - flex items are forced to stay in a single line
  • flex-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
Flexibility

Authors 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 unitless flex-basis values are ignored
  • flex-basis doesn't account for box-sizing: border-box
  • flex-basis doesn't support calc()
  • Importance is ignored on flex-basis when using flex shorthand

How flexbox calculates flex-item's width if no flex-basis or width are set?

For this particular case you need to conisder the default shrink effect set by flex-shrink which has a default value of 1. Initially your element will overflow like below:

$('div').each(function() {
console.log($(this).width());
})
.container {
display: flex;
width: 600px;
}

.container div {
outline: 1px dotted black;
flex-shrink:0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="container">
<div>Lorem ipsum dolor sit amet consectetur adipisicing elit. Fuga aspernatur suscipit aliquam beatae vitae harum, eius expedita quidem incidunt velit! 123456789</div>
<div>Lorem ipsum dolor sit amet consectetur adipisicing elit. Fuga aspernatur suscipit aliquam beatae vitae harum, eius expedita quidem incidunt velit!</div>
</div>

Flexbox items do not have equal widths despite flex-basis: 0

If you don't specify a width the flex container is just doing it's job and growing as specified. A solution to this is to set the min-width so there is no implicit width.

Additionally here is some valuable information on flex-basis: MDN

In case both flex-basis (other than auto) and width (or height in case of flex-direction: column) are set for an element, flex-basis has priority.

.items {    display: flex;    justify-content: space-between;}
.item { flex: 1 0 0; border: 1px solid #333; background: #fde669; min-width: 0;}
.item-title { font-size: 25px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;}
<div class="items">  <div class="item">    <div class="item-title">Title 1</div>  </div>  <div class="item">    <div class="item-title">Title 2</div>  </div>  <div class="item">    <div class="item-title">Some very long title</div>  </div>  <div class="item">    <div class="item-title">Title 3</div>  </div>  </div>

What property controls width when flex-direction is set to column?

From the specification and following the Cross Size Determination:

Determine the used cross size of each flex item. If a flex item has align-self: stretch, its computed cross size property is auto, and neither of its cross-axis margins are auto, the used outer cross size is the used cross size of its flex line, clamped according to the item’s used min and max cross sizes. Otherwise, the used cross size is the item’s hypothetical cross size.

Wihout using stretch you will clearly fall into the hypothetical cross size

Determine the hypothetical cross size of each item by performing layout with the used main size and the available space, treating auto as fit-content.

Then we can also read:

cross size

cross size property

The width or height of a flex container or flex item, whichever is in the cross dimension, is that box’s cross size. Its cross size property is thus either its width or height property, whichever is in the cross dimension.

So you simply define the width with the width property when dealing with a column direction and if it's auto it will compute to fit-content

More detail around fit-content here: https://www.w3.org/TR/css-sizing-3/#fit-content-size

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

Why does width % on flex-container shrink past its contents, but flex-basis does not?

To understand this you need to consider two concepts: The "flex base size" and the "main size".

It's a bit tricky to explain but if you refer to the full algorithm in the specification You will notice that we first calculate the "flex base size" and later we calculate the "hypothetical main size" which is the final size.

For the "hypothetical main size":

The hypothetical main size is the item’s flex base size clamped according to its used min and max main sizes (and flooring the content box size at zero).

When you use width you are affecting the "main sizes" that is used to define the final width (the "hypothetical main size"). In other words, it's not only the min-width that is responsible of the non-shrinking effect but it's the "min max main sizes".

Here is another example to better understand:

.flex-container {
display: flex;
background-color: DodgerBlue;
}

.flex-container>div {
background-color: #f1f1f1;
margin: 2px;
padding: 2px;
font-size: 30px;
flex-basis: 20%;
width: 40px;
}
<div class="flex-container">
<div>Item 1</div>
<div>Item 2</div>
<div>Item 3</div>
</div>

How to set a fixed width column with CSS flexbox

You should use the flex or flex-basis property rather than width. Read more on MDN.

.flexbox .red {
flex: 0 0 25em;
}

The flex CSS property is a shorthand property specifying the ability of a flex item to alter its dimensions to fill available space. It contains:

flex-grow: 0;     /* do not grow   - initial value: 0 */
flex-shrink: 0; /* do not shrink - initial value: 1 */
flex-basis: 25em; /* width/height - initial value: auto */

A simple demo shows how to set the first column to 50px fixed width.

.flexbox {  display: flex;}.red {  background: red;  flex: 0 0 50px;}.green {  background: green;  flex: 1;}.blue {  background: blue;  flex: 1;}
<div class="flexbox">  <div class="red">1</div>  <div class="green">2</div>  <div class="blue">3</div></div>


Related Topics



Leave a reply



Submit