-
Notifications
You must be signed in to change notification settings - Fork 3.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[anchor] Better handling of OOF sizing on first layout.
If position-area is used, an OOF may be tethered to both the IMCB (inset-modified containing block) and the default anchor. For instance, position-area:top will get its top inset from the containing block and the bottom offset from its default anchor. When scrolling, the default anchor will appear to move up or down (or sideways), so that there will be less space available on one side, and more space available on the other side, of the default anchor. Elements tethered to the default anchor AND the containing block can now grow or shrink their IMCB accordingly, based on this. The scroll offset for this use will only be snapshotted at an "anchor recalculation point" - i.e. when an element is laid out for the first time, or when it changes its position fallback style. For now we only consider first-layout as an "anchor recalculation point". Will deal with changing position fallback styles later. This behavior change is behind the CSSAnchorPositionAreaVisualPosition runtime flag. Bug: 373874012 Change-Id: I11f0d25421be6ad6b4612501940696f4c806867d Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6048895 Reviewed-by: Rune Lillesveen <[email protected]> Commit-Queue: Morten Stenshorne <[email protected]> Cr-Commit-Position: refs/heads/main@{#1389310}
- Loading branch information
1 parent
5d7e670
commit b36bca1
Showing
2 changed files
with
272 additions
and
0 deletions.
There are no files selected for viewing
122 changes: 122 additions & 0 deletions
122
css/css-anchor-position/position-area-scrolling-001.tentative.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
<!DOCTYPE html> | ||
<title>position-area to include current scroll position at first layout</title> | ||
<link rel="author" title="Morten Stenshorne" href="mailto:[email protected]"> | ||
<link rel="help" href="https://drafts.csswg.org/css-anchor-position-1/#scroll"> | ||
<script src="/resources/testharness.js"></script> | ||
<script src="/resources/testharnessreport.js"></script> | ||
<script src="support/test-common.js"></script> | ||
<style> | ||
.pos { | ||
position: absolute; | ||
box-sizing: border-box; | ||
border: solid; | ||
position-anchor: --anchor; | ||
width: 50%; | ||
height: 50%; | ||
background: cyan; | ||
} | ||
#container.thicker > .pos { | ||
border-width: thick; | ||
} | ||
</style> | ||
<div id="scrollable" style="position:relative; overflow:hidden; width:500px; height:500px;"> | ||
<div style="width:1000px; height:1000px;"> | ||
<div id="container"> | ||
<div style="height:200px;"></div> | ||
<div style="anchor-name:--anchor; margin-left:200px; width:100px; height:100px; background:gray;"></div> | ||
<div id="e1" class="pos" style="position-area:top left;"></div> | ||
<div id="e2" class="pos" style="position-area:top center;"></div> | ||
<div id="e3" class="pos" style="position-area:top right;"></div> | ||
<div id="e4" class="pos" style="position-area:center left;"></div> | ||
<div id="e5" class="pos" style="position-area:center center;"></div> | ||
<div id="e6" class="pos" style="position-area:center right;"></div> | ||
<div id="e7" class="pos" style="position-area:bottom left;"></div> | ||
<div id="e8" class="pos" style="position-area:bottom center;"></div> | ||
<div id="e9" class="pos" style="position-area:bottom right;"></div> | ||
</div> | ||
</div> | ||
</div> | ||
<script> | ||
function assert_rects_equal(elm, x, y, width, height) { | ||
assert_equals(elm.offsetLeft, x, (elm.id + " x")); | ||
assert_equals(elm.offsetTop, y, (elm.id + " y")); | ||
assert_equals(elm.offsetWidth, width, (elm.id + " width")); | ||
assert_equals(elm.offsetHeight, height, (elm.id + " height")); | ||
} | ||
|
||
function assert_at_initial() { | ||
assert_rects_equal(e1, 100, 100, 100, 100); | ||
assert_rects_equal(e2, 225, 100, 50, 100); | ||
assert_rects_equal(e3, 300, 100, 100, 100); | ||
assert_rects_equal(e4, 100, 225, 100, 50); | ||
assert_rects_equal(e5, 225, 225, 50, 50); | ||
assert_rects_equal(e6, 300, 225, 100, 50); | ||
assert_rects_equal(e7, 100, 300, 100, 100); | ||
assert_rects_equal(e8, 225, 300, 50, 100); | ||
assert_rects_equal(e9, 300, 300, 100, 100); | ||
} | ||
|
||
function assert_at_40_60() { | ||
assert_rects_equal(e1, 120, 130, 80, 70); | ||
assert_rects_equal(e2, 225, 130, 50, 70); | ||
assert_rects_equal(e3, 300, 130, 120, 70); | ||
assert_rects_equal(e4, 120, 225, 80, 50); | ||
assert_rects_equal(e5, 225, 225, 50, 50); | ||
assert_rects_equal(e6, 300, 225, 120, 50); | ||
assert_rects_equal(e7, 120, 300, 80, 130); | ||
assert_rects_equal(e8, 225, 300, 50, 130); | ||
assert_rects_equal(e9, 300, 300, 120, 130); | ||
} | ||
|
||
promise_test(async() => { | ||
assert_at_initial(); | ||
}, "Initial scroll position"); | ||
|
||
promise_test(async() => { | ||
await waitUntilNextAnimationFrame(); | ||
await waitUntilNextAnimationFrame(); | ||
scrollable.scrollTo(40, 60); | ||
await waitUntilNextAnimationFrame(); | ||
await waitUntilNextAnimationFrame(); | ||
assert_at_initial(); | ||
}, "Scroll to 40,60"); | ||
|
||
promise_test(async() => { | ||
// As long as we're within the same animation frame (and therefore haven't | ||
// run ResizeObserver events), there will be no anchor recalculation point. | ||
container.style.display = "flow-root"; | ||
assert_at_initial(); | ||
container.style.display = "none"; | ||
document.body.offsetTop; | ||
container.style.display = "block"; | ||
assert_at_initial(); | ||
}, "Reattach at 40,60"); | ||
|
||
promise_test(async() => { | ||
container.style.display = "none"; | ||
await waitUntilNextAnimationFrame(); | ||
await waitUntilNextAnimationFrame(); | ||
container.style.display = "block"; | ||
await waitUntilNextAnimationFrame(); | ||
await waitUntilNextAnimationFrame(); | ||
assert_at_40_60(); | ||
}, "Redisplay at 40,60"); | ||
|
||
promise_test(async() => { | ||
scrollable.scrollTo(0, 0); | ||
container.className = "thicker"; | ||
container.style.display = "block"; | ||
await waitUntilNextAnimationFrame(); | ||
await waitUntilNextAnimationFrame(); | ||
assert_at_40_60(); | ||
}, "Scroll to 0,0 and relayout"); | ||
|
||
promise_test(async() => { | ||
container.style.display = "none"; | ||
await waitUntilNextAnimationFrame(); | ||
container.style.display = "block"; | ||
await waitUntilNextAnimationFrame(); | ||
await waitUntilNextAnimationFrame(); | ||
assert_at_initial(); | ||
}, "Redisplay at 0,0"); | ||
</script> |
150 changes: 150 additions & 0 deletions
150
css/css-anchor-position/position-area-scrolling-002.tentative.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,150 @@ | ||
<!DOCTYPE html> | ||
<title>position-area to include current scroll position at first layout</title> | ||
<link rel="author" title="Morten Stenshorne" href="mailto:[email protected]"> | ||
<link rel="help" href="https://drafts.csswg.org/css-anchor-position-1/#scroll"> | ||
<script src="/resources/testharness.js"></script> | ||
<script src="/resources/testharnessreport.js"></script> | ||
<script src="support/test-common.js"></script> | ||
<style> | ||
.pos { | ||
position: absolute; | ||
box-sizing: border-box; | ||
border: solid; | ||
position-anchor: --anchor; | ||
width: 50%; | ||
height: 50%; | ||
background: cyan; | ||
} | ||
#container.thicker > .pos { | ||
border-width: thick; | ||
} | ||
</style> | ||
<div style="position:relative; width:500px; height:500px;"> | ||
<div id="scrollable" style="overflow:hidden; width:500px; height:500px;"> | ||
<div style="width:1000px; height:1000px;"> | ||
<div style="height:200px;"></div> | ||
<div style="anchor-name:--anchor; margin-left:200px; width:100px; height:100px; background:gray;"></div> | ||
</div> | ||
</div> | ||
|
||
<div id="container"> | ||
<div id="e1" class="pos" style="position-area:top left;"></div> | ||
<div id="e2" class="pos" style="position-area:top center;"></div> | ||
<div id="e3" class="pos" style="position-area:top right;"></div> | ||
<div id="e4" class="pos" style="position-area:center left;"></div> | ||
<div id="e5" class="pos" style="position-area:center center;"></div> | ||
<div id="e6" class="pos" style="position-area:center right;"></div> | ||
<div id="e7" class="pos" style="position-area:bottom left;"></div> | ||
<div id="e8" class="pos" style="position-area:bottom center;"></div> | ||
<div id="e9" class="pos" style="position-area:bottom right;"></div> | ||
</div> | ||
</div> | ||
|
||
<script> | ||
function assert_rects_equal(elm, x, y, width, height) { | ||
assert_equals(elm.offsetLeft, x, (elm.id + " x")); | ||
assert_equals(elm.offsetTop, y, (elm.id + " y")); | ||
assert_equals(elm.offsetWidth, width, (elm.id + " width")); | ||
assert_equals(elm.offsetHeight, height, (elm.id + " height")); | ||
} | ||
|
||
function assert_scroll_and_layout_at_initial() { | ||
assert_rects_equal(e1, 100, 100, 100, 100); | ||
assert_rects_equal(e2, 225, 100, 50, 100); | ||
assert_rects_equal(e3, 300, 100, 100, 100); | ||
assert_rects_equal(e4, 100, 225, 100, 50); | ||
assert_rects_equal(e5, 225, 225, 50, 50); | ||
assert_rects_equal(e6, 300, 225, 100, 50); | ||
assert_rects_equal(e7, 100, 300, 100, 100); | ||
assert_rects_equal(e8, 225, 300, 50, 100); | ||
assert_rects_equal(e9, 300, 300, 100, 100); | ||
} | ||
|
||
function assert_scroll_at_40_60_layout_at_initial() { | ||
assert_rects_equal(e1, 60, 40, 100, 100); | ||
assert_rects_equal(e2, 185, 40, 50, 100); | ||
assert_rects_equal(e3, 260, 40, 100, 100); | ||
assert_rects_equal(e4, 60, 165, 100, 50); | ||
assert_rects_equal(e5, 185, 165, 50, 50); | ||
assert_rects_equal(e6, 260, 165, 100, 50); | ||
assert_rects_equal(e7, 60, 240, 100, 100); | ||
assert_rects_equal(e8, 185, 240, 50, 100); | ||
assert_rects_equal(e9, 260, 240, 100, 100); | ||
} | ||
|
||
function assert_scroll_and_layout_at_40_60() { | ||
assert_rects_equal(e1, 80, 70, 80, 70); | ||
assert_rects_equal(e2, 185, 70, 50, 70); | ||
assert_rects_equal(e3, 260, 70, 120, 70); | ||
assert_rects_equal(e4, 80, 165, 80, 50); | ||
assert_rects_equal(e5, 185, 165, 50, 50); | ||
assert_rects_equal(e6, 260, 165, 120, 50); | ||
assert_rects_equal(e7, 80, 240, 80, 130); | ||
assert_rects_equal(e8, 185, 240, 50, 130); | ||
assert_rects_equal(e9, 260, 240, 120, 130); | ||
} | ||
|
||
function assert_scroll_at_initial_layout_at_40_60() { | ||
assert_rects_equal(e1, 120, 130, 80, 70); | ||
assert_rects_equal(e2, 225, 130, 50, 70); | ||
assert_rects_equal(e3, 300, 130, 120, 70); | ||
assert_rects_equal(e4, 120, 225, 80, 50); | ||
assert_rects_equal(e5, 225, 225, 50, 50); | ||
assert_rects_equal(e6, 300, 225, 120, 50); | ||
assert_rects_equal(e7, 120, 300, 80, 130); | ||
assert_rects_equal(e8, 225, 300, 50, 130); | ||
assert_rects_equal(e9, 300, 300, 120, 130); | ||
} | ||
|
||
promise_test(async() => { | ||
assert_scroll_and_layout_at_initial(); | ||
}, "Initial scroll position"); | ||
|
||
promise_test(async() => { | ||
await waitUntilNextAnimationFrame(); | ||
await waitUntilNextAnimationFrame(); | ||
scrollable.scrollTo(40, 60); | ||
await waitUntilNextAnimationFrame(); | ||
await waitUntilNextAnimationFrame(); | ||
assert_scroll_at_40_60_layout_at_initial(); | ||
}, "Scroll to 40,60"); | ||
|
||
promise_test(async() => { | ||
// As long as we're within the same animation frame (and therefore haven't | ||
// run ResizeObserver events), there will be no anchor recalculation point. | ||
container.style.display = "flow-root"; | ||
assert_scroll_and_layout_at_initial(); | ||
container.style.display = "none"; | ||
document.body.offsetTop; | ||
container.style.display = "block"; | ||
assert_scroll_and_layout_at_initial(); | ||
}, "Reattach at 40,60"); | ||
|
||
promise_test(async() => { | ||
container.style.display = "none"; | ||
await waitUntilNextAnimationFrame(); | ||
await waitUntilNextAnimationFrame(); | ||
container.style.display = "block"; | ||
await waitUntilNextAnimationFrame(); | ||
await waitUntilNextAnimationFrame(); | ||
assert_scroll_and_layout_at_40_60(); | ||
}, "Redisplay at 40,60"); | ||
|
||
promise_test(async() => { | ||
scrollable.scrollTo(0, 0); | ||
container.className = "thicker"; | ||
container.style.display = "block"; | ||
await waitUntilNextAnimationFrame(); | ||
await waitUntilNextAnimationFrame(); | ||
assert_scroll_at_initial_layout_at_40_60(); | ||
}, "Scroll to 0,0 and relayout"); | ||
|
||
promise_test(async() => { | ||
container.style.display = "none"; | ||
await waitUntilNextAnimationFrame(); | ||
container.style.display = "block"; | ||
await waitUntilNextAnimationFrame(); | ||
await waitUntilNextAnimationFrame(); | ||
assert_scroll_and_layout_at_initial(); | ||
}, "Redisplay at 0,0"); | ||
</script> |