Skip to content

Commit 8574e93

Browse files
committed
[css-contain-3] Move the text about inline-size cycles into the following note, and expand/rework the whole note to more explicit about how this is not a new problem.
1 parent 3659b69 commit 8574e93

1 file changed

Lines changed: 125 additions & 72 deletions

File tree

css-contain-3/Overview.bs

Lines changed: 125 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,7 @@ spec:css-contain-2; type:dfn; text:size containment box
3030
spec:css-sizing-4; type:property; text:contain-intrinsic-size
3131
spec:css-sizing-4; type:property; text:aspect-ratio
3232
spec:intersection-observer; type:dfn; text:intersection root
33-
spec:css-sizing-3; type:value; for:height; text:auto
3433
spec:css-sizing-3; type:property;
35-
text:width
36-
text:height
3734
text:min-width
3835
text:min-height
3936
spec:css-sizing-3; type:dfn; text:width
@@ -107,75 +104,131 @@ Inline-Size Containment</h3>
107104
is determined as if the element had no content.
108105
However, content continues to impact the element’s [=block axis=] [=intrinsic size=].
109106

110-
In some cases,
111-
changes in the [=block size=] can impact layout in the parent formatting context,
112-
which then impacts the [=inline axis|inline=] [=available space=]
113-
(e.g. by triggering scrollbars on an ancestor element)
114-
or the result of [=container size queries=],
115-
which then impacts the element’s [=inline size=],
116-
creating a dependency of this [=inline size=] on the element’s content.
117-
To prevent infinite cycles,
118-
if this then results in a different [=block size=] on the element,
119-
that new [=block size=] can impact the parent formatting context,
120-
but not in a way that reverts it to the previously-problematic layout.
121-
For example, if scrollbars were introduced, they are not then removed;
122-
or if the inline size was reduced, it is not then restored to its previous size.
123-
124-
Note: This is similar to the logic governing float placement,
125-
in which a float whose logical height cannot fit
126-
is shifted down to find more space,
127-
which might also give it more inline-axis available space
128-
and thus produce a shorter float
129-
whose height could have fit in the initial space,
130-
but it is not moved back up
131-
(where it would again be narrower, and thus taller, and thus not fit).
132-
133-
<div class=example>
134-
For example,
135-
the following <code>article</code> is constrained by both
136-
the overall <code>section</code> '/width',
137-
and impacted by the floated <code>div</code>s.
138-
139-
<pre class=lang-markup>
140-
&lt;section style="width: 200px; border: solid; display: flow-root;">
141-
&lt;!-- floated elements that impact the available space -->
142-
&lt;div style="float: left; width: 50px; height: 80px; background: red;">&lt;/div>
143-
&lt;div style="float: right; width: 50px; height: 80px; background: red;">&lt;/div>
144-
&lt;div style="float: left; width: 160px; height: 80px; background: red;">&lt;/div>
145-
146-
&lt;!-- parent layout, determining context -->
147-
&lt;article style="border: solid; display: flow-root; min-width: min-content;">
148-
&lt;header style="background: orange; aspect-ratio: 1/1;">
149-
&lt;h4 style="margin:0;">Article Title&lt;/h4>
150-
&lt;/header>
151-
&lt;/article>
152-
&lt;/section>
153-
</pre>
154-
155-
The block layout algorithm will attempt to layout the <code>article</code>
156-
in the first available space between the first two floated <code>div</code>s.
157-
However, the <code>header</code> '/aspect-ratio'
158-
requires a space with '/height' equal or greater to the '/width',
159-
and the available space is 100px wide by 80px tall,
160-
so the <code>article</code> is unable to fit.
161-
As a result, the block layout algorithm moves on,
162-
and attempts to layout the <code>article</code> in the next available space.
163-
164-
Since <code>article</code> 'min-width' depends on the [=min-content size=],
165-
it will likely be too large to fit in the 40px wide space
166-
beside the final floated <code>div</code>,
167-
and continue to layout below that <code>div</code> as well--
168-
forming a 200px square below all the floated elements.
169-
170-
However, if the 'min-width' is removed from the <code>article</code>,
171-
or if [=inline-size containment=] is added to
172-
either the <code>article</code> or <code>header</code>,
173-
then the <code>article</code> will fit as a 40px square
174-
next to the final floated <code>div</code>.
175-
Even though this resulting size could also fit in the initial space,
176-
agents do not backtrack
177-
and attempt to place the <code>article</code>
178-
in a context that previously failed.
107+
<div class=note>
108+
In some cases,
109+
changes in the [=block size=] can impact layout in the parent formatting context,
110+
which then impacts the [=inline axis|inline=] [=available space=]
111+
(e.g. by triggering scrollbars on an ancestor element)
112+
or the result of [=container size queries=],
113+
which then impacts the element’s [=inline size=],
114+
creating a dependency of this [=inline size=] on the element’s content.
115+
116+
This sort of "cycle" is not new;
117+
it is possible to construct examples of this
118+
using elements with aspect ratios,
119+
or complex usages of floats and clearing.
120+
In general, the relationship between an element's available inline space
121+
and it's resulting block size
122+
is unpredictable and non-monotonic,
123+
with the block size capable of bouncing up and down arbitrarily
124+
as the available inline space is changed.
125+
126+
Implementations today prevent infinite cycling
127+
by ensuring that layout always "moves forward";
128+
in other words,
129+
that certain aspects of a container's layout
130+
do not "revert" to a previous (known-problematic) state,
131+
even if a naive analysis of the constraints would allow for such.
132+
The mitigation for these issues
133+
is that certain aspects of layout
134+
are on a "ratchet",
135+
allowed to progress in one direction but not another:
136+
the available size a container presents to its contents is one such example,
137+
allowed to shrink
138+
(as a result of scrollbars, etc)
139+
but not to then reverse and grow again;
140+
the presence of scrollbars themselves is another,
141+
allowed to be added to an element
142+
but not to then be removed
143+
if the reduced inline available size
144+
causes the contents to no longer overflow;
145+
the "starting point" for elements to be laid out
146+
along the block axis is another,
147+
allowed to move downward as a result of floats
148+
but not to then move back upward
149+
and possibly cause already laid-out floats
150+
to have to move again.
151+
152+
These algorithm ratchets are well-known and common among implementations,
153+
and container queries
154+
(and the associated [=inline-size containment=])
155+
do not introduce any conceptually new problems here.
156+
To the best of the specification editors' knowledge,
157+
existing layout techniques suffice to ensure that layout cycles do not occur,
158+
and the design of this feature
159+
attempts to make them rare in practice in any case.
160+
161+
The precise details of each implementation's mitigation strategies
162+
are not fully interoperable,
163+
unfortunately,
164+
so we hope to capture them in a future specification.
165+
166+
<div class=example>
167+
For example,
168+
the following <code>article</code> is constrained by both
169+
the overall <code>section</code> '/width',
170+
and impacted by the floated <code>div</code>s.
171+
172+
<xmp class=lang-markup>
173+
<section style="width: 200px; border: solid; display: flow-root;">
174+
<!-- floated elements that impact the available space -->
175+
<div style="float: left; width: 50px; height: 80px; background: red;"></div>
176+
<div style="float: right; width: 50px; height: 80px; background: red;"></div>
177+
<div style="float: left; width: 160px; height: 80px; background: red;"></div>
178+
179+
<!-- parent layout, determining context -->
180+
<article style="border: solid; display: flow-root;">
181+
<div style="background: orange; aspect-ratio: 1/1;">
182+
text
183+
</div>
184+
</article>
185+
</section>
186+
</xmp>
187+
188+
The block layout algorithm will first place the floating elements,
189+
with the first two sitting in the left and right corners of the container,
190+
and the third being pushed below them,
191+
since its width does not fit in the remaining space
192+
if it was placed with its top edge flush with the top of the container.
193+
194+
The following <code>article</code> will then be laid out.
195+
Because it is ''display: flow-root'',
196+
it avoids intersecting with any floats,
197+
and thus must take them into account
198+
when figuring out how to size and position itself.
199+
200+
The layout engine first attempts to put the <code>article</code> flush with the top of the container,
201+
as there is enough inline space to accommodate its [=min-content size=];
202+
resulting in it becoming ''100px'' wide.
203+
However, due the aspect ratio of its contents,
204+
this would cause the <code>article</code> to be ''100px'' tall as well,
205+
but there is only ''80px'' of available block space
206+
before it would intersect the third float,
207+
so this layout opportunity is discarded.
208+
209+
It then attempts to position the <code>article</code>
210+
flush with the top of the third float,
211+
in the narrow ''40px''-wide space to its right.
212+
It fits, and its resulting ''40px'' height
213+
doesn't violate any layout rules either,
214+
so this is acceptable.
215+
216+
At this point, the width and height of the <code>article</code>
217+
(''40px'' each)
218+
<em>would</em> fit back in the original considered space,
219+
flush with the top of the container.
220+
However, "progress" along the block axis
221+
when considering layout opportunities
222+
is one such "ratchet" in layout,
223+
and an element is not allowed to return to a higher position
224+
after it determines its size.
225+
226+
Thus, the <code>article</code> is sized to ''40px'' wide and tall
227+
and positioned alongside the third float,
228+
even tho a similar element with an <em>explicit</em> <css>width: 40px</css>
229+
would be positioned at the top of the container,
230+
between the first two floats.
231+
</div>
179232
</div>
180233

181234
Issue(1031): Define inline-size containment in more detail

0 commit comments

Comments
 (0)