Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

flex-wrap: nowrap width doesn't include children

Tags:

html

css

flexbox

Shouldn't a flexbox with flex-wrap: nowrap naturally be the width of it's children?

For some reason, it's only the width of its parent. Is it possible to make it get the width of its children?

In this codepen you can see that the background doesn't extend the full width of all the children.

.flex {
  display: flex;
  flex-wrap: nowrap;
  background-color: lightblue;
}

.flex div {
  flex-basis: 75%;
  flex-shrink: 0;
}
<div class="flex">
  <div>hi</div>
  <div>hi</div>
  <div>hi</div>
  <div>hi</div>
</div>

Edit: I used "should" under the assumption that a typical div with white-space: nowrap applied to inline children would grow to accommodate its children; however, that doesn't appear to be true either (https://codepen.io/robgordon/pen/gEvjpL).

like image 691
rob-gordon Avatar asked Mar 14 '19 17:03

rob-gordon


People also ask

Why doesn't the nested flex parent height grow with children?

Their total height will exceed the height of their parent so they will shrink equally to fit inside it as this is the default behavior AND the parent will not grow with them even if you define flex-shrink:0 on it because there is nothing to shrink for the parent element simply because its following a row direction ...

Which flex property will use to prevent child element to flow out of parent width?

To override this behavior, use min-width: 0 or overflow: hidden .

Do children inherit display flex?

The display property is not inherited, so display: flex is not either.

What does the flex-wrap wrap rule do?

The flex-wrap CSS property sets whether flex items are forced onto one line or can wrap onto multiple lines. If wrapping is allowed, it sets the direction that lines are stacked.


1 Answers

Your element is a block element which means that its width is 100% of its containing block width and in this case it's the body element.

Add border to the body element to better see:

.flex {
  display: flex;
  flex-wrap: nowrap;
  background-color: lightblue;
}

.flex div {
  flex-basis: 75%;
  flex-shrink: 0;
}

body {
  border:2px solid green;
}
<div class="flex">
  <div>hi</div>
  <div>hi</div>
  <div>hi</div>
  <div>hi</div>
</div>

Same think for the body element if you add border to html since this one is also a block element:

.flex {
  display: flex;
  flex-wrap: nowrap;
  background-color: lightblue;
}

.flex div {
  flex-basis: 75%;
  flex-shrink: 0;
}

body {
  border:2px solid green;
}
html {
  border:2px solid red;
}
<div class="flex">
  <div>hi</div>
  <div>hi</div>
  <div>hi</div>
  <div>hi</div>
</div>

So all your element are restriced by your screen size. From the specification we have this rule:

'margin-left' + 'border-left-width' + 'padding-left' + 'width' + 'padding-right' + 'border-right-width' + 'margin-right' = width of containing block

Since we have no padding/margin/border we will have width = width of containing block.

This logic apply to all our elements until we reach the viewport:

The containing block in which the root element lives is a rectangle called the initial containing block. For continuous media, it has the dimensions of the viewport and is anchored at the canvas origin; it is the page area for paged media. The 'direction' property of the initial containing block is the same as for the root element.


Also in your case, there is no way to contain all the elements simply because your are defining the width of your elements using a percetange that will (in all the cases) be bigger than the parent. You have 4*75% that is always bigger than 100%.

So whataver you will do you will always have an overflow:

.flex {
  display: flex;
  flex-wrap: nowrap;
  background-color: lightblue;
}

.flex div {
  flex-basis: 75%;
  flex-shrink: 0;
}

body {
  border:2px solid green;
}
<div class="flex" style="display:inline-flex">
  <div>hi</div>
  <div>hi</div>
  <div>hi</div>
  <div>hi</div>
</div>

<div class="flex" style="width:50%;">
  <div>hi</div>
  <div>hi</div>
  <div>hi</div>
  <div>hi</div>
</div>

<div class="flex" style="width:500%;">
  <div>hi</div>
  <div>hi</div>
  <div>hi</div>
  <div>hi</div>
</div>

<div class="flex" style="width:200px;">
  <div>hi</div>
  <div>hi</div>
  <div>hi</div>
  <div>hi</div>
</div>

But in case the width are defined using pixel for example (let's consider 500px) Then the parent element may contain its child with the inline-flex setting.

.flex {
  display: flex;
  flex-wrap: nowrap;
  background-color: lightblue;
}

.flex div {
  width: 500px;
  flex-shrink: 0;
}

body {
  border:2px solid green;
}
<div class="flex" style="display:inline-flex">
  <div>hi</div>
  <div>hi</div>
  <div>hi</div>
  <div>hi</div>
</div>

<div class="flex" >
  <div>hi</div>
  <div>hi</div>
  <div>hi</div>
  <div>hi</div>
</div>

In this case the width is a shrink-to-fit width described as below:

Calculation of the shrink-to-fit width is similar to calculating the width of a table cell using the automatic table layout algorithm. Roughly: calculate the preferred width by formatting the content without breaking lines other than where explicit line breaks occur, and also calculate the preferred minimum width, e.g., by trying all possible line breaks. CSS 2.1 does not define the exact algorithm. Thirdly, find the available width: in this case, this is the width of the containing block minus the used values of 'margin-left', 'border-left-width', 'padding-left', 'padding-right', 'border-right-width', 'margin-right', and the widths of any relevant scroll bars.

Then the shrink-to-fit width is: min(max(preferred minimum width, available width), preferred width).


Note that using flex-basis with pixel value won't give the same result as width

.flex {
  display: flex;
  flex-wrap: nowrap;
  background-color: lightblue;
}

.flex div {
  flex-basis: 500px;
  flex-shrink: 0;
}

body {
  border:2px solid green;
}
<div class="flex" style="display:inline-flex">
  <div>hi</div>
  <div>hi</div>
  <div>hi</div>
  <div>hi</div>
</div>

<div class="flex" >
  <div>hi</div>
  <div>hi</div>
  <div>hi</div>
  <div>hi</div>
</div>

More details here : https://stackoverflow.com/a/34355447/8620333


nowrap is the default value of flex-wrap so it can be omitted in the below examples

like image 147
Temani Afif Avatar answered Oct 06 '22 22:10

Temani Afif