Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Should flex item overflow the flex container instead of breaking lines?

I have this layout:

  • A row flex container with a definite size, e.g. width: 175px
  • A flex item
    • With an indefinite flex-basis, e.g. flex-basis: content
    • Which is inflexible, e.g. flex: none.
    • Whose max-content size is larger than the available space
    • Whose min-content size is smaller than the available space

.flex-container {
  display: flex;
  width: 175px;
  border: 3px solid black;
  margin-bottom: 10px;
}
.flex-item {
  flex: none;
  border: 3px solid blue;
  margin: 3px;
}
.box {
  display: inline-block;
  vertical-align: middle;
  width: 100px;
  height: 100px;
  border: 3px solid red;
  margin: 3px;
}
<div class="flex-container">
  <div class="flex-item">
    <div class="box"></div>
    <div class="box"></div>
  </div>
</div>

As expected, Firefox breaks lines inside the flex item and sets its width to the available space.

enter image description here

However, Chrome doesn't break lines and thus the flex item overflows the flex container:

enter image description here

Who is right? How can I fix this?

like image 973
Oriol Avatar asked Jan 26 '16 00:01

Oriol


1 Answers

This is what happens:

  1. The Line Length Determination algorithm determines that the flex base size of the flex item is its max-content

    Size the item into the available space using its used flex basis in place of its main size, treating a value of content as max-content. [...] The flex base size is the item’s resulting main size.

  2. Since there are no min nor max size constraints, the hypothetical main size of the flex item is the same value

    The hypothetical main size is the item’s flex base size clamped according to its min and max main size properties.

  3. The Resolving Flexible Lengths algorithm freezes the inflexible flex item and sets its target main size to its hypothetical main size

    Size inflexible items. Freeze, setting its target main size to its hypothetical main size any item that has a flex factor of zero

  4. Finally, the main size is that value too:

    Set each item’s used main size to its target main size.

Therefore, your flex item should be sized as if it had flex-basis: max-content. Chrome, Edge and IE do it correctly.

Instead, Firefox seems to size as if it had flex-basis: fit-content. IMO this is more reasonable, but it's not standard. Bug 876985 should fix this.

Meanwhile, to achieve the standard behavior on Firefox you can use

flex-basis: -moz-max-content;

.flex-container {
  display: flex;
  width: 175px;
  border: 3px solid black;
  margin-bottom: 10px;
}
.flex-item {
  flex: none;
  flex-basis: -moz-max-content;
  border: 3px solid blue;
  margin: 3px;
}
.box {
  display: inline-block;
  vertical-align: middle;
  width: 100px;
  height: 100px;
  border: 3px solid red;
  margin: 3px;
}
<div class="flex-container">
  <div class="flex-item">
    <div class="box"></div>
    <div class="box"></div>
  </div>
</div>

Instead, if you want Firefox's behavior on other browsers, it's not that easy.

Chrome doesn't support fit-content on flex-basis, but it does on width (prefixed)

flex-basis: auto;
width: -webkit-fit-content;
width: fit-content;

.flex-container {
  display: flex;
  width: 175px;
  border: 3px solid black;
  margin-bottom: 10px;
}
.flex-item {
  flex: none;
  width: -webkit-fit-content;
  width: fit-content;
  border: 3px solid blue;
  margin: 3px;
}
.box {
  display: inline-block;
  vertical-align: middle;
  width: 100px;
  height: 100px;
  border: 3px solid red;
  margin: 3px;
}
<div class="flex-container">
  <div class="flex-item">
    <div class="box"></div>
    <div class="box"></div>
  </div>
</div>

However, IE/Edge doesn't support fit-content anywhere. But a max constraint should work on all browsers

max-width: 100%;
box-sizing: border-box; /* Include paddings and borders */

Note the constraint won't include margins, so you may need to correct the percentage using calc, e.g. max-width: calc(100% - 6px).

.flex-container {
  display: flex;
  width: 175px;
  border: 3px solid black;
  margin-bottom: 10px;
}
.flex-item {
  flex: none;
  max-width: calc(100% - 6px);
  box-sizing: border-box;
  border: 3px solid blue;
  margin: 3px;
}
.box {
  display: inline-block;
  vertical-align: middle;
  width: 100px;
  height: 100px;
  border: 3px solid red;
  margin: 3px;
}
<div class="flex-container">
  <div class="flex-item">
    <div class="box"></div>
    <div class="box"></div>
  </div>
</div>
like image 107
Oriol Avatar answered Sep 18 '22 11:09

Oriol