I was trying to be smart and applied max-width: min(100%, 30em);
to my elements that contain text. The result is that under some circumstances, the container of such an element takes up all horizontal space, but not always.
I'm just very curious, how this can be explained!
(I can circumvent that side effect by simply applying max-width: 30em;
, but as these elements may be placed in containers narrower than that, I thought I'd be on the safe side by adding the min()
function.)
.broken .child{
max-width: min(100%, 30em);
}
.okay .child {
width: 100%;
max-width: 30em;
}
.container{
display: inline-flex;
}
<h2>Broken</h2>
<div class="broken">
<div class="container">
<div class="child">
<p>My container would take up all space if I contained more text.</p>
</div>
</div>
</div>
<div class="broken">
<div class="container">
<div class="child">
<p>See! What is going on here? What is going on here? What is going on here? What is going on here? What is going on here? What is going on here? What is going on here? What is going on here?</p>
</div>
</div>
</div>
<h2>Okay</h2>
<div class="okay">
<div class="container">
<div class="child">
<p>Here everything is okay, because instead of the clever max-width/min() combo, I've applied a width and a max-width on my parent.</p>
</div>
</div>
</div>
From the Specification
Sometimes the size of a percentage-sized box’s containing block depends on the intrinsic size contribution of the box itself, creating a cyclic dependency
The "parent" element is a inline-flex element (it size depends on its content) and "child" is using percentage on its max-width
value (that percentage requires to know the parent width that depends on the content).
If the box is non-replaced, then the entire value of any max size property or preferred size property (width/max-width/height/max-height) specified as an expression containing a percentage (such as 10% or calc(10px + 0%)) that is cyclic is treated for the purpose of calculating the box’s intrinsic size contributions only as that property’s initial value. (The percentage is honored as usual, however, during the actual sizing of the box itself; see below.)
That complex syntax means that we first consider the max-width
to be initial
in order to calculate the parent width then after that we use the percentage (that we can know resolve because we found the parent width) when calculating the child max-width
.
And you have the following:
Otherwise, the percentage is resolved against the containing block’s size. (The containing block’s size is not re-resolved based on the resulting size of the box; the contents might thus overflow or underflow the containing block).
In other words, you have a cyclic dependency and the browser decided to "temporary" ignore one of the values to be able to do the calculation.
.child {
max-width: min(100%, 20em);
border: 2px solid blue;
}
.container {
display: inline-flex;
border: 2px solid red;
}
<p>We do the calculation like if we have max-width: initial;</p>
<div class="container">
<div class="child" style="max-width: initial;">
<p>See! What is going on here? What is going on here? What </p>
</div>
</div>
<p>now that the parent width is known, it's used as a refernce for the percentage</p>
<div class="container">
<div class="child" style="max-width: min(100%, 20em);">
<p>See! What is going on here? What is going on here? What </p>
</div>
</div>
<p>20em is smaller than the previous calculated value so it's the one used (and no we don't get back to calculate the width of the parent again)</p>