summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/css/css-anchor-position
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:22:09 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:22:09 +0000
commit43a97878ce14b72f0981164f87f2e35e14151312 (patch)
tree620249daf56c0258faa40cbdcf9cfba06de2a846 /testing/web-platform/tests/css/css-anchor-position
parentInitial commit. (diff)
downloadfirefox-43a97878ce14b72f0981164f87f2e35e14151312.tar.xz
firefox-43a97878ce14b72f0981164f87f2e35e14151312.zip
Adding upstream version 110.0.1.upstream/110.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'testing/web-platform/tests/css/css-anchor-position')
-rw-r--r--testing/web-platform/tests/css/css-anchor-position/anchor-name-001.html38
-rw-r--r--testing/web-platform/tests/css/css-anchor-position/anchor-name-002.html51
-rw-r--r--testing/web-platform/tests/css/css-anchor-position/anchor-name-003.html136
-rw-r--r--testing/web-platform/tests/css/css-anchor-position/anchor-name-basics.html40
-rw-r--r--testing/web-platform/tests/css/css-anchor-position/anchor-name-cross-shadow.html54
-rw-r--r--testing/web-platform/tests/css/css-anchor-position/anchor-name-in-shadow.html53
-rw-r--r--testing/web-platform/tests/css/css-anchor-position/anchor-name-inline-001.html55
-rw-r--r--testing/web-platform/tests/css/css-anchor-position/anchor-name-multicol-001.html54
-rw-r--r--testing/web-platform/tests/css/css-anchor-position/anchor-name-multicol-002.html61
-rw-r--r--testing/web-platform/tests/css/css-anchor-position/anchor-name-multicol-003.html65
-rw-r--r--testing/web-platform/tests/css/css-anchor-position/anchor-name-multicol-004.html59
-rw-r--r--testing/web-platform/tests/css/css-anchor-position/anchor-parse-invalid.html41
-rw-r--r--testing/web-platform/tests/css/css-anchor-position/anchor-parse-valid.html67
-rw-r--r--testing/web-platform/tests/css/css-anchor-position/anchor-position-001.html54
-rw-r--r--testing/web-platform/tests/css/css-anchor-position/anchor-position-002.html72
-rw-r--r--testing/web-platform/tests/css/css-anchor-position/anchor-position-003.html58
-rw-r--r--testing/web-platform/tests/css/css-anchor-position/anchor-position-004.html116
-rw-r--r--testing/web-platform/tests/css/css-anchor-position/anchor-position-borders-001.html135
-rw-r--r--testing/web-platform/tests/css/css-anchor-position/anchor-position-borders-002.html85
-rw-r--r--testing/web-platform/tests/css/css-anchor-position/anchor-position-dynamic-001.html65
-rw-r--r--testing/web-platform/tests/css/css-anchor-position/anchor-position-dynamic-002.html54
-rw-r--r--testing/web-platform/tests/css/css-anchor-position/anchor-position-dynamic-003.html105
-rw-r--r--testing/web-platform/tests/css/css-anchor-position/anchor-position-dynamic-004.html47
-rw-r--r--testing/web-platform/tests/css/css-anchor-position/anchor-position-grid-001.html82
-rw-r--r--testing/web-platform/tests/css/css-anchor-position/anchor-position-inline-001.html36
-rw-r--r--testing/web-platform/tests/css/css-anchor-position/anchor-position-inline-002.html37
-rw-r--r--testing/web-platform/tests/css/css-anchor-position/anchor-position-inline-003.html37
-rw-r--r--testing/web-platform/tests/css/css-anchor-position/anchor-position-inline-004.html175
-rw-r--r--testing/web-platform/tests/css/css-anchor-position/anchor-position-multicol-001.html43
-rw-r--r--testing/web-platform/tests/css/css-anchor-position/anchor-position-multicol-002.html109
-rw-r--r--testing/web-platform/tests/css/css-anchor-position/anchor-position-multicol-003.html66
-rw-r--r--testing/web-platform/tests/css/css-anchor-position/anchor-position-multicol-004.html83
-rw-r--r--testing/web-platform/tests/css/css-anchor-position/anchor-position-multicol-005.html64
-rw-r--r--testing/web-platform/tests/css/css-anchor-position/anchor-position-multicol-006.html71
-rw-r--r--testing/web-platform/tests/css/css-anchor-position/anchor-position-multicol-colspan-001.html100
-rw-r--r--testing/web-platform/tests/css/css-anchor-position/anchor-position-multicol-colspan-002.html76
-rw-r--r--testing/web-platform/tests/css/css-anchor-position/anchor-position-multicol-fixed-001.html77
-rw-r--r--testing/web-platform/tests/css/css-anchor-position/anchor-position-multicol-nested-001.html79
-rw-r--r--testing/web-platform/tests/css/css-anchor-position/anchor-position-principal-box.html32
-rw-r--r--testing/web-platform/tests/css/css-anchor-position/anchor-position-top-layer-001.html50
-rw-r--r--testing/web-platform/tests/css/css-anchor-position/anchor-position-top-layer-002.html50
-rw-r--r--testing/web-platform/tests/css/css-anchor-position/anchor-position-top-layer-003.html51
-rw-r--r--testing/web-platform/tests/css/css-anchor-position/anchor-position-top-layer-004.html51
-rw-r--r--testing/web-platform/tests/css/css-anchor-position/anchor-position-top-layer-005.html51
-rw-r--r--testing/web-platform/tests/css/css-anchor-position/anchor-position-top-layer-006.html51
-rw-r--r--testing/web-platform/tests/css/css-anchor-position/anchor-position-top-layer-ref.html34
-rw-r--r--testing/web-platform/tests/css/css-anchor-position/anchor-position-writing-modes-001.html101
-rw-r--r--testing/web-platform/tests/css/css-anchor-position/anchor-position-writing-modes-002.html103
-rw-r--r--testing/web-platform/tests/css/css-anchor-position/anchor-query-custom-property-registration.html50
-rw-r--r--testing/web-platform/tests/css/css-anchor-position/anchor-query-fallback.html67
-rw-r--r--testing/web-platform/tests/css/css-anchor-position/anchor-scroll-basics.tentative.html71
-rw-r--r--testing/web-platform/tests/css/css-anchor-position/anchor-scroll-fallback-position-001.html101
-rw-r--r--testing/web-platform/tests/css/css-anchor-position/anchor-scroll-fallback-position-002.html62
-rw-r--r--testing/web-platform/tests/css/css-anchor-position/anchor-scroll-fallback-position-003.html73
-rw-r--r--testing/web-platform/tests/css/css-anchor-position/anchor-scroll-fallback-position-004.html75
-rw-r--r--testing/web-platform/tests/css/css-anchor-position/anchor-scroll-fallback-position-005.html63
-rw-r--r--testing/web-platform/tests/css/css-anchor-position/anchor-scroll-fixedpos.tentative.html38
-rw-r--r--testing/web-platform/tests/css/css-anchor-position/anchor-scroll-js-expose.tentative.html89
-rw-r--r--testing/web-platform/tests/css/css-anchor-position/anchor-scroll-nested.tentative.html90
-rw-r--r--testing/web-platform/tests/css/css-anchor-position/anchor-scroll-no-overflow-crash.html41
-rw-r--r--testing/web-platform/tests/css/css-anchor-position/anchor-scroll-update-001.tentative.html83
-rw-r--r--testing/web-platform/tests/css/css-anchor-position/anchor-scroll-update-002.tentative.html84
-rw-r--r--testing/web-platform/tests/css/css-anchor-position/anchor-scroll-update-003.tentative.html81
-rw-r--r--testing/web-platform/tests/css/css-anchor-position/anchor-scroll-update-004.tentative.html93
-rw-r--r--testing/web-platform/tests/css/css-anchor-position/anchor-scroll-update-005.tentative.html56
-rw-r--r--testing/web-platform/tests/css/css-anchor-position/anchor-scroll-update-006.tentative.html56
-rw-r--r--testing/web-platform/tests/css/css-anchor-position/anchor-scroll-vlr.tentative.html81
-rw-r--r--testing/web-platform/tests/css/css-anchor-position/anchor-scroll-vrl.tentative.html81
-rw-r--r--testing/web-platform/tests/css/css-anchor-position/anchor-size-001.html42
-rw-r--r--testing/web-platform/tests/css/css-anchor-position/anchor-size-minmax-001.html44
-rw-r--r--testing/web-platform/tests/css/css-anchor-position/anchor-size-parse-invalid.html42
-rw-r--r--testing/web-platform/tests/css/css-anchor-position/anchor-size-parse-valid.html65
-rw-r--r--testing/web-platform/tests/css/css-anchor-position/anchor-size-replaced-001.html74
-rw-r--r--testing/web-platform/tests/css/css-anchor-position/anchor-size-writing-modes-001.html67
-rw-r--r--testing/web-platform/tests/css/css-anchor-position/at-fallback-position-allowed-declarations.html97
-rw-r--r--testing/web-platform/tests/css/css-anchor-position/at-fallback-position-parse.html39
-rw-r--r--testing/web-platform/tests/css/css-anchor-position/at-position-fallback-invalidation-shadow-dom.html50
-rw-r--r--testing/web-platform/tests/css/css-anchor-position/at-position-fallback-invalidation.html57
-rw-r--r--testing/web-platform/tests/css/css-anchor-position/position-fallback-001.html108
-rw-r--r--testing/web-platform/tests/css/css-anchor-position/position-fallback-002.html61
-rw-r--r--testing/web-platform/tests/css/css-anchor-position/position-fallback-basics.html40
-rw-r--r--testing/web-platform/tests/css/css-anchor-position/position-fallback-cascade-layer-reorder.html72
-rw-r--r--testing/web-platform/tests/css/css-anchor-position/position-fallback-custom-property.html68
-rw-r--r--testing/web-platform/tests/css/css-anchor-position/position-fallback-dynamic.html36
-rw-r--r--testing/web-platform/tests/css/css-anchor-position/position-fallback-grid-001.html92
-rw-r--r--testing/web-platform/tests/css/css-anchor-position/position-fallback-tree-scoped.html159
-rw-r--r--testing/web-platform/tests/css/css-anchor-position/reference/anchor-scroll-fixedpos-ref.html32
-rw-r--r--testing/web-platform/tests/css/css-anchor-position/reference/anchor-scroll-nested-ref.html74
-rw-r--r--testing/web-platform/tests/css/css-anchor-position/reference/anchor-scroll-ref.html61
-rw-r--r--testing/web-platform/tests/css/css-anchor-position/reference/anchor-scroll-update-005-ref.html34
-rw-r--r--testing/web-platform/tests/css/css-anchor-position/reference/anchor-scroll-update-006-ref.html34
-rw-r--r--testing/web-platform/tests/css/css-anchor-position/reference/anchor-scroll-vlr-ref.html70
-rw-r--r--testing/web-platform/tests/css/css-anchor-position/reference/anchor-scroll-vrl-ref.html70
-rw-r--r--testing/web-platform/tests/css/css-anchor-position/reference/sticky-anchor-position-invalid-ref.html28
-rw-r--r--testing/web-platform/tests/css/css-anchor-position/sticky-anchor-position-invalid.html32
-rw-r--r--testing/web-platform/tests/css/css-anchor-position/support/green-16x16.pngbin0 -> 92 bytes
-rw-r--r--testing/web-platform/tests/css/css-anchor-position/support/test-common.js27
97 files changed, 6384 insertions, 0 deletions
diff --git a/testing/web-platform/tests/css/css-anchor-position/anchor-name-001.html b/testing/web-platform/tests/css/css-anchor-position/anchor-name-001.html
new file mode 100644
index 0000000000..f85c9248d9
--- /dev/null
+++ b/testing/web-platform/tests/css/css-anchor-position/anchor-name-001.html
@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/#determining">
+<link rel="author" href="mailto:kojii@chromium.org">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/check-layout-th.js"></script>
+<style>
+.relpos {
+ position: relative;
+}
+.anchor1 {
+ anchor-name: --a1;
+ width: 10px;
+ height: 10px;
+ background: orange;
+}
+.target {
+ position: absolute;
+ width: anchor-size(--a1 width);
+ height: 10px;
+ background: lime;
+}
+</style>
+<body onload="checkLayout('.target')">
+ <!--
+ All targets should find the 10px anchor, because it's the first
+ one in the pre-order DFS from the `relpos`.
+ -->
+ <div class="relpos">
+ <div class="target" data-expected-width=10></div>
+ <div class="anchor1" style="width: 10px">
+ <div class="anchor1" style="width: 20px"></div>
+ <div class="target" data-expected-width=10></div>
+ </div>
+ <div class="anchor1" style="width: 30px"></div>
+ <div class="target" data-expected-width=10></div>
+ <div>
+</body>
diff --git a/testing/web-platform/tests/css/css-anchor-position/anchor-name-002.html b/testing/web-platform/tests/css/css-anchor-position/anchor-name-002.html
new file mode 100644
index 0000000000..88728f6f47
--- /dev/null
+++ b/testing/web-platform/tests/css/css-anchor-position/anchor-name-002.html
@@ -0,0 +1,51 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/#determining">
+<link rel="author" href="mailto:kojii@chromium.org">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/check-layout-th.js"></script>
+<style>
+.relpos {
+ position: relative;
+}
+.abspos {
+ position: absolute;
+}
+.anchor1 {
+ anchor-name: --a1;
+ width: 10px;
+ height: 10px;
+ background: orange;
+}
+.target {
+ position: absolute;
+ width: anchor-size(--a1 width);
+ height: 10px;
+ background: lime;
+}
+</style>
+<body onload="checkLayout('.target')">
+ <div class="relpos">
+ <div>
+ <div class="relpos">
+ <div class="abspos">
+ <div class="relpos">
+ <div class="anchor1" style="position: absolute"></div>
+ <!-- This target should not find the anchor, because the anchor is
+ positioned. -->
+ <div class="target" data-expected-width=0></div>
+ </div>
+ <!-- This target should find the anchor, because the last containing
+ block has `position: relative`. -->
+ <div class="target" data-expected-width=10></div>
+ </div>
+ <!-- This target should not find the anchor, because the last containing
+ block has `position: absolute`. -->
+ <div class="target" data-expected-width=0></div>
+ </div>
+ </div>
+ <!-- This target should find the anchor, because the last containing block
+ is statically positioned. -->
+ <div class="target" data-expected-width=10></div>
+ </div>
+</body>
diff --git a/testing/web-platform/tests/css/css-anchor-position/anchor-name-003.html b/testing/web-platform/tests/css/css-anchor-position/anchor-name-003.html
new file mode 100644
index 0000000000..998e6433d2
--- /dev/null
+++ b/testing/web-platform/tests/css/css-anchor-position/anchor-name-003.html
@@ -0,0 +1,136 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/#determining">
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/#propdef-anchor-name">
+<link rel="author" href="mailto:kojii@chromium.org">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/check-layout-th.js"></script>
+<style>
+.relpos {
+ position: relative;
+}
+.abspos {
+ position: absolute;
+}
+.anchor1 {
+ anchor-name: --a1;
+ width: 10px;
+ height: 10px;
+ background: orange;
+}
+.target {
+ position: absolute;
+ width: anchor-size(--a1 width);
+ height: 10px;
+ background: lime;
+}
+</style>
+<body onload="checkLayout('.target')">
+ <!-- In-flow and out-of-flow boxes in a containing block. -->
+ <div class="relpos">
+ <div>
+ <div class="relpos">
+ <div class="abspos">
+ <div class="relpos">
+ <div class="anchor1" style="position: absolute; width: 10px"></div>
+ <div class="anchor1" style="width: 20px"></div>
+ <div class="anchor1" style="position: absolute; width: 30px"></div>
+ <div class="anchor1" style="width: 40px"></div>
+ <div class="target" data-expected-width=20></div>
+ </div>
+ <div class="target" data-expected-width=10></div>
+ </div>
+ <div class="target" data-expected-width=0></div>
+ </div>
+ <div class="target" data-expected-width=10></div>
+ </div>
+ <div class="target" data-expected-width=10></div>
+ </div>
+
+ <!-- In-flow boxes in ancestors, after the propagated ones. -->
+ <div class="relpos">
+ <div>
+ <div class="relpos">
+ <div class="abspos">
+ <div class="relpos">
+ <div class="anchor1" style="position: absolute; width: 10px"></div>
+ <div class="anchor1" style="width: 20px"></div>
+ <div class="target" data-expected-width=20></div>
+ </div>
+ <div class="anchor1" style="width: 50px"></div>
+ <div class="target" data-expected-width=10></div>
+ </div>
+ <div class="target" data-expected-width=0></div>
+ </div>
+ <div class="anchor1" style="width: 60px"></div>
+ <div class="target" data-expected-width=10></div>
+ </div>
+ <div class="anchor1" style="width: 70px"></div>
+ <div class="target" data-expected-width=10></div>
+ </div>
+
+ <!-- Out-of-flow boxes in ancestors, after the propagated ones. -->
+ <div class="relpos">
+ <div>
+ <div class="relpos">
+ <div class="abspos">
+ <div class="relpos">
+ <div class="anchor1" style="position: absolute; width: 10px"></div>
+ <div class="anchor1" style="width: 20px"></div>
+ <div class="target" data-expected-width=20></div>
+ </div>
+ <div class="anchor1" style="position: absolute; width: 110px"></div>
+ <div class="target" data-expected-width=10></div>
+ </div>
+ <div class="target" data-expected-width=0></div>
+ </div>
+ <div class="target" data-expected-width=10></div>
+ </div>
+ <div class="anchor1" style="position: absolute; width: 100px"></div>
+ <div class="target" data-expected-width=10></div>
+ </div>
+
+ <!-- In-flow boxes in ancestors, before the propagated ones. -->
+ <div class="relpos">
+ <div class="anchor1" style="width: 100px"></div>
+ <div>
+ <div class="relpos">
+ <div class="anchor1" style="width: 110px"></div>
+ <div class="abspos">
+ <div class="anchor1" style="width: 120px"></div>
+ <div class="relpos">
+ <div class="anchor1" style="position: absolute; width: 10px"></div>
+ <div class="anchor1" style="width: 20px"></div>
+ <div class="target" data-expected-width=20></div>
+ </div>
+ <div class="target" data-expected-width=120></div>
+ </div>
+ <div class="target" data-expected-width=110></div>
+ </div>
+ <div class="target" data-expected-width=100></div>
+ </div>
+ <div class="target" data-expected-width=100></div>
+ </div>
+
+ <!-- Out-of-flow boxes in ancestors, before the propagated ones. -->
+ <div class="relpos">
+ <div class="anchor1" style="position: absolute; width: 100px"></div>
+ <div>
+ <div class="relpos">
+ <div class="anchor1" style="position: absolute; width: 110px"></div>
+ <div class="abspos">
+ <div class="anchor1" style="position: absolute; width: 120px"></div>
+ <div class="relpos">
+ <div class="anchor1" style="position: absolute; width: 10px"></div>
+ <div class="anchor1" style="width: 20px"></div>
+ <div class="target" data-expected-width=20></div>
+ </div>
+ <div class="target" data-expected-width=10></div>
+ </div>
+ <div class="target" data-expected-width=0></div>
+ </div>
+ <div class="target" data-expected-width=110></div>
+ </div>
+ <div class="target" data-expected-width=110></div>
+ </div>
+</body>
diff --git a/testing/web-platform/tests/css/css-anchor-position/anchor-name-basics.html b/testing/web-platform/tests/css/css-anchor-position/anchor-name-basics.html
new file mode 100644
index 0000000000..1d88b94137
--- /dev/null
+++ b/testing/web-platform/tests/css/css-anchor-position/anchor-name-basics.html
@@ -0,0 +1,40 @@
+<!DOCTYPE html>
+<title>Tests basics of the 'anchor-name' property</title>
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/#propdef-anchor-name">
+<link rel="author" href="mailto:xiaochengh@chromium.org">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/parsing-testcommon.js"></script>
+<script src="/css/support/computed-testcommon.js"></script>
+<script src="/css/support/inheritance-testcommon.js"></script>
+<script src="/css/support/interpolation-testcommon.js"></script>
+
+<div id="container">
+ <div id="target"></div>
+</div>
+
+<script>
+// anchor-name: none | <dashed-ident>
+test_valid_value('anchor-name', 'none');
+test_valid_value('anchor-name', '--foo');
+test_invalid_value('anchor-name', 'foo-bar');
+test_invalid_value('anchor-name', '--foo --bar')
+test_invalid_value('anchor-name', '--foo, --bar')
+test_invalid_value('anchor-name', '100px');
+test_invalid_value('anchor-name', '100%');
+
+// Computed value: as specified
+test_computed_value('anchor-name', 'none');
+test_computed_value('anchor-name', '--foo');
+
+// Initial: none
+// Inherited: no
+assert_not_inherited('anchor-name', 'none', '--foo');
+
+// Animation type: discrete
+test_no_interpolation({
+ property: 'anchor-name',
+ from: '--foo',
+ to: 'none',
+});
+</script>
diff --git a/testing/web-platform/tests/css/css-anchor-position/anchor-name-cross-shadow.html b/testing/web-platform/tests/css/css-anchor-position/anchor-name-cross-shadow.html
new file mode 100644
index 0000000000..cc494831a8
--- /dev/null
+++ b/testing/web-platform/tests/css/css-anchor-position/anchor-name-cross-shadow.html
@@ -0,0 +1,54 @@
+<!DOCTYPE html>
+<title>Tests that the anchor element can be in a different tree scope</title>
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/#target-anchor-element">
+<link rel="author" href="mailto:xiaochengh@chromium.org">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<style>
+.cb {
+ position: absolute;
+}
+
+#host1::part(anchor) {
+ anchor-name: --a1;
+ margin-left: 15px;
+}
+#target1 {
+ position: absolute;
+ left: anchor(--a1 left);
+}
+</style>
+
+<div class="cb">
+ <div id="host1"></div>
+ <div id="target1"></div>
+</div>
+
+<div class="cb">
+ <div id="host2"></div>
+</div>
+
+<script>
+test(() => {
+ host1.attachShadow({mode: 'open'}).innerHTML = '<div part="anchor"></div>';
+ assert_equals(target1.offsetLeft, 15);
+}, 'Should be able to set anchor-name to a shadow DOM part and anchor to it');
+
+test(() => {
+ let shadow = host2.attachShadow({mode: 'open'});
+ shadow.innerHTML = `
+ <style>
+ :host {
+ anchor-name: --a2;
+ margin-left: 15px;
+ }
+ #target2 {
+ position: absolute;
+ left: anchor(--a2 left);
+ }
+ </style>
+ <div id="target2"></div>
+ `;
+ assert_equals(shadow.getElementById('target2').offsetLeft, 15);
+}, 'Should be able to set anchor-name to the shadow host and anchor to it');
+</script>
diff --git a/testing/web-platform/tests/css/css-anchor-position/anchor-name-in-shadow.html b/testing/web-platform/tests/css/css-anchor-position/anchor-name-in-shadow.html
new file mode 100644
index 0000000000..7e505ed592
--- /dev/null
+++ b/testing/web-platform/tests/css/css-anchor-position/anchor-name-in-shadow.html
@@ -0,0 +1,53 @@
+<!DOCTYPE html>
+<title>anchor-name is a tree scoped reference</title>
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/#target-anchor-element">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<style>
+ body { margin-top: 0; }
+ #anchor {
+ anchor-name: --anchor;
+ }
+ #filler {
+ height: 100px;
+ }
+ #anchored {
+ position: absolute;
+ top: anchor(--anchor top);
+ }
+</style>
+<div id="host"></div>
+<div id="filler"></div>
+<div id="anchor"></div>
+<div id="anchored"></div>
+<script>
+ const host_root = host.attachShadow({mode:"open"});
+ host_root.innerHTML = `
+ <style>
+ div { anchor-name: --anchor; }
+ </style>
+ <div></div>
+ `;
+
+ test(() => {
+ assert_equals(anchored.offsetTop, 100, "#anchored is positioned against #anchor");
+ }, "anchor-name should not leak out of a shadow tree");
+</script>
+
+<div id="anchor_host" style="anchor-name: --anchor-host"></div>
+<script>
+ const anchor_host_root = anchor_host.attachShadow({mode:"open"});
+ anchor_host_root.innerHTML = `
+ <style>
+ div {
+ position: absolute;
+ left: anchor(--anchor-host left, 37px);
+ }
+ </style>
+ <div id="anchored"></div>
+ `;
+
+ test(() => {
+ assert_equals(anchor_host_root.querySelector("#anchored").offsetLeft, 37, "#anchored is positioned using fallback");
+ }, "anchor() in shadow tree should not match host anchor-name");
+</script>
diff --git a/testing/web-platform/tests/css/css-anchor-position/anchor-name-inline-001.html b/testing/web-platform/tests/css/css-anchor-position/anchor-name-inline-001.html
new file mode 100644
index 0000000000..024225fecb
--- /dev/null
+++ b/testing/web-platform/tests/css/css-anchor-position/anchor-name-inline-001.html
@@ -0,0 +1,55 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/#determining">
+<link rel="author" href="mailto:kojii@chromium.org">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/check-layout-th.js"></script>
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+.container {
+ font-family: Ahem;
+ font-size: 10px;
+ line-height: 1;
+ width: 10em;
+}
+.relpos {
+ position: relative;
+}
+.abspos {
+ position: absolute;
+}
+.columns {
+ column-count: 2;
+ column-fill: auto;
+ column-gap: 10px;
+ column-width: 100px;
+ width: 210px;
+ height: 100px;
+}
+.anchor {
+ anchor-name: --a1;
+ background: orange;
+}
+.target {
+ position: absolute;
+ width: anchor-size(--a1 width);
+ height: 10px;
+ background: lime;
+}
+</style>
+<body onload="checkLayout('.target')">
+ <div class="container relpos xcolumns">
+ <div style="height: 150px"></div>
+ <div class="relpos">
+ <span class="relpos">
+ <span class="relpos">
+ <span class="anchor abspos">123</span>
+ <span class="anchor">12</span>
+ <span class="target" data-expected-width=20></span>
+ </span>
+ <span class="target" data-expected-width=30></span>
+ </span>
+ <span class="target" data-expected-width=30></span>
+ </div>
+ <div>
+</body>
diff --git a/testing/web-platform/tests/css/css-anchor-position/anchor-name-multicol-001.html b/testing/web-platform/tests/css/css-anchor-position/anchor-name-multicol-001.html
new file mode 100644
index 0000000000..13ff9524b7
--- /dev/null
+++ b/testing/web-platform/tests/css/css-anchor-position/anchor-name-multicol-001.html
@@ -0,0 +1,54 @@
+<!DOCTYPE html>
+<title>Anchors in a different containing block in multicol</title>
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/#propdef-anchor-name">
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/#anchor-size">
+<link rel="author" href="mailto:kojii@chromium.org">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/check-layout-th.js"></script>
+<style>
+.relpos {
+ position: relative;
+}
+.columns {
+ column-count: 2;
+ column-fill: auto;
+ column-gap: 10px;
+ column-width: 100px;
+ width: 210px;
+ height: 100px;
+}
+.spacer {
+ height: 10px;
+ background: pink;
+}
+.anchor1 {
+ anchor-name: --a1;
+ margin-left: 10px;
+ width: 40px;
+ height: 20px;
+ background: orange;
+}
+.target {
+ position: absolute;
+ left: anchor(--a1 left);
+ top: anchor(--a1 top);
+ width: anchor-size(--a1 width);
+ height: anchor-size(--a1 height);
+ background: lime;
+ opacity: .3;
+}
+</style>
+<body onload="checkLayout('.target')">
+ <div class="columns">
+ <div class="relpos">
+ <div class="spacer"></div>
+ <div class="anchor1"></div>
+ </div>
+ <div class="relpos">
+ <div class="target"
+ data-offset-x=0 data-offset-y=0
+ data-expected-width=0 data-expected-height=0></div>
+ </div>
+ </div>
+</body>
diff --git a/testing/web-platform/tests/css/css-anchor-position/anchor-name-multicol-002.html b/testing/web-platform/tests/css/css-anchor-position/anchor-name-multicol-002.html
new file mode 100644
index 0000000000..292b6f295a
--- /dev/null
+++ b/testing/web-platform/tests/css/css-anchor-position/anchor-name-multicol-002.html
@@ -0,0 +1,61 @@
+<!DOCTYPE html>
+<title>Anchors in OOF in multicol</title>
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/#propdef-anchor-name">
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/#anchor-pos">
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/#anchor-size">
+<link rel="author" href="mailto:kojii@chromium.org">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/check-layout-th.js"></script>
+<style>
+.relpos {
+ position: relative;
+}
+.abspos {
+ position: absolute;
+}
+.columns {
+ column-count: 2;
+ column-fill: auto;
+ column-gap: 10px;
+ column-width: 100px;
+ width: 210px;
+ height: 100px;
+}
+.spacer {
+ height: 10px;
+ background: pink;
+}
+.anchor {
+ anchor-name: --a1;
+ margin-left: 10px;
+ width: 40px;
+ height: 60px;
+ background: orange;
+}
+.target {
+ position: absolute;
+ background: lime;
+ opacity: .5;
+ left: anchor(--a1 left);
+ top: anchor(--a1 top);
+ width: anchor-size(--a1 width);
+ height: anchor-size(--a1 height);
+}
+</style>
+<body onload="checkLayout('.target')">
+ <div class="spacer"></div>
+ <div class="columns">
+ <div class="relpos">
+ <div class="relpos">
+ <div class="abspos">
+ <div class="spacer"></div>
+ <div class="anchor"></div>
+ </div>
+ </div>
+ <div class="target"
+ data-offset-x=10 data-offset-y=10
+ data-expected-width=40 data-expected-height=60></div>
+ </div>
+ </div>
+</body>
diff --git a/testing/web-platform/tests/css/css-anchor-position/anchor-name-multicol-003.html b/testing/web-platform/tests/css/css-anchor-position/anchor-name-multicol-003.html
new file mode 100644
index 0000000000..a343a732ad
--- /dev/null
+++ b/testing/web-platform/tests/css/css-anchor-position/anchor-name-multicol-003.html
@@ -0,0 +1,65 @@
+<!DOCTYPE html>
+<title>Anchor name resolution of OOF anchors in multicol</title>
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/#propdef-anchor-name">
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/#anchor-size">
+<link rel="author" href="mailto:kojii@chromium.org">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/check-layout-th.js"></script>
+<style>
+.relpos {
+ position: relative;
+}
+.abspos {
+ position: absolute;
+}
+.columns {
+ column-count: 6;
+ column-fill: auto;
+ column-gap: 10px;
+ column-width: 20px;
+ width: 170px;
+ height: 50px;
+}
+.spacer {
+ height: 10px;
+ background: pink;
+}
+.anchor {
+ anchor-name: --a1;
+ margin-left: 5px;
+ width: 10px;
+ background: orange;
+}
+.target {
+ position: absolute;
+ background: lime;
+ opacity: .3;
+ left: anchor(--a1 left);
+ top: anchor(--a1 top);
+ width: anchor-size(--a1 width);
+ height: anchor-size(--a1 height);
+}
+</style>
+<body onload="checkLayout('.target')">
+ <div class="spacer"></div>
+ <div class="relpos">
+ <div class="columns relpos">
+ <div class="relpos">
+ <div class="relpos">
+ <div class="spacer"></div>
+ <div class="anchor abspos" style="top: 120px; height: 100px"></div>
+ <div class="anchor" style="height: 60px"></div>
+ <div class="target"
+ data-expected-width=40 data-expected-height=50></div>
+ </div>
+ <div class="target"
+ data-expected-width=70 data-expected-height=50></div>
+ </div>
+ <div class="target"
+ data-expected-width=70 data-expected-height=50></div>
+ </div>
+ <div class="target"
+ data-expected-width=70 data-expected-height=50></div>
+ </div>
+</body>
diff --git a/testing/web-platform/tests/css/css-anchor-position/anchor-name-multicol-004.html b/testing/web-platform/tests/css/css-anchor-position/anchor-name-multicol-004.html
new file mode 100644
index 0000000000..11287c0c60
--- /dev/null
+++ b/testing/web-platform/tests/css/css-anchor-position/anchor-name-multicol-004.html
@@ -0,0 +1,59 @@
+<!DOCTYPE html>
+<title>Anchor name resolution of OOF anchors in multicol</title>
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/#propdef-anchor-name">
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/#anchor-size">
+<link rel="author" href="mailto:kojii@chromium.org">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/check-layout-th.js"></script>
+<style>
+.relpos {
+ position: relative;
+}
+.abspos {
+ position: absolute;
+}
+.columns {
+ column-count: 6;
+ column-fill: auto;
+ column-gap: 10px;
+ column-width: 20px;
+ width: 170px;
+ height: 50px;
+}
+.spacer {
+ height: 10px;
+ background: pink;
+}
+.anchor {
+ anchor-name: --a1;
+ margin-left: 5px;
+ width: 10px;
+ background: orange;
+}
+.target {
+ position: absolute;
+ background: lime;
+ opacity: .3;
+ left: anchor(--a1 left);
+ top: anchor(--a1 top);
+ width: anchor-size(--a1 width);
+ height: anchor-size(--a1 height);
+}
+</style>
+<body onload="checkLayout('.target')">
+ <div class="spacer"></div>
+ <div class="relpos">
+ <div class="columns relpos">
+ <div class="relpos">
+ <div class="spacer"></div>
+ <div class="anchor" style="height: 60px"></div>
+ <div class="anchor abspos" style="top: 120px; height: 100px"></div>
+ <div class="target"
+ data-expected-width=40 data-expected-height=50></div>
+ </div>
+ <div class="target"
+ data-expected-width=40 data-expected-height=50></div>
+ </div>
+ </div>
+</body>
diff --git a/testing/web-platform/tests/css/css-anchor-position/anchor-parse-invalid.html b/testing/web-platform/tests/css/css-anchor-position/anchor-parse-invalid.html
new file mode 100644
index 0000000000..de4b0ffac4
--- /dev/null
+++ b/testing/web-platform/tests/css/css-anchor-position/anchor-parse-invalid.html
@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+<title>Tests values that are invalid at parse time for the anchor() function</title>
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/#anchor-pos">
+<link rel="author" href="mailto:xiaochengh@chromium.org">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/parsing-testcommon.js"></script>
+
+<script>
+// anchor() can only be used in inset properties
+test_invalid_value('margin-top', 'anchor(--foo top)');
+test_invalid_value('height', 'anchor(--foo top)');
+test_invalid_value('font-size', 'anchor(--foo top)');
+
+// Invalid parameter format
+test_invalid_value('top', 'anchor(--foo, top)');
+test_invalid_value('top', 'anchor(--foo top,)');
+test_invalid_value('top', 'anchor(--foo top bottom)');
+test_invalid_value('top', 'anchor(--foo top, 10px 20%)');
+test_invalid_value('top', 'anchor(--foo top, 10px, 20%)');
+
+// Anchor name must be a dashed ident
+test_invalid_value('top', 'anchor(foo top)');
+
+// Invalid anchor side values
+test_invalid_value('top', 'anchor(--foo height)');
+test_invalid_value('top', 'anchor(--foo 10em)');
+test_invalid_value('top', 'anchor(--foo 100s)');
+
+// Invalid fallback values
+test_invalid_value('top', 'anchor(--foo top, 1)');
+test_invalid_value('top', 'anchor(--foo top, 100s)');
+test_invalid_value('top', 'anchor(--foo top, bottom)');
+test_invalid_value('top', 'anchor(--foo top, anchor(bar top))');
+test_invalid_value('top', 'anchor(--foo top, anchor-size(--bar height))');
+
+// Invalid anchor values in calc tree
+test_invalid_value('top', 'calc(anchor(foo top) + 10px + 10%)');
+test_invalid_value('top', 'calc(10px + 100 * anchor(--foo top, anchor(bar bottom)))');
+test_invalid_value('top', 'min(anchor(--foo top), anchor(--bar bottom), anchor-size(--baz height))');
+</script>
diff --git a/testing/web-platform/tests/css/css-anchor-position/anchor-parse-valid.html b/testing/web-platform/tests/css/css-anchor-position/anchor-parse-valid.html
new file mode 100644
index 0000000000..14d233e5f4
--- /dev/null
+++ b/testing/web-platform/tests/css/css-anchor-position/anchor-parse-valid.html
@@ -0,0 +1,67 @@
+<!DOCTYPE html>
+<title>Tests parsing of the anchor() function</title>
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/#anchor-pos">
+<link rel="author" href="mailto:xiaochengh@chromium.org">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/parsing-testcommon.js"></script>
+
+<script>
+const anchorNames = [
+ '',
+ '--foo',
+];
+
+const insetProperties = [
+ 'left',
+ 'right',
+ 'top',
+ 'bottom',
+ 'inset-block-start',
+ 'inset-block-end',
+ 'inset-inline-start',
+ 'inset-inline-end',
+];
+
+const anchorSides = [
+ 'left',
+ 'right',
+ 'top',
+ 'bottom',
+ 'start',
+ 'end',
+ 'self-start',
+ 'self-end',
+ 'center',
+ '50%',
+];
+
+const fallbacks = [
+ null,
+ '1px',
+ '50%',
+ 'calc(1px + 50%)',
+ 'anchor(left)',
+ 'anchor(--bar left)',
+ 'anchor(--bar left, anchor(--baz right))',
+];
+
+// Tests basic combinations
+for (let property of insetProperties) {
+ // Using a wrong anchor-side (e.g., `top: anchor(--foo left)`) doesn't cause a
+ // parse error, but triggers the fallback when resolved.
+ for (let name of anchorNames) {
+ for (let side of anchorSides) {
+ for (let fallback of fallbacks) {
+ let value = `anchor(${name ? name + ' ' : ''}${side}${fallback ? ', ' + fallback : ''})`;
+ test_valid_value(property, value);
+ }
+ }
+ }
+}
+
+// Tests that anchor() can be used in a calc tree
+test_valid_value('top', 'calc((anchor(--foo top) + anchor(--bar bottom)) / 2)');
+test_valid_value('top', 'anchor(--foo top, calc(anchor(--bar bottom) * 0.5))');
+test_valid_value('top', 'min(100px, 10%, anchor(--foo top), anchor(--bar bottom))');
+</script>
diff --git a/testing/web-platform/tests/css/css-anchor-position/anchor-position-001.html b/testing/web-platform/tests/css/css-anchor-position/anchor-position-001.html
new file mode 100644
index 0000000000..68e62e5479
--- /dev/null
+++ b/testing/web-platform/tests/css/css-anchor-position/anchor-position-001.html
@@ -0,0 +1,54 @@
+<!DOCTYPE html>
+<title>Tests `anchor` function for top/left/bottom/right properties</title>
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/#propdef-anchor-name">
+<link rel="author" href="mailto:kojii@chromium.org">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/check-layout-th.js"></script>
+<style>
+#container {
+ position: relative;
+}
+#a1 {
+ anchor-name: --a1;
+ background: orange;
+ margin-left: 100px;
+ margin-top: 100px;
+ width: 100px;
+ height: 100px;
+}
+#a2 {
+ anchor-name: --a2;
+ background: purple;
+ margin-left: 500px;
+ margin-top: 100px;
+ width: 100px;
+ height: 100px;
+}
+#target {
+ background: green;
+ position: absolute;
+ left: anchor(--a1 right);
+ top: anchor(--a1 bottom);
+ right: anchor(--a2 left);
+ bottom: anchor(--a2 top);
+}
+#ref {
+ background: red;
+ position: absolute;
+ left: 200px;
+ top: 100px;
+ width: 300px;
+ height: 100px;
+}
+</style>
+<body onload="checkLayout('#target')">
+ <div id="container">
+ <div id="a1"></div>
+ <div id="a2"></div>
+ <div id="ref"></div>
+ <div id="target"
+ data-offset-x=200 data-offset-y=100
+ data-expected-width=300 data-expected-height=100></div>
+ </div>
+</body>
diff --git a/testing/web-platform/tests/css/css-anchor-position/anchor-position-002.html b/testing/web-platform/tests/css/css-anchor-position/anchor-position-002.html
new file mode 100644
index 0000000000..0e4b2808d3
--- /dev/null
+++ b/testing/web-platform/tests/css/css-anchor-position/anchor-position-002.html
@@ -0,0 +1,72 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/#propdef-anchor-name">
+<link rel="author" href="mailto:kojii@chromium.org">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/check-layout-th.js"></script>
+<style>
+#container {
+ position: relative;
+ transform: translate(0, 0); /* Make it a containing block. */
+}
+#anchor1 {
+ anchor-name: --a1;
+ width: 5px;
+ height: 7px;
+ background: orange;
+}
+#anchor2 {
+ anchor-name: --a2;
+ width: 9px;
+ height: 11px;
+ background: blue;
+}
+#anchor3 {
+ anchor-name: --a3;
+ width: 13px;
+ height: 15px;
+ background: purple;
+}
+.target {
+ position: absolute;
+}
+</style>
+<!--
+ The anchors are in different containing blocks, but they still fulfill the
+ conditions:
+ * if it has a different containing block from the querying element, the last
+ containing block in its containing block chain before reaching the querying
+ element’s containing block is not, itself, positioned.
+ https://drafts.csswg.org/css-anchor-1/#determining
+
+ From the definition of the "containing block":
+ https://drafts.csswg.org/css-position/#def-cb
+ properties such as `transform` can create a containing block without setting
+ the `position` property.
+-->
+<body onload="checkLayout('.target')">
+ <div id="container">
+ <div>
+ <div id="anchor1"></div>
+ </div>
+ <div class="target" style="left: anchor(--a1 right)" data-offset-x=5></div>
+
+ <div>
+ <div style="transform: translate(0, 0)">
+ <div style="position: absolute; left: 10px;">
+ <div id="anchor2"></div>
+ </div>
+ </div>
+ </div>
+ <div class="target" style="left: anchor(--a2 right)" data-offset-x=19></div>
+
+ <div>
+ <div style="transform: translate(0, 0)">
+ <div style="position: fixed; left: 20px">
+ <div id="anchor3"></div>
+ </div>
+ </div>
+ </div>
+ <div class="target" style="left: anchor(--a3 right)" data-offset-x=33></div>
+ </div>
+</body>
diff --git a/testing/web-platform/tests/css/css-anchor-position/anchor-position-003.html b/testing/web-platform/tests/css/css-anchor-position/anchor-position-003.html
new file mode 100644
index 0000000000..fe8ec3a8d6
--- /dev/null
+++ b/testing/web-platform/tests/css/css-anchor-position/anchor-position-003.html
@@ -0,0 +1,58 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/#determining">
+<link rel="author" href="mailto:kojii@chromium.org">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/check-layout-th.js"></script>
+<style>
+.cb {
+ position: relative;
+}
+.not-positioned-cb {
+ transform: translate(0, 0); /* Make it a containing block. */
+}
+.anchor1 {
+ anchor-name: --a1;
+}
+.size5x7 {
+ width: 5px;
+ height: 7px;
+ background: orange;
+}
+.size9x11 {
+ width: 9px;
+ height: 11px;
+ background: blue;
+}
+.target {
+ position: absolute;
+}
+</style>
+<!--
+ To determine the target anchor element, find the first element el in tree
+ order.
+ https://drafts.csswg.org/css-anchor-1/#determining
+-->
+<body onload="checkLayout('.target')">
+ <div class="cb">
+ <div class="anchor1 size5x7"></div>
+ <div class="anchor1 size9x11"></div>
+ <div class="target" style="left: anchor(--a1 right)" data-offset-x=5></div>
+ </div>
+
+ <div class="cb">
+ <div class="anchor1 size5x7">
+ <div class="anchor1 size9x11"></div>
+ <div class="target" style="left: anchor(--a1 right)" data-offset-x=5></div>
+ </div>
+ <div class="target" style="left: anchor(--a1 right)" data-offset-x=5></div>
+ </div>
+
+ <div class="cb">
+ <div class="anchor1 size5x7 not-positioned-cb">
+ <div class="anchor1 size9x11"></div>
+ <div class="target" style="left: anchor(--a1 right)" data-offset-x=9></div>
+ </div>
+ <div class="target" style="left: anchor(--a1 right)" data-offset-x=5></div>
+ </div>
+</body>
diff --git a/testing/web-platform/tests/css/css-anchor-position/anchor-position-004.html b/testing/web-platform/tests/css/css-anchor-position/anchor-position-004.html
new file mode 100644
index 0000000000..d6d4d64276
--- /dev/null
+++ b/testing/web-platform/tests/css/css-anchor-position/anchor-position-004.html
@@ -0,0 +1,116 @@
+<!DOCTYPE html>
+<title>The `anchor()` function with percentages</title>
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/#anchor-pos">
+<link rel="author" href="mailto:kojii@chromium.org">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/check-layout-th.js"></script>
+<style>
+.relpos {
+ position: relative;
+ width: 200px;
+ outline: 1px solid;
+}
+.vrl-rtl {
+ writing-mode: vertical-rl;
+ direction: rtl;
+}
+.spacer {
+ background: yellow;
+ width: 10px;
+ height: 10px;
+}
+#anchor {
+ anchor-name: --a1;
+ margin: 20px;
+ width: 100px;
+ height: 200px;
+ background: orange;
+}
+.target {
+ position: absolute;
+}
+</style>
+<body onload="checkLayout('.target')">
+ <div class="relpos">
+ <div class="spacer"></div>
+ <div id="anchor"></div>
+
+ <div class="target" style="left: anchor(--a1 0%)"
+ data-offset-x="20"></div>
+ <div class="target" style="left: anchor(--a1 20%)"
+ data-offset-x="40"></div>
+ <div class="target" style="left: anchor(--a1 50%)"
+ data-offset-x="70"></div>
+ <div class="target" style="left: anchor(--a1 center)"
+ data-offset-x="70"></div>
+ <div class="target" style="left: anchor(--a1 80%)"
+ data-offset-x="100"></div>
+ <div class="target" style="left: anchor(--a1 100%)"
+ data-offset-x="120"></div>
+
+ <div class="target" style="right: anchor(--a1 0%)"
+ data-offset-x="20"></div>
+ <div class="target" style="right: anchor(--a1 20%)"
+ data-offset-x="40"></div>
+ <div class="target" style="right: anchor(--a1 50%)"
+ data-offset-x="70"></div>
+ <div class="target" style="right: anchor(--a1 center)"
+ data-offset-x="70"></div>
+ <div class="target" style="right: anchor(--a1 80%)"
+ data-offset-x="100"></div>
+ <div class="target" style="right: anchor(--a1 100%)"
+ data-offset-x="120"></div>
+
+ <div class="target" style="top: anchor(--a1 0%)"
+ data-offset-y="30"></div>
+ <div class="target" style="top: anchor(--a1 20%)"
+ data-offset-y="70"></div>
+ <div class="target" style="top: anchor(--a1 50%)"
+ data-offset-y="130"></div>
+ <div class="target" style="top: anchor(--a1 center)"
+ data-offset-y="130"></div>
+ <div class="target" style="top: anchor(--a1 80%)"
+ data-offset-y="190"></div>
+ <div class="target" style="top: anchor(--a1 100%)"
+ data-offset-y="230"></div>
+
+ <div class="target" style="bottom: anchor(--a1 0%)"
+ data-offset-y="30"></div>
+ <div class="target" style="bottom: anchor(--a1 20%)"
+ data-offset-y="70"></div>
+ <div class="target" style="bottom: anchor(--a1 50%)"
+ data-offset-y="130"></div>
+ <div class="target" style="bottom: anchor(--a1 center)"
+ data-offset-y="130"></div>
+ <div class="target" style="bottom: anchor(--a1 80%)"
+ data-offset-y="190"></div>
+ <div class="target" style="bottom: anchor(--a1 100%)"
+ data-offset-y="230"></div>
+ </div>
+
+ <div class="vrl-rtl relpos">
+ <div class="spacer"></div>
+ <div id="anchor"></div>
+
+ <div class="target" style="left: anchor(--a1 0%)"
+ data-offset-x="170"></div>
+ <div class="target" style="left: anchor(--a1 100%)"
+ data-offset-x="70"></div>
+
+ <div class="target" style="right: anchor(--a1 0%)"
+ data-offset-x="170"></div>
+ <div class="target" style="right: anchor(--a1 100%)"
+ data-offset-x="70"></div>
+
+ <div class="target" style="top: anchor(--a1 0%)"
+ data-offset-y="220"></div>
+ <div class="target" style="top: anchor(--a1 100%)"
+ data-offset-y="20"></div>
+
+ <div class="target" style="bottom: anchor(--a1 0%)"
+ data-offset-y="220"></div>
+ <div class="target" style="bottom: anchor(--a1 100%)"
+ data-offset-y="20"></div>
+ </div>
+</body>
diff --git a/testing/web-platform/tests/css/css-anchor-position/anchor-position-borders-001.html b/testing/web-platform/tests/css/css-anchor-position/anchor-position-borders-001.html
new file mode 100644
index 0000000000..5bbe3d7914
--- /dev/null
+++ b/testing/web-platform/tests/css/css-anchor-position/anchor-position-borders-001.html
@@ -0,0 +1,135 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/#anchor-pos">
+<link rel="author" href="mailto:kojii@chromium.org">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/check-layout-th.js"></script>
+<style>
+.cb {
+ position: relative;
+ border-bottom: 2px solid gray;
+}
+.not-positioned-cb {
+ transform: translate(0, 0); /* Make it a containing block. */
+}
+.margins { margin: 5px 6px 7px 8px; }
+.borders { border-width: 5px 6px 7px 8px; border-style: solid; }
+.paddings { padding: 5px 6px 7px 8px; }
+.spacer {
+ height: 9px;
+}
+.anchor1 {
+ anchor-name: --a1;
+ margin-left: 50px;
+ width: 31px;
+ height: 31px;
+ background: blue;
+}
+.target {
+ position: absolute;
+ left: anchor(--a1 left);
+ right: anchor(--a1 right);
+ top: anchor(--a1 top);
+ bottom: anchor(--a1 bottom);
+ background: orange;
+}
+</style>
+<body onload="checkLayout('.target')">
+ <!-- Margins/borders/paddings on the containing block. -->
+ <div class="cb margins">
+ <div class="spacer"></div>
+ <div class="anchor1"></div>
+ <div class="target"
+ data-offset-x=50 data-offset-y=9
+ data-expected-width=31 data-expected-height=31></div>
+ </div>
+ <div class="cb borders">
+ <div class="spacer"></div>
+ <div class="anchor1"></div>
+ <div class="target"
+ data-offset-x=50 data-offset-y=9
+ data-expected-width=31 data-expected-height=31></div>
+ </div>
+ <div class="cb paddings">
+ <div class="spacer"></div>
+ <div class="anchor1"></div>
+ <div class="target"
+ data-offset-x=58 data-offset-y=14
+ data-expected-width=31 data-expected-height=31></div>
+ </div>
+
+ <!-- Margins/borders/paddings on the nested containing block. -->
+ <div class="cb">
+ <div class="spacer"></div>
+ <div class="not-positioned-cb margins">
+ <div class="anchor1"></div>
+ </div>
+ <div class="target"
+ data-offset-x=58 data-offset-y=14
+ data-expected-width=31 data-expected-height=31></div>
+ </div>
+ <div class="cb">
+ <div class="spacer"></div>
+ <div class="not-positioned-cb borders">
+ <div class="anchor1"></div>
+ </div>
+ <div class="target"
+ data-offset-x=58 data-offset-y=14
+ data-expected-width=31 data-expected-height=31></div>
+ </div>
+ <div class="cb">
+ <div class="spacer"></div>
+ <div class="not-positioned-cb paddings">
+ <div class="anchor1"></div>
+ </div>
+ <div class="target"
+ data-offset-x=58 data-offset-y=14
+ data-expected-width=31 data-expected-height=31></div>
+ </div>
+
+ <!-- Margins/borders/paddings on the anchor. -->
+ <div class="cb">
+ <div class="spacer"></div>
+ <div class="anchor1 margins"></div>
+ <div class="target"
+ data-offset-x=50 data-offset-y=14
+ data-expected-width=31 data-expected-height=31></div>
+ </div>
+ <div class="cb">
+ <div class="spacer"></div>
+ <div class="anchor1 borders"></div>
+ <div class="target"
+ data-offset-x=50 data-offset-y=9
+ data-expected-width=45 data-expected-height=43></div>
+ </div>
+ <div class="cb">
+ <div class="spacer"></div>
+ <div class="anchor1 paddings"></div>
+ <div class="target"
+ data-offset-x=50 data-offset-y=9
+ data-expected-width=45 data-expected-height=43></div>
+ </div>
+
+ <!-- Margins/borders/paddings on the querying element. -->
+ <div class="cb">
+ <div class="spacer"></div>
+ <div class="anchor1"></div>
+ <div class="target margins"
+ data-offset-x=58 data-offset-y=14
+ data-expected-width=17 data-expected-height=19></div>
+ </div>
+ <div class="cb">
+ <div class="spacer"></div>
+ <div class="anchor1"></div>
+ <div class="target borders"
+ data-offset-x=50 data-offset-y=9
+ data-expected-width=31 data-expected-height=31></div>
+ </div>
+ <div class="cb">
+ <div class="spacer"></div>
+ <div class="anchor1"></div>
+ <div class="target paddings"
+ data-offset-x=50 data-offset-y=9
+ data-expected-width=31 data-expected-height=31></div>
+ </div>
+</body>
diff --git a/testing/web-platform/tests/css/css-anchor-position/anchor-position-borders-002.html b/testing/web-platform/tests/css/css-anchor-position/anchor-position-borders-002.html
new file mode 100644
index 0000000000..a3813750bf
--- /dev/null
+++ b/testing/web-platform/tests/css/css-anchor-position/anchor-position-borders-002.html
@@ -0,0 +1,85 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/#anchor-pos">
+<link rel="author" href="mailto:kojii@chromium.org">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<style>
+.cb {
+ position: relative;
+ border-bottom: 2px solid gray;
+}
+.not-positioned-cb {
+ transform: translate(0, 0); /* Make it a containing block. */
+}
+.scroller { overflow: scroll; }
+.borders { border-width: 5px 6px 7px 8px; border-style: solid; }
+.spacer {
+ height: 9px;
+}
+.anchor1 {
+ anchor-name: --a1;
+ margin-right: 50px;
+ width: 31px;
+ height: 31px;
+ background: red;
+}
+.target {
+ position: absolute;
+ left: anchor(--a1 left);
+ right: anchor(--a1 right);
+ top: anchor(--a1 top);
+ bottom: anchor(--a1 bottom);
+ background: lime;
+}
+</style>
+<body>
+ <div class="spacer"></div>
+ <div class="cb scroller" dir="rtl">
+ <div class="spacer"></div>
+ <div class="anchor1"></div>
+ <div class="target"></div>
+ </div>
+ <div class="cb scroller borders" dir="rtl">
+ <div class="spacer"></div>
+ <div class="anchor1"></div>
+ <div class="target"></div>
+ </div>
+ <div class="cb">
+ <div class="scroller borders" dir="rtl">
+ <div class="spacer"></div>
+ <div class="anchor1"></div>
+ </div>
+ <div class="target"></div>
+ </div>
+ <div class="cb scroller borders" dir="rtl">
+ <div class="not-positioned-cb">
+ <div class="spacer"></div>
+ <div class="anchor1"></div>
+ </div>
+ <div class="target"></div>
+ </div>
+ <div class="cb scroller borders" dir="rtl">
+ <div class="not-positioned-cb scroller borders">
+ <div class="spacer"></div>
+ <div class="anchor1"></div>
+ </div>
+ <div class="target"></div>
+ </div>
+<script>
+function getBoundingClientRectAsArray(element) {
+ const rect = element.getBoundingClientRect();
+ return [rect.left, rect.top, rect.right, rect.bottom];
+}
+
+const anchors = document.getElementsByClassName('anchor1');
+const targets = document.getElementsByClassName('target');
+for (let i = 0; i < targets.length; ++i) {
+ test(() => {
+ const anchor = anchors[i];
+ const target = targets[i];
+ assert_array_equals(getBoundingClientRectAsArray(anchor),
+ getBoundingClientRectAsArray(target));
+ });
+}
+</script>
+</body>
diff --git a/testing/web-platform/tests/css/css-anchor-position/anchor-position-dynamic-001.html b/testing/web-platform/tests/css/css-anchor-position/anchor-position-dynamic-001.html
new file mode 100644
index 0000000000..5b5ee82990
--- /dev/null
+++ b/testing/web-platform/tests/css/css-anchor-position/anchor-position-dynamic-001.html
@@ -0,0 +1,65 @@
+<!DOCTYPE html>
+<title>Tests `anchor` function when anchor positions are changed dynamically</title>
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/#propdef-anchor-name">
+<link rel="author" href="mailto:kojii@chromium.org">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/check-layout-th.js"></script>
+<style>
+#container {
+ position: relative;
+}
+#a1 {
+ anchor-name: --a1;
+ background: orange;
+ margin-left: 100px;
+ margin-top: 100px;
+ width: 50px;
+ height: 50px;
+}
+.after #a1 {
+ width: 100px;
+ height: 100px;
+}
+#a2 {
+ anchor-name: --a2;
+ background: purple;
+ margin-left: 250px;
+ margin-top: 350px;
+ width: 100px;
+ height: 100px;
+}
+.after #a2 {
+ margin-left: 500px;
+ margin-top: 100px;
+}
+#target {
+ background: green;
+ position: absolute;
+ left: anchor(--a1 right);
+ top: anchor(--a1 bottom);
+ right: anchor(--a2 left);
+ bottom: anchor(--a2 top);
+}
+#ref {
+ background: red;
+ position: absolute;
+ left: 200px;
+ top: 100px;
+ width: 300px;
+ height: 100px;
+}
+</style>
+<body id="container">
+ <div id="a1"></div>
+ <div id="a2"></div>
+ <div id="ref"></div>
+ <div id="target"
+ data-offset-x=200 data-offset-y=100
+ data-expected-width=300 data-expected-height=100></div>
+<script>
+document.body.offsetTop; // Force layout.
+container.classList.add('after');
+checkLayout('#target');
+</script>
+</body>
diff --git a/testing/web-platform/tests/css/css-anchor-position/anchor-position-dynamic-002.html b/testing/web-platform/tests/css/css-anchor-position/anchor-position-dynamic-002.html
new file mode 100644
index 0000000000..f70f93441d
--- /dev/null
+++ b/testing/web-platform/tests/css/css-anchor-position/anchor-position-dynamic-002.html
@@ -0,0 +1,54 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/#propdef-anchor-name">
+<link rel="author" href="mailto:kojii@chromium.org">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/check-layout-th.js"></script>
+<style>
+#container {
+ position: relative;
+}
+#anchor1 {
+ anchor-name: --a1;
+}
+#anchor2 {
+ anchor-name: --a2;
+}
+#anchor1, #anchor2 {
+ width: 5px;
+ height: 7px;
+ background: orange;
+}
+.after #anchor1, .after #anchor2 {
+ width: 10px;
+}
+.target {
+ position: absolute;
+}
+</style>
+<body>
+ <div id="container">
+ <!-- When the anchor is in the same containing block. -->
+ <div id="anchor1"></div>
+ <div class="target" style="left: anchor(--a1 right)" data-offset-x=5></div>
+ <div class="target" style="width: anchor-size(--a1 width)" data-expected-width=5></div>
+
+ <!-- When the anchor is in a different containing block. -->
+ <div>
+ <div id="anchor2"></div>
+ </div>
+ <div class="target" style="left: anchor(--a2 right)" data-offset-x=5></div>
+ <div class="target" style="width: anchor-size(--a2 width)" data-expected-width=5></div>
+ </div>
+<script>
+checkLayout('.target');
+container.classList.add('after');
+for (const element of document.getElementsByClassName('target')) {
+ if (element.dataset.offsetX === '5')
+ element.dataset.offsetX = '10';
+ if (element.dataset.expectedWidth === '5')
+ element.dataset.expectedWidth = '10';
+}
+checkLayout('.after .target');
+</script>
+</body>
diff --git a/testing/web-platform/tests/css/css-anchor-position/anchor-position-dynamic-003.html b/testing/web-platform/tests/css/css-anchor-position/anchor-position-dynamic-003.html
new file mode 100644
index 0000000000..04ccd56c77
--- /dev/null
+++ b/testing/web-platform/tests/css/css-anchor-position/anchor-position-dynamic-003.html
@@ -0,0 +1,105 @@
+<!DOCTYPE html>
+<title>Tests that anchor layout changes in another BFC cause relayout on the anchored element</title>
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/#propdef-anchor-name">
+<link rel="author" href="mailto:xiaochengh@chromium.org">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/check-layout-th.js"></script>
+<style>
+.containing-block {
+ position: absolute;
+}
+.anchor {
+ anchor-name: --a1;
+ width: 50px;
+ height: 70px;
+ background: orange;
+}
+.after .anchor {
+ width: 70px;
+ height: 50px;
+}
+.target {
+ position: absolute;
+ left: anchor(--a1 right);
+ top: anchor(--a1 bottom);
+ width: anchor-size(--a1 width);
+ height: anchor-size(--a1 height);
+ background: green;
+}
+
+/* Various types of BFC as the containing block of the anchor */
+.float {
+ float: left;
+}
+.table {
+ display: table;
+}
+.inline-block {
+ display: inline-block;
+ vertical-align: bottom;
+}
+.contain {
+ contain: layout;
+}
+.scroller {
+ overflow: scroll;
+ width: 20px;
+ height: 20px;
+}
+</style>
+<body>
+ <div class="containing-block">
+ <div class="float">
+ <div class="anchor"></div>
+ </div>
+ <div class="target"></div>
+ </div>
+
+ <div class="containing-block">
+ <div class="table">
+ <div class="anchor"></div>
+ </div>
+ <div class="target"></div>
+ </div>
+
+ <div class="containing-block">
+ <div class="inline-block">
+ <div class="anchor"></div>
+ </div>
+ <div class="target"></div>
+ </div>
+
+ <div class="containing-block">
+ <div class="contain">
+ <div class="anchor"></div>
+ </div>
+ <div class="target"></div>
+ </div>
+
+ <div class="containing-block">
+ <div class="scroller">
+ <div class="anchor"></div>
+ </div>
+ <div class="target"></div>
+ </div>
+
+<script>
+for (const element of document.getElementsByClassName('target')) {
+ element.dataset.offsetX = '50';
+ element.dataset.offsetY = '70';
+ element.dataset.expectedWidth = '50';
+ element.dataset.expectedHeight = '70';
+}
+checkLayout('.target');
+
+document.body.classList.add('after');
+for (const element of document.getElementsByClassName('target')) {
+ element.dataset.offsetX = '70';
+ element.dataset.offsetY = '50';
+ element.dataset.expectedWidth = '70';
+ element.dataset.expectedHeight = '50';
+}
+checkLayout('.after .target');
+</script>
+</body>
diff --git a/testing/web-platform/tests/css/css-anchor-position/anchor-position-dynamic-004.html b/testing/web-platform/tests/css/css-anchor-position/anchor-position-dynamic-004.html
new file mode 100644
index 0000000000..b818e23c7f
--- /dev/null
+++ b/testing/web-platform/tests/css/css-anchor-position/anchor-position-dynamic-004.html
@@ -0,0 +1,47 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/#anchor-pos">
+<link rel="author" href="mailto:kojii@chromium.org">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/check-layout-th.js"></script>
+<style>
+.cb {
+ position: relative;
+}
+#anchor1 {
+ anchor-name: --a1;
+ margin-left: 15px;
+ width: 30px;
+ height: 20px;
+ background: red;
+}
+.after #anchor1 {
+ margin-left: 50px;
+}
+.target {
+ position: absolute;
+ left: anchor(--a1 left);
+ top: anchor(--a1 top);
+ right: anchor(--a1 right);
+ bottom: anchor(--a1 bottom);
+ background: lime;
+}
+</style>
+<body onload="run_test()">
+ <div class="cb">
+ <div style="contain: strict; height: 50px">
+ <div class="spacer" style="height: 10px"></div>
+ <div id="anchor1"></div>
+ </div>
+
+ <div class="target"
+ data-offset-x=50 data-offset-y=10
+ data-expected-width=30 data-expected-height=20></div>
+ </div>
+<script>
+function run_test() {
+ document.body.classList.add('after');
+ checkLayout('.target');
+}
+</script>
+</body>
diff --git a/testing/web-platform/tests/css/css-anchor-position/anchor-position-grid-001.html b/testing/web-platform/tests/css/css-anchor-position/anchor-position-grid-001.html
new file mode 100644
index 0000000000..8178f212fe
--- /dev/null
+++ b/testing/web-platform/tests/css/css-anchor-position/anchor-position-grid-001.html
@@ -0,0 +1,82 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/#anchor-pos">
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/#anchor-size">
+<link rel="author" href="mailto:kojii@chromium.org">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/check-layout-th.js"></script>
+<style>
+.cb {
+ position: relative;
+}
+.columns {
+ column-count: 3;
+ column-fill: auto;
+ column-gap: 10px;
+ width: 620px;
+ height: 100px;
+}
+.grid {
+ display: grid;
+ grid-template-columns: repeat(2, 100px);
+ grid-template-rows: 50px 100px;
+}
+.spacer {
+ background: yellow;
+}
+.anchor1 {
+ anchor-name: --a1;
+ grid-column: 2;
+ grid-row: 2;
+ border: 2px solid orange;
+ border-width: 5px 6px 7px 8px;
+}
+.target {
+ grid-column: 2;
+ grid-row: 2;
+ position: absolute;
+ width: anchor-size(--a1 width);
+ height: anchor-size(--a1 height);
+ background: lime;
+ opacity: .2;
+}
+.target1-l {
+ left: anchor(--a1 left);
+ top: anchor(--a1 top);
+ width: 8px;
+}
+.target1-r {
+ right: anchor(--a1 right);
+ bottom: anchor(--a1 bottom);
+ width: 6px;
+}
+.target1-t {
+ left: anchor(--a1 left);
+ top: anchor(--a1 top);
+ height: 5px;
+}
+.target1-b {
+ right: anchor(--a1 right);
+ bottom: anchor(--a1 bottom);
+ height: 5px;
+}
+</style>
+<body onload="checkLayout('.target')">
+ <div>
+ <div class="spacer" style="height: 10px"></div>
+ <div class="columns">
+ <div class="spacer" style="height: 10px"></div>
+ <div class="grid cb">
+ <div>1</div>
+ <div>2</div>
+ <div>3</div>
+ <div class="anchor1"></div>
+
+ <div class="target target1-l" data-offset-x=100 data-expected-height=100></div>
+ <div class="target target1-r" data-offset-x=404 data-expected-height=100></div>
+ <div class="target target1-t" data-offset-y=0 data-expected-width=310></div>
+ <div class="target target1-b" data-offset-y=95 data-expected-width=310></div>
+ </div>
+ </div>
+ </div>
+</body>
diff --git a/testing/web-platform/tests/css/css-anchor-position/anchor-position-inline-001.html b/testing/web-platform/tests/css/css-anchor-position/anchor-position-inline-001.html
new file mode 100644
index 0000000000..09acf6be8b
--- /dev/null
+++ b/testing/web-platform/tests/css/css-anchor-position/anchor-position-inline-001.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/#propdef-anchor-name">
+<link rel="author" href="mailto:kojii@chromium.org">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/check-layout-th.js"></script>
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+#container {
+ position: relative;
+ font-family: Ahem;
+ font-size: 10px;
+ line-height: 1;
+ width: 10em;
+}
+#anchor1 {
+ anchor-name: --a1;
+}
+.target {
+ position: absolute;
+}
+</style>
+<body onload="checkLayout('.target')">
+ <div id="container">
+ <div>spacer</div>
+ <div>
+ <br>
+ 0123<span id="anchor1">456</span>78
+ </div>
+
+ <div class="target" style="left: anchor(--a1 left)" data-offset-x=40></div>
+ <div class="target" style="right: anchor(--a1 right)" data-offset-x=70></div>
+ <div class="target" style="top: anchor(--a1 top)" data-offset-y=20></div>
+ <div class="target" style="bottom: anchor(--a1 bottom)" data-offset-y=30></div>
+ </div>
+</body>
diff --git a/testing/web-platform/tests/css/css-anchor-position/anchor-position-inline-002.html b/testing/web-platform/tests/css/css-anchor-position/anchor-position-inline-002.html
new file mode 100644
index 0000000000..c366db4b28
--- /dev/null
+++ b/testing/web-platform/tests/css/css-anchor-position/anchor-position-inline-002.html
@@ -0,0 +1,37 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/#propdef-anchor-name">
+<link rel="author" href="mailto:kojii@chromium.org">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/check-layout-th.js"></script>
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+#container {
+ position: relative;
+ font-family: Ahem;
+ font-size: 10px;
+ line-height: 1;
+ width: 10em;
+}
+#anchor1 {
+ anchor-name: --a1;
+}
+.target {
+ position: absolute;
+}
+</style>
+<body onload="checkLayout('.target')">
+ <div id="container">
+ <div>spacer</div>
+ <div>
+ <br>
+ <!-- The following line wraps between "5" and "7". -->
+ 0123<span id="anchor1">45 789</span>000
+ </div>
+
+ <div class="target" style="left: anchor(--a1 left)" data-offset-x=0></div>
+ <div class="target" style="right: anchor(--a1 right)" data-offset-x=60></div>
+ <div class="target" style="top: anchor(--a1 top)" data-offset-y=20></div>
+ <div class="target" style="bottom: anchor(--a1 bottom)" data-offset-y=40></div>
+ </div>
+</body>
diff --git a/testing/web-platform/tests/css/css-anchor-position/anchor-position-inline-003.html b/testing/web-platform/tests/css/css-anchor-position/anchor-position-inline-003.html
new file mode 100644
index 0000000000..17ab508583
--- /dev/null
+++ b/testing/web-platform/tests/css/css-anchor-position/anchor-position-inline-003.html
@@ -0,0 +1,37 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/#propdef-anchor-name">
+<link rel="author" href="mailto:kojii@chromium.org">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/check-layout-th.js"></script>
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+#container {
+ position: relative;
+ font-family: Ahem;
+ font-size: 10px;
+ line-height: 1;
+ width: 10em;
+}
+#anchor1 {
+ anchor-name: --a1;
+}
+.target {
+ position: absolute;
+}
+</style>
+<body onload="checkLayout('.target')">
+ <div id="container">
+ <div>spacer</div>
+ <div>
+ <br>
+ <!-- The bidi reordering creates two fragments of the `span` in a line. -->
+ a<span id="anchor1">1&#x202E;2&#x202D;</span>z
+ </div>
+
+ <div class="target" style="left: anchor(--a1 left)" data-offset-x=10></div>
+ <div class="target" style="right: anchor(--a1 right)" data-offset-x=40></div>
+ <div class="target" style="top: anchor(--a1 top)" data-offset-y=20></div>
+ <div class="target" style="bottom: anchor(--a1 bottom)" data-offset-y=30></div>
+ </div>
+</body>
diff --git a/testing/web-platform/tests/css/css-anchor-position/anchor-position-inline-004.html b/testing/web-platform/tests/css/css-anchor-position/anchor-position-inline-004.html
new file mode 100644
index 0000000000..58da8be7c7
--- /dev/null
+++ b/testing/web-platform/tests/css/css-anchor-position/anchor-position-inline-004.html
@@ -0,0 +1,175 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/#propdef-anchor-name">
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/#anchor-pos">
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/#anchor-size">
+<link rel="author" href="mailto:kojii@chromium.org">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/check-layout-th.js"></script>
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+body > div {
+ font-family: Ahem;
+ font-size: 10px;
+ line-height: 1;
+ width: 10em;
+}
+.cb {
+ position: relative;
+}
+.columns {
+ column-count: 3;
+ column-fill: auto;
+ column-gap: 1em;
+ column-width: 10em;
+ orphans: 1;
+ widows: 1;
+ width: 32em;
+ height: 50px;
+ background: yellow;
+}
+.anchor1 {
+ anchor-name: --a1;
+ color: red;
+}
+.target {
+ position: absolute;
+ background: lime;
+ opacity: .2;
+}
+.target1-pos {
+ left: anchor(--a1 left);
+ top: anchor(--a1 top);
+ right: anchor(--a1 right);
+ bottom: anchor(--a1 bottom);
+}
+.target1-size {
+ left: anchor(--a1 left);
+ top: anchor(--a1 top);
+ width: anchor-size(--a1 width);
+ height: anchor-size(--a1 height);
+}
+</style>
+<body onload="checkLayout('.target')">
+ <!-- The inline anchor appear in a single line inline containing block. -->
+ <div class="cb">
+ <div>spacer</div>
+ <div>
+ 0
+ <span class="cb">
+ 12
+ <span class="anchor1">a1</span>
+ 34
+ <span class="target target1-pos"
+ data-offset-x=30 data-offset-y=0
+ data-expected-width=20 data-expected-height=10></span>
+ <span class="target target1-size"
+ data-offset-x=30 data-offset-y=0
+ data-expected-width=20 data-expected-height=10></span>
+ </span>
+ <span class="target target1-pos"
+ data-offset-x=50 data-offset-y=10
+ data-expected-width=20 data-expected-height=10></span>
+ <span class="target target1-size"
+ data-offset-x=50 data-offset-y=10
+ data-expected-width=20 data-expected-height=10></span>
+ </div>
+ <span class="target target1-pos"
+ data-offset-x=50 data-offset-y=10
+ data-expected-width=20 data-expected-height=10></span>
+ <span class="target target1-size"
+ data-offset-x=50 data-offset-y=10
+ data-expected-width=20 data-expected-height=10></span>
+ </div>
+
+ <!-- The inline anchor and inline containing block wrap to two lines. -->
+ <div class="cb">
+ <div>
+ 0
+ <span class="cb">
+ 12
+ <span class="anchor1">a1 a1 a1</span>
+ 345
+ <span class="target target1-pos"
+ data-offset-x=-20 data-offset-y=0
+ data-expected-width=100 data-expected-height=20></span>
+ <span class="target target1-size"
+ data-offset-x=-20 data-offset-y=0
+ data-expected-width=100 data-expected-height=20></span>
+ </span>
+ <span class="target target1-pos"
+ data-offset-x=0 data-offset-y=0
+ data-expected-width=100 data-expected-height=20></span>
+ <span class="target target1-size"
+ data-offset-x=0 data-offset-y=0
+ data-expected-width=100 data-expected-height=20></span>
+ </div>
+ <span class="target target1-pos"
+ data-offset-x=0 data-offset-y=0
+ data-expected-width=100 data-expected-height=20></span>
+ <span class="target target1-size"
+ data-offset-x=0 data-offset-y=0
+ data-expected-width=100 data-expected-height=20></span>
+ </div>
+
+ <!-- The inline anchor and inline containing block have forced line breaks. -->
+ <div class="cb">
+ <div>
+ 0
+ <span class="cb">
+ 12
+ <span class="anchor1">a1<br>a1</span>
+ 345
+ <span class="target target1-pos"
+ data-offset-x=-20 data-offset-y=0
+ data-expected-width=70 data-expected-height=20></span>
+ <span class="target target1-size"
+ data-offset-x=-20 data-offset-y=0
+ data-expected-width=70 data-expected-height=20></span>
+ </span>
+ <span class="target target1-pos"
+ data-offset-x=0 data-offset-y=0
+ data-expected-width=70 data-expected-height=20></span>
+ <span class="target target1-size"
+ data-offset-x=0 data-offset-y=0
+ data-expected-width=70 data-expected-height=20></span>
+ </div>
+ <span class="target target1-pos"
+ data-offset-x=0 data-offset-y=0
+ data-expected-width=70 data-expected-height=20></span>
+ <span class="target target1-size"
+ data-offset-x=0 data-offset-y=0
+ data-expected-width=70 data-expected-height=20></span>
+ </div>
+
+ <!-- The inline anchor and inline containing block wrap to two columns. -->
+ <div class="cb columns">
+ <div class="spacer" style="height: 90px"></div>
+ <div>
+ 0
+ <span class="cb">
+ 12
+ <span class="anchor1">a1 a1 a1</span>
+ 345
+ <span class="target target1-pos"
+ data-offset-x=30 data-offset-y=-40
+ data-expected-width=80 data-expected-height=50></span>
+ <span class="target target1-size"
+ data-offset-x=30 data-offset-y=-40
+ data-expected-width=80 data-expected-height=50></span>
+ </span>
+ <span class="target target1-pos"
+ data-offset-x=160 data-offset-y=0
+ data-expected-width=80 data-expected-height=50></span>
+ <span class="target target1-size"
+ data-offset-x=160 data-offset-y=0
+ data-expected-width=80 data-expected-height=50></span>
+ </div>
+ <span class="target target1-pos"
+ data-offset-x=160 data-offset-y=0
+ data-expected-width=80 data-expected-height=50></span>
+ <span class="target target1-size"
+ data-offset-x=160 data-offset-y=0
+ data-expected-width=80 data-expected-height=50></span>
+ </div>
+</body>
diff --git a/testing/web-platform/tests/css/css-anchor-position/anchor-position-multicol-001.html b/testing/web-platform/tests/css/css-anchor-position/anchor-position-multicol-001.html
new file mode 100644
index 0000000000..777df1b84c
--- /dev/null
+++ b/testing/web-platform/tests/css/css-anchor-position/anchor-position-multicol-001.html
@@ -0,0 +1,43 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/#propdef-anchor-name">
+<link rel="author" href="mailto:kojii@chromium.org">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/check-layout-th.js"></script>
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+#container {
+ position: relative;
+ font-family: Ahem;
+ font-size: 10px;
+ line-height: 1;
+ width: 10em;
+}
+.columns {
+ column-width: 100px;
+ column-count: 3;
+ column-gap: 10px;
+ height: 100px;
+}
+#anchor1 {
+ anchor-name: --a1;
+ background: blue;
+}
+.target {
+ position: absolute;
+}
+</style>
+<body onload="checkLayout('.target')">
+ <div id="container">
+ <div>spacer</div>
+ <div class="columns">
+ <div style="height: 150px"></div>
+ <div id="anchor1" style="height: 100px"></div>
+ </div>
+
+ <div class="target" style="left: anchor(--a1 left)" data-offset-x=110></div>
+ <div class="target" style="right: anchor(--a1 right)" data-offset-x=320></div>
+ <div class="target" style="top: anchor(--a1 top)" data-offset-y=10></div>
+ <div class="target" style="bottom: anchor(--a1 bottom)" data-offset-y=110></div>
+ </div>
+</body>
diff --git a/testing/web-platform/tests/css/css-anchor-position/anchor-position-multicol-002.html b/testing/web-platform/tests/css/css-anchor-position/anchor-position-multicol-002.html
new file mode 100644
index 0000000000..748f9ad2b5
--- /dev/null
+++ b/testing/web-platform/tests/css/css-anchor-position/anchor-position-multicol-002.html
@@ -0,0 +1,109 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/#propdef-anchor-name">
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/#anchor-pos">
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/#anchor-size">
+<link rel="author" href="mailto:kojii@chromium.org">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/check-layout-th.js"></script>
+<style>
+.cb {
+ transform: translate(0); /* Make it a containing block. */
+ border-width: 5px 6px 7px 8px;
+ border-style: solid;
+ padding: 5px 6px 7px 8px;
+}
+.columns {
+ column-count: 4;
+ column-fill: auto;
+ column-gap: 10px;
+ column-width: 100px;
+ width: 320px;
+ height: 100px;
+}
+.spacer {
+ height: 10px;
+ background: pink;
+}
+.anchor1 {
+ anchor-name: --a1;
+ margin-left: 10px;
+ width: 50px;
+ height: 90px;
+ background: blue;
+}
+.target {
+ position: absolute;
+}
+.fixed {
+ position: fixed;
+}
+.target1 {
+ left: anchor(--a1 left);
+ top: anchor(--a1 top);
+ width: anchor-size(--a1 width);
+ height: anchor-size(--a1 height);
+ background: lime;
+ opacity: .3;
+}
+.target1-rb {
+ right: anchor(--a1 right);
+ bottom: anchor(--a1 bottom);
+ width: 10px;
+ height: 10px;
+ background: purple;
+}
+</style>
+<body onload="checkLayout('.target')">
+ <p>The green box should be a union of blue boxes,
+ and the purple box should be at the right-bottom of the green box.
+ </p>
+ <div class="spacer" style="height: 10px"></div>
+ <div class="cb">
+ <div class="columns">
+ <div class="spacer" style="height: 30px"></div>
+ <div class="cb">
+ <!-- This spacer fills up to the middle of the 2nd column. -->
+ <div class="spacer" style="height: 130px"></div>
+ <div class="anchor1"></div>
+ <div class="spacer" style="height: 100px"></div>
+
+ <!-- The containing block of querying elements is block-fragmented. -->
+ <div class="target target1"
+ data-offset-x=18 data-offset-y=65
+ data-expected-width=160 data-expected-height=100></div>
+ <div class="target target1-rb"
+ data-offset-x=168 data-offset-y=155></div>
+ <div class="target fixed target1"
+ data-offset-x=26 data-offset-y=70
+ data-expected-width=160 data-expected-height=100></div>
+ <div class="target fixed target1-rb"
+ data-offset-x=176 data-offset-y=160></div>
+ </div>
+
+ <!-- The containing block of querying elements is a multi-column. -->
+ <div class="target target1"
+ data-offset-x=144 data-offset-y=5
+ data-expected-width=160 data-expected-height=100></div>
+ <div class="target target1-rb"
+ data-offset-x=294 data-offset-y=95></div>
+ <div class="target fixed target1"
+ data-offset-x=152 data-offset-y=10
+ data-expected-width=160 data-expected-height=100></div>
+ <div class="target fixed target1-rb"
+ data-offset-x=302 data-offset-y=100></div>
+ </div>
+
+ <!-- The containing block of querying elements is not fragmented. -->
+ <div class="target target1"
+ data-offset-x=144 data-offset-y=5
+ data-expected-width=160 data-expected-height=100></div>
+ <div class="target target1-rb"
+ data-offset-x=294 data-offset-y=95></div>
+ <div class="target fixed target1"
+ data-offset-x=152 data-offset-y=10
+ data-expected-width=160 data-expected-height=100></div>
+ <div class="target fixed target1-rb"
+ data-offset-x=302 data-offset-y=100></div>
+ </div>
+</body>
diff --git a/testing/web-platform/tests/css/css-anchor-position/anchor-position-multicol-003.html b/testing/web-platform/tests/css/css-anchor-position/anchor-position-multicol-003.html
new file mode 100644
index 0000000000..3685d0782c
--- /dev/null
+++ b/testing/web-platform/tests/css/css-anchor-position/anchor-position-multicol-003.html
@@ -0,0 +1,66 @@
+<!DOCTYPE html>
+<title>Tests anchors on out-of-flow boxes</title>
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/#determining">
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/#propdef-anchor-name">
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/#anchor-size">
+<link rel="author" href="mailto:kojii@chromium.org">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/check-layout-th.js"></script>
+<style>
+.relpos {
+ position: relative;
+}
+.columns {
+ column-count: 2;
+ column-fill: auto;
+ column-gap: 10px;
+ column-width: 100px;
+ width: 210px;
+ height: 50px;
+}
+.anchor1 {
+ anchor-name: --a1;
+ position: absolute;
+ width: 10px;
+ height: 30px;
+ background: orange;
+}
+.target {
+ position: absolute;
+ height: anchor-size(--a1 height);
+ background: lime;
+}
+</style>
+<body onload="checkLayout('.target')">
+ <div class="spacer" style="height: 10px"></div>
+ <div class="relpos">
+ <div class="columns">
+ <div class="relpos">
+ <div class="spacer" style="height: 30px"></div>
+ <div class="anchor1"></div>
+ <div class="target" data-expected-height=0></div>
+ </div>
+ <div class="target" data-expected-height=50></div>
+ </div>
+ <div class="target" data-expected-height=50></div>
+ </div>
+
+ <div class="spacer" style="height: 10px"></div>
+ <div class="relpos">
+ <div class="columns">
+ <div class="spacer" style="height: 10px"></div>
+ <div class="relpos">
+ <div class="spacer" style="height: 10px"></div>
+ <div class="relpos">
+ <div class="spacer" style="height: 10px"></div>
+ <div class="anchor1"></div>
+ <div class="target" data-expected-height=0></div>
+ </div>
+ <div class="target" data-expected-height=50></div>
+ </div>
+ <div class="target" data-expected-height=50></div>
+ </div>
+ <div class="target" data-expected-height=50></div>
+ </div>
+</body>
diff --git a/testing/web-platform/tests/css/css-anchor-position/anchor-position-multicol-004.html b/testing/web-platform/tests/css/css-anchor-position/anchor-position-multicol-004.html
new file mode 100644
index 0000000000..dea289f07e
--- /dev/null
+++ b/testing/web-platform/tests/css/css-anchor-position/anchor-position-multicol-004.html
@@ -0,0 +1,83 @@
+<!DOCTYPE html>
+<title>Tests resolving anchor-name conflicts in multicol</title>
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/#propdef-anchor-name">
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/#anchor-pos">
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/#anchor-size">
+<link rel="author" href="mailto:kojii@chromium.org">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/check-layout-th.js"></script>
+<style>
+.cb {
+ transform: translate(0); /* Make it a containing block. */
+ border-width: 5px 6px 7px 8px;
+ border-style: solid;
+ padding: 5px 6px 7px 8px;
+}
+.columns {
+ column-count: 5;
+ column-fill: auto;
+ column-gap: 10px;
+ column-width: 100px;
+ width: 540px;
+ height: 100px;
+}
+.spacer {
+ height: 10px;
+ background: pink;
+}
+.anchor1 {
+ anchor-name: --a1;
+ margin-left: 10px;
+ width: 40px;
+ height: 90px;
+ background: blue;
+}
+.target {
+ position: absolute;
+}
+.target1 {
+ left: anchor(--a1 left);
+ top: anchor(--a1 top);
+ width: anchor-size(--a1 width);
+ height: anchor-size(--a1 height);
+ background: lime;
+ opacity: .3;
+}
+.target1-rb {
+ right: anchor(--a1 right);
+ bottom: anchor(--a1 bottom);
+ width: 10px;
+ height: 10px;
+ background: purple;
+}
+</style>
+<body onload="checkLayout('.target')">
+ <p>The green box should be a union of blue boxes,
+ and the purple box should be at the right-bottom of the green box.
+ </p>
+ <div class="spacer" style="height: 10px"></div>
+ <div class="columns">
+ <div class="spacer" style="height: 70px"></div>
+ <div class="cb">
+ <!-- This spacer fills up to the middle of the 2nd column. -->
+ <div class="spacer" style="height: 60px"></div>
+ <div class="anchor1"></div>
+ <div class="cb">
+ <div class="spacer" style="height: 120px"></div>
+ <div class="anchor1" style="width: 20px"></div>
+
+ <div class="target target1"
+ data-offset-x=18 data-offset-y=65
+ data-expected-width=130 data-expected-height=100></div>
+ <div class="target target1-rb"
+ data-offset-x=138 data-offset-y=155></div>
+ </div>
+
+ <div class="target target1"
+ data-offset-x=18 data-offset-y=25
+ data-expected-width=150 data-expected-height=100></div>
+ <div class="target target1-rb"
+ data-offset-x=158 data-offset-y=115></div>
+ </div>
+</body>
diff --git a/testing/web-platform/tests/css/css-anchor-position/anchor-position-multicol-005.html b/testing/web-platform/tests/css/css-anchor-position/anchor-position-multicol-005.html
new file mode 100644
index 0000000000..92f468ceda
--- /dev/null
+++ b/testing/web-platform/tests/css/css-anchor-position/anchor-position-multicol-005.html
@@ -0,0 +1,64 @@
+<!DOCTYPE html>
+<title>Overflow pushing anchors to later fragmentainers than querying element in multicol</title>
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/#propdef-anchor-name">
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/#anchor-pos">
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/#anchor-size">
+<link rel="author" href="mailto:kojii@chromium.org">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/check-layout-th.js"></script>
+<style>
+.relpos {
+ position: relative;
+}
+.abspos {
+ position: absolute;
+}
+.columns {
+ column-count: 2;
+ column-fill: auto;
+ column-gap: 10px;
+ column-width: 100px;
+ width: 210px;
+ height: 100px;
+}
+.spacer {
+ height: 10px;
+ background: pink;
+}
+.anchor1 {
+ anchor-name: --a1;
+ margin-left: 10px;
+ width: 40px;
+ height: 80px;
+ background: orange;
+}
+.target {
+ position: absolute;
+ background: lime;
+ opacity: 1;
+}
+.target1 {
+ left: anchor(--a1 left);
+ top: anchor(--a1 top);
+ width: anchor-size(--a1 width);
+ height: anchor-size(--a1 height);
+}
+</style>
+<body onload="checkLayout('.target')">
+ <div class="spacer" style="height: 10px"></div>
+ <div class="columns">
+ <div class="relpos">
+ <div style="height: 50px">
+ <div class="spacer" style="height: 110px"></div>
+ <div class="relpos" style="height: 50px">
+ <div class="anchor1 abspos"></div>
+ </div>
+ </div>
+ <div style="height: 50px">
+ <div class="target target1"
+ data-expected-width=40 data-expected-height=80></div>
+ </div>
+ </div>
+ </div>
+</body>
diff --git a/testing/web-platform/tests/css/css-anchor-position/anchor-position-multicol-006.html b/testing/web-platform/tests/css/css-anchor-position/anchor-position-multicol-006.html
new file mode 100644
index 0000000000..2b9f55c024
--- /dev/null
+++ b/testing/web-platform/tests/css/css-anchor-position/anchor-position-multicol-006.html
@@ -0,0 +1,71 @@
+<!DOCTYPE html>
+<title>Tests two OOF anchors in different containing blocks in multicol.</title>
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/#propdef-anchor-name">
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/#anchor-pos">
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/#anchor-size">
+<link rel="author" href="mailto:kojii@chromium.org">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/check-layout-th.js"></script>
+<style>
+.relpos {
+ position: relative;
+}
+.columns {
+ column-count: 3;
+ column-fill: auto;
+ column-gap: 10px;
+ column-width: 100px;
+ width: 320px;
+ height: 50px;
+}
+.anchor1 {
+ anchor-name: --a1;
+ position: absolute;
+ width: 10px;
+ height: 30px;
+ background: orange;
+}
+.anchor2 {
+ anchor-name: --a2;
+ position: absolute;
+ width: 30px;
+ height: 30px;
+ background: purple;
+}
+.target {
+ position: absolute;
+ width: 5px;
+ background: lime;
+}
+.target1 {
+ left: anchor(--a1 left);
+ top: anchor(--a1 top);
+ height: anchor-size(--a1 height);
+}
+.target2 {
+ left: anchor(--a2 left);
+ top: anchor(--a2 top);
+ height: anchor-size(--a2 height);
+}
+</style>
+<body onload="checkLayout('.target')">
+ <div class="spacer" style="height: 10px"></div>
+ <div class="relpos">
+ <div class="columns">
+ <div class="relpos">
+ <div class="spacer" style="height: 30px"></div>
+ <div class="anchor1"></div>
+ </div>
+ <div class="spacer" style="height: 70px"></div>
+ <div class="relpos">
+ <div class="spacer" style="height: 10px"></div>
+ <div class="anchor2"></div>
+ </div>
+ <div class="target target1" data-expected-height=50></div>
+ <div class="target target2" data-expected-height=30></div>
+ </div>
+ <div class="target target1" data-expected-height=50></div>
+ <div class="target target2" data-expected-height=30></div>
+ </div>
+</body>
diff --git a/testing/web-platform/tests/css/css-anchor-position/anchor-position-multicol-colspan-001.html b/testing/web-platform/tests/css/css-anchor-position/anchor-position-multicol-colspan-001.html
new file mode 100644
index 0000000000..705f872a79
--- /dev/null
+++ b/testing/web-platform/tests/css/css-anchor-position/anchor-position-multicol-colspan-001.html
@@ -0,0 +1,100 @@
+<!DOCTYPE html>
+<title>Anchors in column spanners in multicol</title>
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/#propdef-anchor-name">
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/#anchor-pos">
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/#anchor-size">
+<link rel="author" href="mailto:kojii@chromium.org">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/check-layout-th.js"></script>
+<style>
+.relpos {
+ position: relative;
+}
+.columns {
+ column-count: 2;
+ column-fill: auto;
+ column-gap: 10px;
+ column-width: 100px;
+ width: 210px;
+ height: 100px;
+}
+.colspan {
+ column-span: all;
+}
+.spacer {
+ height: 10px;
+ background: pink;
+}
+.anchor1 {
+ anchor-name: --a1;
+ margin-left: 10px;
+ width: 40px;
+ height: 20px;
+ background: orange;
+}
+.target {
+ position: absolute;
+ left: anchor(--a1 left);
+ top: anchor(--a1 top);
+ width: anchor-size(--a1 width);
+ height: anchor-size(--a1 height);
+ background: lime;
+ opacity: .3;
+}
+</style>
+<body onload="checkLayout('.target')">
+ <div class="relpos">
+ <div class="spacer" style="height: 10px"></div>
+ <div class="columns relpos">
+ <div class="spacer" style="height: 40px"></div>
+ <div class="relpos">
+ <div class="colspan">
+ <div class="relpos">
+ <!--
+ The containing block chain of this anchor is `relpos`, `colspan`,
+ and `columns`, skipping the 2nd `relpos`, because the containing
+ block of the spanner is the multicol container.
+ https://drafts.csswg.org/css-multicol/#column-span
+ -->
+ <div class="anchor1"></div>
+ <!--
+ The containing block of this target is inside a spanner.
+ -->
+ <div class="target"
+ data-offset-x=10 data-offset-y=0
+ data-expected-width=40 data-expected-height=20></div>
+ </div>
+ <!--
+ The containing block of this target is the multicol container.
+ -->
+ <div class="target"
+ data-offset-x=10 data-offset-y=20
+ data-expected-width=40 data-expected-height=20></div>
+ </div>
+ <!--
+ The containing block of this target is in the multicol,
+ but outside of the spanner.
+ This should not find the anchor, because the containing block of the
+ spanner is the multicol container.
+ -->
+ <div class="target"
+ data-offset-x=0 data-offset-y=0
+ data-expected-width=0 data-expected-height=0></div>
+ </div>
+ <div class="spacer" style="height: 80px"></div>
+ <!--
+ The containing block of this target is the multicol container.
+ -->
+ <div class="target"
+ data-offset-x=10 data-offset-y=20
+ data-expected-width=40 data-expected-height=20></div>
+ </div>
+ <!--
+ The containing block of this target is outside of the multicol.
+ -->
+ <div class="target"
+ data-offset-x=10 data-offset-y=30
+ data-expected-width=40 data-expected-height=20></div>
+ </div>
+</body>
diff --git a/testing/web-platform/tests/css/css-anchor-position/anchor-position-multicol-colspan-002.html b/testing/web-platform/tests/css/css-anchor-position/anchor-position-multicol-colspan-002.html
new file mode 100644
index 0000000000..b6e720da18
--- /dev/null
+++ b/testing/web-platform/tests/css/css-anchor-position/anchor-position-multicol-colspan-002.html
@@ -0,0 +1,76 @@
+<!DOCTYPE html>
+<title>Anchors in column-spanner in multicol</title>
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/#propdef-anchor-name">
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/#anchor-pos">
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/#anchor-size">
+<link rel="author" href="mailto:kojii@chromium.org">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/check-layout-th.js"></script>
+<style>
+.relpos {
+ position: relative;
+}
+.columns {
+ column-count: 2;
+ column-fill: auto;
+ column-gap: 10px;
+ column-width: 100px;
+ width: 210px;
+ height: 100px;
+}
+.colspan {
+ column-span: all;
+}
+.spacer {
+ height: 10px;
+ background: pink;
+}
+.anchor1 {
+ anchor-name: --a1;
+ margin-left: 10px;
+ width: 40px;
+ background: blue;
+}
+.anchor1 .spacer {
+ background: inherit;
+}
+.target {
+ position: absolute;
+ left: anchor(--a1 left);
+ top: anchor(--a1 top);
+ width: anchor-size(--a1 width);
+ height: anchor-size(--a1 height);
+ background: lime;
+ opacity: .3;
+}
+</style>
+<body onload="checkLayout('.target')">
+ <div class="relpos">
+ <div class="spacer" style="height: 10px"></div>
+ <div class="columns relpos">
+ <div class="spacer" style="height: 50px"></div>
+ <div class="relpos">
+ <div class="anchor1">
+ <div class="spacer" style="height: 10px"></div>
+ <div class="colspan" style="height: 20px"></div>
+ <div class="spacer" style="height: 30px"></div>
+ </div>
+ <!--
+ When anchors are split by the column spanners, OOFs laid out in a
+ multicol (i.e., the containing block is within a multicol) can't
+ compute the united bounding box, because the coordinate system in the
+ multicol can't express united rectangles across columns that are not
+ lined up.
+ <div class="target"></div>
+ -->
+ </div>
+ <div class="target"
+ data-offset-x=10 data-offset-y=20
+ data-expected-width=150 data-expected-height=60></div>
+ </div>
+ <div class="target"
+ data-offset-x=10 data-offset-y=30
+ data-expected-width=150 data-expected-height=60></div>
+ </div>
+</body>
diff --git a/testing/web-platform/tests/css/css-anchor-position/anchor-position-multicol-fixed-001.html b/testing/web-platform/tests/css/css-anchor-position/anchor-position-multicol-fixed-001.html
new file mode 100644
index 0000000000..4321c20def
--- /dev/null
+++ b/testing/web-platform/tests/css/css-anchor-position/anchor-position-multicol-fixed-001.html
@@ -0,0 +1,77 @@
+<!DOCTYPE html>
+<title>Anchors on fixed positioned objects in multicol</title>
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/#anchor-pos">
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/#anchor-size">
+<link rel="author" href="mailto:kojii@chromium.org">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/check-layout-th.js"></script>
+<style>
+.transform {
+ transform: translate(0);
+}
+.columns {
+ column-count: 2;
+ column-fill: auto;
+ column-gap: 10px;
+ column-width: 100px;
+ width: 210px;
+ height: 50px;
+}
+.colspan {
+ column-span: all;
+}
+.spacer {
+ height: 10px;
+ background: pink;
+}
+.anchor {
+ anchor-name: --a1;
+ background: orange;
+ margin-left: 10px;
+ width: 40px;
+ height: 10px;
+}
+.fixedpos {
+ position: fixed;
+ margin-left: 20px;
+ width: 20px;
+ height: 30px;
+}
+.target {
+ position: absolute;
+ background: lime;
+ opacity: .3;
+ left: anchor(--a1 left);
+ top: anchor(--a1 top);
+ width: anchor-size(--a1 width);
+ height: anchor-size(--a1 height);
+}
+</style>
+<body onload="checkLayout('.target')">
+ <div class="transform">
+ <div class="spacer" style="height: 10px"></div>
+ <div class="columns">
+ <div class="transform">
+ <div class="spacer" style="height: 20px"></div>
+ <div class="transform">
+ <div class="spacer" style="height: 20px"></div>
+ <div class="anchor fixedpos"></div>
+ <div class="anchor"></div>
+ <div class="target"
+ data-offset-x="10" data-offset-y="20"
+ data-expected-width=40 data-expected-height=10></div>
+ </div>
+ <div class="target"
+ data-offset-x="20" data-offset-y="0"
+ data-expected-width=130 data-expected-height=50></div>
+ </div>
+ <div class="target"
+ data-offset-x="20" data-offset-y="10"
+ data-expected-width=130 data-expected-height=50></div>
+ </div>
+ <div class="target"
+ data-offset-x="20" data-offset-y="10"
+ data-expected-width=130 data-expected-height=50></div>
+ </div>
+</body>
diff --git a/testing/web-platform/tests/css/css-anchor-position/anchor-position-multicol-nested-001.html b/testing/web-platform/tests/css/css-anchor-position/anchor-position-multicol-nested-001.html
new file mode 100644
index 0000000000..d83b8ddd95
--- /dev/null
+++ b/testing/web-platform/tests/css/css-anchor-position/anchor-position-multicol-nested-001.html
@@ -0,0 +1,79 @@
+<!DOCTYPE html>
+<title>Anchors in nested multicol</title>
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/#propdef-anchor-name">
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/#anchor-pos">
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/#anchor-size">
+<link rel="author" href="mailto:kojii@chromium.org">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/check-layout-th.js"></script>
+<style>
+.cb {
+ position: relative;
+ border-style: solid;
+ border-width: 3px 2px 4px 1px;
+ padding: 3px 2px 4px 1px;
+}
+.columns {
+ column-count: 4;
+ column-fill: auto;
+ column-gap: 10px;
+ column-width: 150px;
+ width: 630px;
+ height: 100px;
+}
+.columns .columns {
+ column-count: 2;
+ column-width: 60px;
+ width: 130px;
+ height: 200px;
+}
+.spacer {
+ background: pink;
+}
+.anchor1 {
+ anchor-name: --a1;
+ margin-left: 10px;
+ width: 20px;
+ height: 150px;
+ background: blue;
+}
+.target {
+ position: absolute;
+ left: anchor(--a1 left);
+ top: anchor(--a1 top);
+ width: anchor-size(--a1 width);
+ height: anchor-size(--a1 height);
+ background: lime;
+ opacity: .3;
+}
+</style>
+<body onload="checkLayout('.target')">
+ <p>The green box should be a union of blue boxes,
+ and the purple box should be at the right-bottom of the green box.
+ </p>
+ <div class="cb">
+ <div class="spacer" style="height: 10px"></div>
+ <div class="columns">
+ <div class="cb">
+ <div class="spacer" style="height: 110px"></div>
+ <div class="columns">
+ <div class="cb">
+ <div class="spacer" style="height: 60px"></div>
+ <div class="anchor1"></div>
+ <div class="spacer" style="height: 80px"></div>
+ <div class="target"
+ data-offset-x=11 data-offset-y=-19
+ data-expected-width=180 data-expected-height=100></div>
+ </div>
+ </div>
+ <div class="target"
+ data-offset-x=13 data-offset-y=97
+ data-expected-width=180 data-expected-height=100></div>
+ </div>
+ </div>
+ <div class="target"
+ data-offset-x=175 data-offset-y=13
+ data-expected-width=180 data-expected-height=100></div>
+ </div>
+</body>
diff --git a/testing/web-platform/tests/css/css-anchor-position/anchor-position-principal-box.html b/testing/web-platform/tests/css/css-anchor-position/anchor-position-principal-box.html
new file mode 100644
index 0000000000..9bb1fd4c4d
--- /dev/null
+++ b/testing/web-platform/tests/css/css-anchor-position/anchor-position-principal-box.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<title>anchor-name only applies to elements which generate a principal box</title>
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/#target-anchor-element">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<style>
+ body { margin-top: 0; }
+ #outer {
+ anchor-name: --anchor;
+ display: contents;
+ }
+ #inner {
+ anchor-name: --anchor;
+ }
+ #filler {
+ height: 100px;
+ }
+ #anchored {
+ position: absolute;
+ top: anchor(--anchor top);
+ }
+</style>
+<div id="outer">
+ <div id="filler"></div>
+ <div id="inner"></div>
+</div>
+<div id="anchored"></div>
+<script>
+ test(() => {
+ assert_equals(anchored.offsetTop, 100, "#anchored is positioned against #inner");
+ }, "anchor-name should only apply to elements which generate a principal box");
+</script>
diff --git a/testing/web-platform/tests/css/css-anchor-position/anchor-position-top-layer-001.html b/testing/web-platform/tests/css/css-anchor-position/anchor-position-top-layer-001.html
new file mode 100644
index 0000000000..c96f6eef55
--- /dev/null
+++ b/testing/web-platform/tests/css/css-anchor-position/anchor-position-top-layer-001.html
@@ -0,0 +1,50 @@
+<!DOCTYPE html>
+<title>Top-layer element can anchor to non-top-layer absolutely positioned element</title>
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/#target-anchor-element">
+<link rel="author" href="mailto:xiaochengh@chromium.org">
+<link rel="match" href="anchor-position-top-layer-ref.html">
+
+<style>
+#anchor {
+ position: absolute;
+ top: 300px;
+ left: 200px;
+ width: 100px;
+ height: 100px;
+ background: orange;
+ anchor-name: --a;
+}
+
+#target {
+ top: anchor(--a top);
+ left: anchor(--a right);
+ width: 100px;
+ height: 100px;
+ background: lime;
+ anchor-scroll: --a;
+}
+
+body {
+ margin: 0;
+ height: 300vh;
+}
+
+dialog {
+ margin: 0;
+ border: 0;
+ padding: 0;
+ inset: auto;
+}
+
+dialog::backdrop {
+ background: transparent;
+}
+</style>
+
+<div id="anchor"></div>
+<dialog id="target"></dialog>
+
+<script>
+target.showModal();
+document.scrollingElement.scrollTop = 100;
+</script>
diff --git a/testing/web-platform/tests/css/css-anchor-position/anchor-position-top-layer-002.html b/testing/web-platform/tests/css/css-anchor-position/anchor-position-top-layer-002.html
new file mode 100644
index 0000000000..e626e6b935
--- /dev/null
+++ b/testing/web-platform/tests/css/css-anchor-position/anchor-position-top-layer-002.html
@@ -0,0 +1,50 @@
+<!DOCTYPE html>
+<title>Top-layer element can anchor to non-top-layer fixed positioned element</title>
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/#target-anchor-element">
+<link rel="author" href="mailto:xiaochengh@chromium.org">
+<link rel="match" href="anchor-position-top-layer-ref.html">
+
+<style>
+#anchor {
+ position: fixed;
+ top: 200px;
+ left: 200px;
+ width: 100px;
+ height: 100px;
+ background: orange;
+ anchor-name: --a;
+}
+
+#target {
+ top: anchor(--a top);
+ left: anchor(--a right);
+ width: 100px;
+ height: 100px;
+ background: lime;
+ anchor-scroll: --a;
+}
+
+body {
+ margin: 0;
+ height: 300vh;
+}
+
+dialog {
+ margin: 0;
+ border: 0;
+ padding: 0;
+ inset: auto;
+}
+
+dialog::backdrop {
+ background: transparent;
+}
+</style>
+
+<div id="anchor"></div>
+<dialog id="target"></dialog>
+
+<script>
+target.showModal();
+document.scrollingElement.scrollTop = 100;
+</script>
diff --git a/testing/web-platform/tests/css/css-anchor-position/anchor-position-top-layer-003.html b/testing/web-platform/tests/css/css-anchor-position/anchor-position-top-layer-003.html
new file mode 100644
index 0000000000..39f3c362c7
--- /dev/null
+++ b/testing/web-platform/tests/css/css-anchor-position/anchor-position-top-layer-003.html
@@ -0,0 +1,51 @@
+<!DOCTYPE html>
+<title>Top-layer element can anchor to preceeding top-layer absolutely positioned element</title>
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/#target-anchor-element">
+<link rel="author" href="mailto:xiaochengh@chromium.org">
+<link rel="match" href="anchor-position-top-layer-ref.html">
+
+<style>
+#anchor {
+ position: absolute;
+ top: 300px;
+ left: 200px;
+ width: 100px;
+ height: 100px;
+ background: orange;
+ anchor-name: --a;
+}
+
+#target {
+ top: anchor(--a top);
+ left: anchor(--a right);
+ width: 100px;
+ height: 100px;
+ background: lime;
+ anchor-scroll: --a;
+}
+
+body {
+ margin: 0;
+ height: 300vh;
+}
+
+dialog {
+ margin: 0;
+ border: 0;
+ padding: 0;
+ inset: auto;
+}
+
+dialog::backdrop {
+ background: transparent;
+}
+</style>
+
+<dialog id="anchor"></dialog>
+<dialog id="target"></dialog>
+
+<script>
+anchor.showModal();
+target.showModal();
+document.scrollingElement.scrollTop = 100;
+</script>
diff --git a/testing/web-platform/tests/css/css-anchor-position/anchor-position-top-layer-004.html b/testing/web-platform/tests/css/css-anchor-position/anchor-position-top-layer-004.html
new file mode 100644
index 0000000000..8e189e0e7b
--- /dev/null
+++ b/testing/web-platform/tests/css/css-anchor-position/anchor-position-top-layer-004.html
@@ -0,0 +1,51 @@
+<!DOCTYPE html>
+<title>Top-layer element can anchor to preceeding top-layer fixed positioned element</title>
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/#target-anchor-element">
+<link rel="author" href="mailto:xiaochengh@chromium.org">
+<link rel="match" href="anchor-position-top-layer-ref.html">
+
+<style>
+#anchor {
+ position: fixed;
+ top: 200px;
+ left: 200px;
+ width: 100px;
+ height: 100px;
+ background: orange;
+ anchor-name: --a;
+}
+
+#target {
+ top: anchor(--a top);
+ left: anchor(--a right);
+ width: 100px;
+ height: 100px;
+ background: lime;
+ anchor-scroll: --a;
+}
+
+body {
+ margin: 0;
+ height: 300vh;
+}
+
+dialog {
+ margin: 0;
+ border: 0;
+ padding: 0;
+ inset: auto;
+}
+
+dialog::backdrop {
+ background: transparent;
+}
+</style>
+
+<dialog id="anchor"></dialog>
+<dialog id="target"></dialog>
+
+<script>
+anchor.showModal();
+target.showModal();
+document.scrollingElement.scrollTop = 100;
+</script>
diff --git a/testing/web-platform/tests/css/css-anchor-position/anchor-position-top-layer-005.html b/testing/web-platform/tests/css/css-anchor-position/anchor-position-top-layer-005.html
new file mode 100644
index 0000000000..d9e4fa86e1
--- /dev/null
+++ b/testing/web-platform/tests/css/css-anchor-position/anchor-position-top-layer-005.html
@@ -0,0 +1,51 @@
+<!DOCTYPE html>
+<title>Non-top-layer element cannot anchor to top-layer element</title>
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/#target-anchor-element">
+<link rel="author" href="mailto:xiaochengh@chromium.org">
+<link rel="match" href="anchor-position-top-layer-ref.html">
+
+<style>
+#anchor {
+ position: absolute;
+ top: 300px;
+ left: 200px;
+ width: 100px;
+ height: 100px;
+ background: orange;
+ anchor-name: --a;
+}
+
+#target {
+ position: fixed;
+ top: anchor(--a bottom, 200px);
+ left: anchor(--a left, 300px);
+ width: 100px;
+ height: 100px;
+ background: lime;
+ anchor-scroll: --a;
+}
+
+body {
+ margin: 0;
+ height: 300vh;
+}
+
+dialog {
+ margin: 0;
+ border: 0;
+ padding: 0;
+ inset: auto;
+}
+
+dialog::backdrop {
+ background: transparent;
+}
+</style>
+
+<dialog id="anchor"></dialog>
+<div id="target"></div>
+
+<script>
+anchor.showModal();
+document.scrollingElement.scrollTop = 100;
+</script>
diff --git a/testing/web-platform/tests/css/css-anchor-position/anchor-position-top-layer-006.html b/testing/web-platform/tests/css/css-anchor-position/anchor-position-top-layer-006.html
new file mode 100644
index 0000000000..5f5cd67a1d
--- /dev/null
+++ b/testing/web-platform/tests/css/css-anchor-position/anchor-position-top-layer-006.html
@@ -0,0 +1,51 @@
+<!DOCTYPE html>
+<title>Top-layer element cannot anchor to succeeding top-layer element</title>
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/#target-anchor-element">
+<link rel="author" href="mailto:xiaochengh@chromium.org">
+<link rel="match" href="anchor-position-top-layer-ref.html">
+
+<style>
+#anchor {
+ position: absolute;
+ top: 300px;
+ left: 200px;
+ width: 100px;
+ height: 100px;
+ background: orange;
+ anchor-name: --a;
+}
+
+#target {
+ position: fixed;
+ top: anchor(--a bottom, 200px);
+ left: anchor(--a left, 300px);
+ width: 100px;
+ height: 100px;
+ background: lime;
+ anchor-scroll: --a;
+}
+
+body {
+ margin: 0;
+ height: 300vh;
+}
+
+dialog {
+ margin: 0;
+ border: 0;
+ padding: 0;
+}
+
+dialog::backdrop {
+ background: transparent;
+}
+</style>
+
+<dialog id="anchor"></dialog>
+<dialog id="target"></dialog>
+
+<script>
+target.showModal();
+anchor.showModal();
+document.scrollingElement.scrollTop = 100;
+</script>
diff --git a/testing/web-platform/tests/css/css-anchor-position/anchor-position-top-layer-ref.html b/testing/web-platform/tests/css/css-anchor-position/anchor-position-top-layer-ref.html
new file mode 100644
index 0000000000..dc7f77f2b3
--- /dev/null
+++ b/testing/web-platform/tests/css/css-anchor-position/anchor-position-top-layer-ref.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<title>Tests anchor positioning with top-layer elements</title>
+
+<style>
+body {
+ margin: 0;
+ height: 300vh;
+}
+
+#anchor {
+ position: fixed;
+ top: 200px;
+ left: 200px;
+ width: 100px;
+ height: 100px;
+ background: orange;
+}
+
+#target {
+ position: fixed;
+ top: 200px;
+ left: 300px;
+ width: 100px;
+ height: 100px;
+ background: lime;
+}
+</style>
+
+<div id="anchor"></div>
+<div id="target"></div>
+
+<script>
+document.scrollingElement.scrollTop = 100;
+</script>
diff --git a/testing/web-platform/tests/css/css-anchor-position/anchor-position-writing-modes-001.html b/testing/web-platform/tests/css/css-anchor-position/anchor-position-writing-modes-001.html
new file mode 100644
index 0000000000..c75a7c1e39
--- /dev/null
+++ b/testing/web-platform/tests/css/css-anchor-position/anchor-position-writing-modes-001.html
@@ -0,0 +1,101 @@
+<!DOCTYPE html>
+<title>Tests `anchor` function for `writing-mode`/`direction`s</title>
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/#propdef-anchor-name">
+<link rel="author" href="mailto:kojii@chromium.org">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script><style>
+:root, body {
+ margin: 0;
+}
+#container {
+ position: relative;
+ width: 600px;
+ height: 400px;
+}
+#a1 {
+ anchor-name: --a1;
+ background: orange;
+ margin-left: 100px;
+ margin-top: 100px;
+ width: 100px;
+ height: 100px;
+}
+.htb-rtl #a1 { margin-right: 400px; }
+.vlr-rtl #a1 { margin-bottom: 200px; }
+.vrl-ltr #a1 { margin-right: 400px; }
+.vrl-rtl #a1 { margin-right: 400px; margin-bottom: 200px; }
+#a2 {
+ anchor-name: --a2;
+ background: purple;
+ margin-left: 500px;
+ margin-top: 100px;
+ width: 100px;
+ height: 100px;
+}
+.vlr-ltr #a2 { margin-left: 300px; margin-top: 300px; }
+.vlr-rtl #a2 { margin-left: 300px; margin-top: 300px; }
+.vrl-ltr #a2 { margin-right: -600px; margin-top: 300px; }
+.vrl-rtl #a2 { margin-right: -600px; margin-top: 300px; }
+#target {
+ background: green;
+ position: absolute;
+ left: anchor(--a1 right);
+ top: anchor(--a1 bottom);
+ right: anchor(--a2 left);
+ bottom: anchor(--a2 top);
+}
+.htb-ltr { writing-mode: horizontal-tb; direction: ltr; }
+.htb-rtl { writing-mode: horizontal-tb; direction: rtl; }
+.vlr-ltr { writing-mode: vertical-lr; direction: ltr; }
+.vlr-rtl { writing-mode: vertical-lr; direction: rtl; }
+.vrl-ltr { writing-mode: vertical-rl; direction: ltr; }
+.vrl-rtl { writing-mode: vertical-rl; direction: rtl; }
+</style>
+<body>
+ <div id="container">
+ <div id="a1"></div>
+ <div id="a2"></div>
+ <div id="target"></div>
+ </div>
+<script>
+const classes = [
+ 'htb-ltr', 'htb-rtl',
+ 'vlr-ltr', 'vlr-rtl',
+ 'vrl-ltr', 'vrl-rtl'];
+const combinations = [];
+for (const container_class of classes) {
+ for (const a1_class of classes) {
+ for (const a2_class of classes) {
+ for (const target_class of classes) {
+ combinations.push([container_class, a1_class, a2_class, target_class]);
+ }
+ }
+ }
+}
+
+for (let i = 0; i < combinations.length; ++i)
+ run_test_index(i);
+
+function run_test_index(i) {
+ const combination = combinations[i];
+ run_test(i, ...combination);
+}
+
+function run_test(i, container_class, a1_class, a2_class, target_class) {
+ container.classList.add(container_class);
+ a1.classList.add(a1_class);
+ a2.classList.add(a2_class);
+ target.classList.add(target_class);
+ test(() => {
+ const bounds = target.getBoundingClientRect();
+ assert_array_equals(
+ [bounds.left, bounds.top, bounds.right, bounds.bottom],
+ [200, 200, 500, 300]);
+ }, `${i}: ${container_class}/${a1_class}/${a2_class}/${target_class}`);
+ container.classList.remove(container_class);
+ a1.classList.remove(a1_class);
+ a2.classList.remove(a2_class);
+ target.classList.remove(target_class);
+}
+</script>
+</body>
diff --git a/testing/web-platform/tests/css/css-anchor-position/anchor-position-writing-modes-002.html b/testing/web-platform/tests/css/css-anchor-position/anchor-position-writing-modes-002.html
new file mode 100644
index 0000000000..834835ef21
--- /dev/null
+++ b/testing/web-platform/tests/css/css-anchor-position/anchor-position-writing-modes-002.html
@@ -0,0 +1,103 @@
+<!DOCTYPE html>
+<title>Tests logical `anchor` function for `writing-mode`/`direction`s</title>
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/#anchor-pos">
+<link rel="author" href="mailto:kojii@chromium.org">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<style>
+.htb-ltr { writing-mode: horizontal-tb; direction: ltr; }
+.htb-rtl { writing-mode: horizontal-tb; direction: rtl; }
+.vlr-ltr { writing-mode: vertical-lr; direction: ltr; }
+.vlr-rtl { writing-mode: vertical-lr; direction: rtl; }
+.vrl-ltr { writing-mode: vertical-rl; direction: ltr; }
+.vrl-rtl { writing-mode: vertical-rl; direction: rtl; }
+.relpos {
+ position: relative;
+ outline: blue 1px solid;
+}
+.spacer {
+ width: 10px;
+ height: 10px;
+ background: yellow;
+}
+.anchor {
+ anchor-name: --a1;
+ margin: 5px;
+ width: 30px;
+ height: 30px;
+ background: orange;
+}
+.target {
+ position: absolute;
+ outline: 5px solid lime;
+}
+</style>
+<body>
+ <template id="template">
+ <div class="relpos">
+ <div class="spacer"></div>
+ <div class="anchor"></div>
+ </div>
+ </template>
+<script>
+// Generate tests for all combinations.
+// The first two entries are the side `start` and `end` should match in x-axis.
+// The next two entries are the side `start` and `end` should match in y-axis.
+const writingDirs = {
+ 'htb-ltr':['l', 'r', 't', 'b'],
+ 'htb-rtl':['r', 'l', 't', 'b'],
+ 'vrl-ltr':['r', 'l', 't', 'b'],
+ 'vrl-rtl':['r', 'l', 'b', 't'],
+ 'vlr-ltr':['l', 'r', 't', 'b'],
+ 'vlr-rtl':['l', 'r', 'b', 't'],
+};
+const container = document.body;
+const cb_template = template.content.firstElementChild;
+for (const [writingDir, matches] of Object.entries(writingDirs)) {
+ const cb = cb_template.cloneNode(true);
+ cb.classList.add(writingDir);
+ createTarget(null, 'left: anchor(--a1 start)', matches[0], cb);
+ createTarget(null, 'left: anchor(--a1 end)', matches[1], cb);
+ createTarget(null, 'top: anchor(--a1 start)', matches[2], cb);
+ createTarget(null, 'top: anchor(--a1 end)', matches[3], cb);
+ createTarget(writingDir, 'left: anchor(--a1 self-start)', matches[0], cb);
+ createTarget(writingDir, 'left: anchor(--a1 self-end)', matches[1], cb);
+ createTarget(writingDir, 'top: anchor(--a1 self-start)', matches[2], cb);
+ createTarget(writingDir, 'top: anchor(--a1 self-end)', matches[3], cb);
+ container.appendChild(cb);
+}
+
+function createTarget(className, style, match, cb) {
+ const target = document.createElement('div');
+ target.classList.add('target');
+ if (className)
+ target.classList.add(className);
+ target.style = style;
+ target.dataset.name = style;
+ target.dataset.match = match;
+ cb.appendChild(target);
+}
+
+// Test all `.target`s.
+for (const target of document.querySelectorAll('.target')) {
+ const cb = target.parentElement;
+ const anchor = cb.querySelector('.anchor');
+ test(() => {
+ switch (target.dataset.match) {
+ case 'l':
+ assert_equals(anchor.offsetLeft, target.offsetLeft);
+ break;
+ case 'r':
+ assert_equals(anchor.offsetLeft + anchor.offsetWidth, target.offsetLeft);
+ break;
+ case 't':
+ assert_equals(anchor.offsetTop, target.offsetTop);
+ break;
+ case 'b':
+ assert_equals(anchor.offsetTop + anchor.offsetHeight, target.offsetTop);
+ break;
+ }
+ }, `${cb.classList}/${target.classList}/${target.dataset.name}`);
+}
+</script>
+</body>
diff --git a/testing/web-platform/tests/css/css-anchor-position/anchor-query-custom-property-registration.html b/testing/web-platform/tests/css/css-anchor-position/anchor-query-custom-property-registration.html
new file mode 100644
index 0000000000..af211a0ee5
--- /dev/null
+++ b/testing/web-platform/tests/css/css-anchor-position/anchor-query-custom-property-registration.html
@@ -0,0 +1,50 @@
+<!DOCTYPE html>
+<title>Tests using anchor queries in custom property initial value</title>
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/">
+<link rel="help" href="https://drafts.css-houdini.org/css-properties-values-api/#register-a-custom-property">
+<link rel="author" href="mailto:xiaochengh@chromium.org">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<script>
+setup(() => assert_own_property(CSS, 'registerProperty'));
+
+// Anchor queries are not computationally independent, so they cannot be used
+// in the initial value of any typed custom property.
+
+test(() => assert_throws_dom(
+ 'SyntaxError',
+ () => CSS.registerProperty({
+ name: '--x',
+ syntax: '<length>',
+ inherits: false,
+ initialValue: 'anchor(--foo top)',
+ })), 'anchor() cannot be used as <length> initial value');
+
+test(() => assert_throws_dom(
+ 'SyntaxError',
+ () => CSS.registerProperty({
+ name: '--x',
+ syntax: '<length>',
+ inherits: false,
+ initialValue: 'anchor-size(--foo width)',
+ })), 'anchor-size() cannot be used as <length> initial value');
+
+test(() => assert_throws_dom(
+ 'SyntaxError',
+ () => CSS.registerProperty({
+ name: '--x',
+ syntax: '<length-percentage>',
+ inherits: false,
+ initialValue: 'anchor(--foo top)',
+ })), 'anchor() cannot be used as <length-percentage> initial value');
+
+test(() => assert_throws_dom(
+ 'SyntaxError',
+ () => CSS.registerProperty({
+ name: '--x',
+ syntax: '<length-percentage>',
+ inherits: false,
+ initialValue: 'anchor-size(--foo width)',
+ })), 'anchor-size() cannot be used as <length-percentage> initial value');
+</script>
diff --git a/testing/web-platform/tests/css/css-anchor-position/anchor-query-fallback.html b/testing/web-platform/tests/css/css-anchor-position/anchor-query-fallback.html
new file mode 100644
index 0000000000..8d413fd862
--- /dev/null
+++ b/testing/web-platform/tests/css/css-anchor-position/anchor-query-fallback.html
@@ -0,0 +1,67 @@
+<!DOCTYPE html>
+<title>Tests the fallback value in anchor queries</title>
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/#anchor-pos">
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/#anchor-size">
+<link rel="author" href="mailto:xiaochengh@chromium.org">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/check-layout-th.js"></script>
+<style>
+#container {
+ position: relative;
+ display: flex;
+ flex-wrap: wrap;
+ width: 300px;
+}
+
+.flex-item {
+ width: 100px;
+ height: 50px;
+ flex: auto;
+}
+
+#a1 {
+ anchor-name: --a1;
+ background: orange;
+}
+#a2 {
+ anchor-name: --a2;
+ background: purple;
+}
+
+.target {
+ position: absolute;
+}
+</style>
+
+<body id="container" onload="checkLayout('.target')">
+ <div class="flex-item" id="a1"></div>
+ <div class="flex-item"></div>
+ <div class="flex-item"></div>
+ <div class="flex-item"></div>
+ <div class="flex-item"></div>
+ <div class="flex-item"></div>
+ <div class="flex-item"></div>
+ <div class="flex-item"></div>
+ <div class="flex-item" id="a2"></div>
+
+ <!-- Fallback due to no valid anchor -->
+ <div class="target" style="left: anchor(--inexist-anchor left, 50px)" data-offset-x="50"></div>
+ <div class="target" style="width: anchor-size(--inexist-anchor width, 50px)" data-expected-width="50"></div>
+
+ <!-- Fallback due to wrong axis for anchor() -->
+ <div class="target" style="left: anchor(--a1 top, 50px)" data-offset-x="50"></div>
+ <div class="target" style="left: anchor(--a1 bottom, 50px)" data-offset-x="50"></div>
+ <div class="target" style="top: anchor(--a1 left, 50px)" data-offset-y="50"></div>
+ <div class="target" style="top: anchor(--a1 right, 50px)" data-offset-y="50"></div>
+
+ <!-- More complicated fallback values -->
+ <div class="target" style="left: anchor(--inexist-anchor left, 50%)" data-offset-x="150"></div>
+ <div class="target" style="left: anchor(--inexist-anchor left, calc(20% + 20px))" data-offset-x="80"></div>
+ <div class="target" style="top: anchor(--a1 left, anchor(--a2 top))" data-offset-y="100"></div>
+ <div class="target" style="top: anchor(--a1 left, calc((anchor(--a1 bottom) + anchor(--a2 top)) / 2)" data-offset-y="75"></div>
+ <div class="target" style="width: anchor-size(--inexist-anchor width, 50%)" data-expected-width="150"></div>
+ <div class="target" style="width: anchor-size(--inexist-anchor width, calc(20% + 20px))" data-expected-width="80"></div>
+ <div class="target" style="height: anchor-size(--inexist-anchor height, anchor-size(--a1 width))" data-expected-height="100"></div>
+ <div class="target" style="height: anchor-size(--inexist-anchor height, calc((anchor-size(--a1 width) + anchor-size(--a2 height)) / 2)" data-expected-height="75"></div>
+</body>
diff --git a/testing/web-platform/tests/css/css-anchor-position/anchor-scroll-basics.tentative.html b/testing/web-platform/tests/css/css-anchor-position/anchor-scroll-basics.tentative.html
new file mode 100644
index 0000000000..fa42e33d92
--- /dev/null
+++ b/testing/web-platform/tests/css/css-anchor-position/anchor-scroll-basics.tentative.html
@@ -0,0 +1,71 @@
+<!DOCTYPE html>
+<title>Basic of anchor-scroll: anchored elements should be "pinned" to the anchor when anchor is scrolled</title>
+<link rel="author" href="mailto:xiaochengh@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/">
+<link rel="match" href="reference/anchor-scroll-ref.html">
+<link rel="stylesheet" href="/fonts/ahem.css">
+<style>
+body {
+ font: 20px/1 Ahem;
+ margin: 0;
+}
+
+#scroll-container {
+ width: 400px;
+ height: 400px;
+ overflow: scroll;
+}
+
+#scroll-contents {
+ width: 1000px;
+ height: 1000px;
+ position: relative;
+}
+
+#placefiller-above-anchor {
+ height: 500px;
+}
+
+#placefiller-before-anchor {
+ display: inline-block;
+ width: 500px;
+}
+
+#anchor {
+ anchor-name: --anchor;
+}
+
+#inner-anchored {
+ color: green;
+ position: absolute;
+ left: anchor(--anchor left);
+ bottom: anchor(--anchor top);
+ anchor-scroll: --anchor;
+}
+
+#outer-anchored {
+ color: yellow;
+ position: absolute;
+ left: anchor(--anchor left);
+ top: anchor(--anchor bottom);
+ anchor-scroll: --anchor;
+}
+</style>
+
+<div style="position: relative">
+ <div id="scroll-container">
+ <div id="scroll-contents">
+ <div id="placefiller-above-anchor"></div>
+ <div id="placefiller-before-anchor"></div>
+ <span id="anchor">anchor</span>
+ <div id="inner-anchored">inner-anchored</div>
+ </div>
+ </div>
+ <div id="outer-anchored">outer-anchored</div>
+</div>
+
+<script>
+const scroller = document.getElementById('scroll-container');
+scroller.scrollTop = 300;
+scroller.scrollLeft = 450;
+</script>
diff --git a/testing/web-platform/tests/css/css-anchor-position/anchor-scroll-fallback-position-001.html b/testing/web-platform/tests/css/css-anchor-position/anchor-scroll-fallback-position-001.html
new file mode 100644
index 0000000000..a9a5d8c0ff
--- /dev/null
+++ b/testing/web-platform/tests/css/css-anchor-position/anchor-scroll-fallback-position-001.html
@@ -0,0 +1,101 @@
+<!DOCTYPE html>
+<title>Tests that position fallback responds to scrolling</title>
+<link rel="author" href="mailto:xiaochengh@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/#scroll">
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/#fallback-apply">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/test-common.js"></script>
+<style>
+#cb {
+ width: 400px;
+ height: 400px;
+ margin: 100px;
+ transform: scale(1);
+ outline: 1px solid black;
+}
+
+#scroller {
+ width: 400px;
+ height: 400px;
+ overflow: scroll;
+}
+
+#anchor {
+ width: 100px;
+ height: 100px;
+ margin-left: 150px;
+ margin-right: 275px;
+ margin-top: 300px;
+ margin-bottom: 300px;
+ background: orange;
+ anchor-name: --a;
+}
+
+#anchored {
+ position: absolute;
+ background: green;
+ anchor-scroll: --a;
+ position-fallback: --fallback;
+}
+
+@position-fallback --fallback {
+ /* Above the anchor */
+ @try {
+ width: 100px; height: 100px;
+ left: anchor(--a left);
+ bottom: anchor(--a top);
+ }
+ /* Left of the anchor */
+ @try {
+ width: 100px; height: 100px;
+ right: anchor(--a left);
+ top: anchor(--a top);
+ }
+ /* Right of the anchor */
+ @try {
+ width: 100px; height: 100px;
+ left: anchor(--a right);
+ top: anchor(--a top);
+ }
+}
+</style>
+
+<div id="cb">
+ <div id="scroller">
+ <div id="anchor"></div>
+ </div>
+ <div id="anchored"></div>
+</div>
+
+<script>
+promise_test(async () => {
+ await waitUntilNextAnimationFrame();
+ assert_fallback_position(anchored, anchor, 'top');
+}, 'Should be above the anchor when at initial scroll position');
+
+promise_test(async () => {
+ scroller.scrollTop = 200;
+ await waitUntilNextAnimationFrame();
+ assert_fallback_position(anchored, anchor, 'top');
+}, 'Scroll down until the top edge of #anchor touches container but not overflowing');
+
+promise_test(async () => {
+ scroller.scrollTop = 201;
+ await waitUntilNextAnimationFrame();
+ assert_fallback_position(anchored, anchor, 'left');
+}, 'Scroll further down, making the first fallback position overflow by 1px');
+
+promise_test(async () => {
+ scroller.scrollTop = 200;
+ await waitUntilNextAnimationFrame();
+ assert_fallback_position(anchored, anchor, 'top');
+}, 'Scroll back up to reuse the first fallback position');
+
+promise_test(async () => {
+ scroller.scrollTop = 249;
+ scroller.scrollLeft = 51;
+ await waitUntilNextAnimationFrame();
+ assert_fallback_position(anchored, anchor, 'right');
+}, 'Scroll bottom-right to make the first three fallback positions overflow');
+</script>
diff --git a/testing/web-platform/tests/css/css-anchor-position/anchor-scroll-fallback-position-002.html b/testing/web-platform/tests/css/css-anchor-position/anchor-scroll-fallback-position-002.html
new file mode 100644
index 0000000000..e51f675fff
--- /dev/null
+++ b/testing/web-platform/tests/css/css-anchor-position/anchor-scroll-fallback-position-002.html
@@ -0,0 +1,62 @@
+<!DOCTYPE html>
+<html dir="rtl">
+<title>Tests position fallback with rtl scroller</title>
+<link rel="author" href="mailto:xiaochengh@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/#scroll">
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/#fallback-apply">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/test-common.js"></script>
+
+<style>
+body {
+ margin: 0;
+}
+
+#anchor {
+ anchor-name: --a;
+ width: 100px;
+ height: 100px;
+ margin-right: 200px;
+ background: orange;
+}
+
+#spacer {
+ width: 1000vw;
+ height: 1px;
+}
+
+#anchored {
+ position: fixed;
+ width: 100px;
+ height: 100px;
+ background: green;
+ anchor-scroll: --a;
+ top: anchor(--a top);
+ position-fallback: --pf;
+}
+
+@position-fallback --pf {
+ @try { left: anchor(--a right); }
+ @try { right: anchor(--a left); }
+}
+</style>
+
+<div id="anchor"></div>
+<div id="spacer"></div>
+<div id="anchored"></div>
+
+<script>
+promise_test(async () => {
+ await waitUntilNextAnimationFrame();
+ assert_fallback_position(anchored, anchor, 'right');
+}, 'Should use the first fallback position at the initial scroll offset');
+
+promise_test(async () => {
+ document.documentElement.scrollLeft = -101;
+ await waitUntilNextAnimationFrame();
+ assert_fallback_position(anchored, anchor, 'left');
+}, 'Should use the second fallback position after scrolling left');
+</script>
+
+</html>
diff --git a/testing/web-platform/tests/css/css-anchor-position/anchor-scroll-fallback-position-003.html b/testing/web-platform/tests/css/css-anchor-position/anchor-scroll-fallback-position-003.html
new file mode 100644
index 0000000000..ae212f9190
--- /dev/null
+++ b/testing/web-platform/tests/css/css-anchor-position/anchor-scroll-fallback-position-003.html
@@ -0,0 +1,73 @@
+<!DOCTYPE html>
+<title>Tests position fallback with bottom-up scroller</title>
+<link rel="author" href="mailto:xiaochengh@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/#scroll">
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/#fallback-apply">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/test-common.js"></script>
+
+<style>
+#containing-block {
+ width: 400px;
+ height: 400px;
+ transform: scale(1);
+ border: 1px solid black;
+}
+
+#scroller {
+ display: flex;
+ flex-direction: column-reverse;
+ width: 400px;
+ height: 400px;
+ overflow-y: scroll;
+}
+
+.box {
+ min-height: 100px;
+ width: 100px;
+}
+
+#anchor {
+ anchor-name: --a;
+ background: orange;
+}
+
+#anchored {
+ position: absolute;
+ width: 100px;
+ height: 100px;
+ background: green;
+ anchor-scroll: --a;
+ position-fallback: --pf;
+}
+
+@position-fallback --pf {
+ @try { top: anchor(--a bottom); }
+ @try { bottom: anchor(--a top); }
+}
+</style>
+
+<div id="containing-block">
+ <div id="scroller">
+ <div class="box"></div>
+ <div class="box" id="anchor"></div>
+ <div class="box"></div>
+ <div class="box"></div>
+ <div class="box"></div>
+ </div>
+ <div id="anchored"></div>
+</div>
+
+<script>
+promise_test(async () => {
+ await waitUntilNextAnimationFrame();
+ assert_fallback_position(anchored, anchor, 'bottom');
+}, 'Should use the first fallback position at the initial scroll offset');
+
+promise_test(async () => {
+ scroller.scrollTop = -1;
+ await waitUntilNextAnimationFrame();
+ assert_fallback_position(anchored, anchor, 'top');
+}, 'Should use the second fallback position after scrolling up');
+</script>
diff --git a/testing/web-platform/tests/css/css-anchor-position/anchor-scroll-fallback-position-004.html b/testing/web-platform/tests/css/css-anchor-position/anchor-scroll-fallback-position-004.html
new file mode 100644
index 0000000000..0227fa753e
--- /dev/null
+++ b/testing/web-platform/tests/css/css-anchor-position/anchor-scroll-fallback-position-004.html
@@ -0,0 +1,75 @@
+<!DOCTYPE html>
+<title>Tests position fallback with scrollers with mixed writing modes</title>
+<link rel="author" href="mailto:xiaochengh@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/#scroll">
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/#fallback-apply">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/test-common.js"></script>
+
+<style>
+body {
+ margin: 0;
+}
+
+#vrl-scroller {
+ writing-mode: vertical-rl;
+ overflow-x: scroll;
+ width: calc(100vw - 90px);
+ height: 400px;
+ outline: 1px solid black;
+}
+
+#anchor {
+ anchor-name: --a;
+ width: 100px;
+ height: 100px;
+ margin-left: 1000px;
+ background: orange;
+}
+
+#anchored {
+ position: fixed;
+ width: 100px;
+ height: 100px;
+ background: green;
+ anchor-scroll: --a;
+ position-fallback: --pf;
+}
+
+@position-fallback --pf {
+ /* Top of the anchor */
+ @try { bottom: anchor(--a top); left: anchor(--a left); }
+ /* Bottom of the anchor */
+ @try { top: anchor(--a bottom); left: anchor(--a left); }
+ /* Left of the anchor */
+ @try { top: anchor(--a top); right: anchor(--a left); }
+}
+</style>
+
+<div style="height: 200px"></div>
+<div id="vrl-scroller">
+ <div id="anchor"></div>
+</div>
+<div style="height: 1000px"></div>
+<div id="anchored"></div>
+
+<script>
+promise_test(async () => {
+ await waitUntilNextAnimationFrame();
+ assert_fallback_position(anchored, anchor, 'top');
+}, 'Should use the first fallback position at the initial scroll offsets');
+
+promise_test(async () => {
+ document.documentElement.scrollTop = 101;
+ await waitUntilNextAnimationFrame();
+ assert_fallback_position(anchored, anchor, 'bottom');
+}, 'Should use the second fallback position after scrolling viewport down');
+
+promise_test(async () => {
+ let vrlScroller = document.getElementById('vrl-scroller');
+ vrlScroller.scrollLeft = -100;
+ await waitUntilNextAnimationFrame();
+ assert_fallback_position(anchored, anchor, 'left');
+}, 'Should use the third fallback position after scrolling the vrl scroller left');
+</script>
diff --git a/testing/web-platform/tests/css/css-anchor-position/anchor-scroll-fallback-position-005.html b/testing/web-platform/tests/css/css-anchor-position/anchor-scroll-fallback-position-005.html
new file mode 100644
index 0000000000..3dedd4d7e6
--- /dev/null
+++ b/testing/web-platform/tests/css/css-anchor-position/anchor-scroll-fallback-position-005.html
@@ -0,0 +1,63 @@
+<!DOCTYPE html>
+<html dir="rtl">
+<title>Tests position fallback with rtl scroller and vertical-rl OOF</title>
+<link rel="author" href="mailto:xiaochengh@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/#scroll">
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/#fallback-apply">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/test-common.js"></script>
+
+<style>
+body {
+ margin: 0;
+}
+
+#anchor {
+ anchor-name: --a;
+ width: 100px;
+ height: 100px;
+ margin-right: 200px;
+ background: orange;
+}
+
+#spacer {
+ width: 1000vw;
+ height: 1px;
+}
+
+#anchored {
+ writing-mode: vertical-rl;
+ position: fixed;
+ width: 100px;
+ height: 100px;
+ background: green;
+ anchor-scroll: --a;
+ top: anchor(--a top);
+ position-fallback: --pf;
+}
+
+@position-fallback --pf {
+ @try { left: anchor(--a right); }
+ @try { right: anchor(--a left); }
+}
+</style>
+
+<div id="anchor"></div>
+<div id="spacer"></div>
+<div id="anchored"></div>
+
+<script>
+promise_test(async () => {
+ await waitUntilNextAnimationFrame();
+ assert_fallback_position(anchored, anchor, 'right');
+}, 'Should use the first fallback position at the initial scroll offset');
+
+promise_test(async () => {
+ document.documentElement.scrollLeft = -101;
+ await waitUntilNextAnimationFrame();
+ assert_fallback_position(anchored, anchor, 'left');
+}, 'Should use the second fallback position after scrolling left');
+</script>
+
+</html>
diff --git a/testing/web-platform/tests/css/css-anchor-position/anchor-scroll-fixedpos.tentative.html b/testing/web-platform/tests/css/css-anchor-position/anchor-scroll-fixedpos.tentative.html
new file mode 100644
index 0000000000..ee7d22608b
--- /dev/null
+++ b/testing/web-platform/tests/css/css-anchor-position/anchor-scroll-fixedpos.tentative.html
@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+<title>Tests that anchor-scroll adjusts location of fixed-positioned elements correctly</title>
+<link rel="author" href="mailto:xiaochengh@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/">
+<link rel="match" href="reference/anchor-scroll-fixedpos-ref.html">
+<style>
+body {
+ margin: 0;
+ height: 2000px;
+}
+
+div {
+ width: 100px;
+ height: 100px;
+}
+
+#anchor {
+ anchor-name: --a1;
+ margin: 300px;
+ background: orange;
+}
+
+#anchored {
+ position: fixed;
+ anchor-scroll: --a1;
+ left: anchor(--a1 right);
+ top: anchor(--a1 top);
+ background: green;
+}
+
+</style>
+
+<div id="anchor"></div>
+<div id="anchored"></div>
+
+<script>
+document.documentElement.scrollTop = 200;
+</script>
diff --git a/testing/web-platform/tests/css/css-anchor-position/anchor-scroll-js-expose.tentative.html b/testing/web-platform/tests/css/css-anchor-position/anchor-scroll-js-expose.tentative.html
new file mode 100644
index 0000000000..f19d010d35
--- /dev/null
+++ b/testing/web-platform/tests/css/css-anchor-position/anchor-scroll-js-expose.tentative.html
@@ -0,0 +1,89 @@
+<!DOCTYPE html>
+<title>Tests that anchor element's actual rendered location is property exposed via JS APIs under anchor-scroll</title>
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/#anchor-scroll">
+<link rel="author" href="mailto:xiaochengh@chromium.org">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<style>
+#container {
+ position: absolute;
+ top: 0px;
+ left: 0px;
+}
+#scroller {
+ margin-left: 100px;
+ margin-top: 100px;
+ width: 400px;
+ height: 400px;
+ overflow: scroll;
+}
+#anchor-container {
+ width: 2000px;
+ height: 1000px;
+}
+#anchor {
+ margin: 400px;
+ margin-left: 1400px;
+ width: 100px;
+ height: 100px;
+ background-color: yellow;
+ anchor-name: --anchor;
+}
+#anchored {
+ position: absolute;
+ left: anchor(--anchor left);
+ bottom: anchor(--anchor top);
+ width: 100px;
+ height: 100px;
+ anchor-scroll: --anchor;
+ background-color: green;
+}
+</style>
+
+<div id="container">
+ <div id="scroller">
+ <div id="anchor"></div>
+ </div>
+ <div id="anchored">Text</div>
+</div>
+
+<script>
+promise_setup(async () => {
+ // Move both the anchor and the anchored elements into the visible area of the
+ // scroller. This also runs layout to setup an empty anchor-scroll snapshot.
+ scroller.scrollTop = 300;
+ scroller.scrollLeft = 1300;
+
+ // Ensure up-to-date anchor-scroll snapshot.
+ await new Promise(resolve => requestAnimationFrame(resolve));
+});
+
+promise_test(async () => {
+ let rect = anchored.getBoundingClientRect();
+ assert_equals(rect.x, 200);
+ assert_equals(rect.y, 100);
+}, 'Element.getBoundingClientRect() returns the actual rendered location');
+
+promise_test(async () => {
+ let range = document.createRange();
+ let text = anchored.firstChild;
+ range.setStart(text, 0);
+ range.setEnd(text, text.length);
+ let rect = range.getBoundingClientRect();
+ assert_equals(rect.x, 200);
+ assert_equals(rect.y, 100);
+}, 'Range.getBoundingClientRect() returns the actual rendered location');
+
+promise_test(async () => {
+ assert_equals(anchored.offsetLeft, 200);
+ assert_equals(anchored.offsetTop, 100);
+}, 'Element.offset* return adjusted offsets');
+
+promise_test(() => new Promise(resolve => {
+ let observer = new IntersectionObserver(entryList => {
+ if (entryList.some(entry => entry.isIntersecting))
+ resolve();
+ });
+ observer.observe(anchored);
+}), 'IntersectionObserver should fire when anchor-scroll moves element into visible area');
+</script>
diff --git a/testing/web-platform/tests/css/css-anchor-position/anchor-scroll-nested.tentative.html b/testing/web-platform/tests/css/css-anchor-position/anchor-scroll-nested.tentative.html
new file mode 100644
index 0000000000..964b02a5b0
--- /dev/null
+++ b/testing/web-platform/tests/css/css-anchor-position/anchor-scroll-nested.tentative.html
@@ -0,0 +1,90 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<title>Tests anchor-scroll with nested scroll containers</title>
+<link rel="author" href="mailto:xiaochengh@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/">
+<link rel="match" href="reference/anchor-scroll-nested-ref.html">
+<style>
+body {
+ margin: 0;
+ width: 1500px;
+ height: 1500px;
+ position: relative;
+}
+
+#outer-scroller {
+ margin: 500px;
+ width: 350px;
+ height: 350px;
+ outline: 1px solid black;
+ overflow: scroll;
+}
+
+#inner-scroller {
+ margin: 100px;
+ width: 250px;
+ height: 250px;
+ outline: 1px solid black;
+ overflow: scroll;
+}
+
+#anchor {
+ margin: 200px;
+ width: 50px;
+ height: 50px;
+ background-color: green;
+ anchor-name: --anchor;
+}
+
+.anchored {
+ position: absolute;
+ width: 50px;
+ height: 50px;
+ left: anchor(--anchor left);
+ anchor-scroll: --anchor;
+}
+
+.above {
+ bottom: anchor(--anchor top);
+ background-color: red;
+}
+
+.below {
+ top: anchor(--anchor bottom);
+ background-color: yellow;
+}
+</style>
+
+<div id="outer-scroller">
+ <div id="inner-scroller">
+ <div id="anchor"></div>
+ <div class="anchored above"></div>
+ </div>
+</div>
+
+<div class="anchored below"></div>
+
+<script>
+function raf() {
+ return new Promise(resolve => requestAnimationFrame(resolve));
+}
+
+async function runTest() {
+ await raf();
+ await raf();
+
+ document.documentElement.scrollTop = 400;
+ document.documentElement.scrollLeft = 400;
+
+ let outerScroller = document.getElementById('outer-scroller');
+ outerScroller.scrollTop = 50;
+ outerScroller.scrollLeft = 50;
+
+ let innerScroller = document.getElementById('inner-scroller');
+ innerScroller.scrollTop = 100;
+ innerScroller.scrollLeft = 100;
+
+ document.documentElement.classList.remove('reftest-wait');
+}
+runTest();
+</script>
diff --git a/testing/web-platform/tests/css/css-anchor-position/anchor-scroll-no-overflow-crash.html b/testing/web-platform/tests/css/css-anchor-position/anchor-scroll-no-overflow-crash.html
new file mode 100644
index 0000000000..d8fa3821cf
--- /dev/null
+++ b/testing/web-platform/tests/css/css-anchor-position/anchor-scroll-no-overflow-crash.html
@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+<title>Tests that anchor-scroll doesn't crash renderer when anchor is in a scroller whose content doesn't overflow</title>
+<link rel="author" href="mailto:xiaochengh@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/">
+<style>
+#container {
+ position: relative;
+}
+
+#scroller {
+ overflow: scroll;
+ width: 400px;
+ height: 400px;
+}
+
+#anchor {
+ anchor-name: --a;
+ margin: 100px;
+ width: 100px;
+ height: 100px;
+ background: green;
+}
+
+#anchored {
+ position: absolute;
+ anchor-scroll: --a;
+ left: anchor(--a left);
+ bottom: anchor(--a top);
+ width: 100px;
+ height: 100px;
+ background: orange;
+}
+
+</style>
+
+<div id="container">
+ <div id="scroller">
+ <div id="anchor">anchor</div>
+ </div>
+ <div id="anchored">anchored</div>
+</div>
diff --git a/testing/web-platform/tests/css/css-anchor-position/anchor-scroll-update-001.tentative.html b/testing/web-platform/tests/css/css-anchor-position/anchor-scroll-update-001.tentative.html
new file mode 100644
index 0000000000..9400136e98
--- /dev/null
+++ b/testing/web-platform/tests/css/css-anchor-position/anchor-scroll-update-001.tentative.html
@@ -0,0 +1,83 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<title>Basic of anchor-scroll: anchored elements should keep "pinned" to the anchor during anchor scroll updates</title>
+<link rel="author" href="mailto:xiaochengh@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/">
+<link rel="match" href="reference/anchor-scroll-ref.html">
+<link rel="stylesheet" href="/fonts/ahem.css">
+<style>
+body {
+ font: 20px/1 Ahem;
+ margin: 0;
+}
+
+#scroll-container {
+ width: 400px;
+ height: 400px;
+ overflow: scroll;
+}
+
+#scroll-contents {
+ width: 1000px;
+ height: 1000px;
+ position: relative;
+}
+
+#placefiller-above-anchor {
+ height: 500px;
+}
+
+#placefiller-before-anchor {
+ display: inline-block;
+ width: 500px;
+}
+
+#anchor {
+ anchor-name: --anchor;
+}
+
+#inner-anchored {
+ color: green;
+ position: absolute;
+ left: anchor(--anchor left);
+ bottom: anchor(--anchor top);
+ anchor-scroll: --anchor;
+}
+
+#outer-anchored {
+ color: yellow;
+ position: absolute;
+ left: anchor(--anchor left);
+ top: anchor(--anchor bottom);
+ anchor-scroll: --anchor;
+}
+</style>
+
+<div style="position: relative">
+ <div id="scroll-container">
+ <div id="scroll-contents">
+ <div id="placefiller-above-anchor"></div>
+ <div id="placefiller-before-anchor"></div>
+ <span id="anchor">anchor</span>
+ <div id="inner-anchored">inner-anchored</div>
+ </div>
+ </div>
+ <div id="outer-anchored">outer-anchored</div>
+</div>
+
+<script>
+function raf() {
+ return new Promise(resolve => requestAnimationFrame(resolve));
+}
+
+async function runTest() {
+ await raf();
+ await raf();
+ const scroller = document.getElementById('scroll-container');
+ scroller.scrollTop = 300;
+ scroller.scrollLeft = 450;
+ document.documentElement.classList.remove('reftest-wait');
+}
+runTest();
+</script>
+</html>
diff --git a/testing/web-platform/tests/css/css-anchor-position/anchor-scroll-update-002.tentative.html b/testing/web-platform/tests/css/css-anchor-position/anchor-scroll-update-002.tentative.html
new file mode 100644
index 0000000000..4e8fcbe295
--- /dev/null
+++ b/testing/web-platform/tests/css/css-anchor-position/anchor-scroll-update-002.tentative.html
@@ -0,0 +1,84 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<title>Basic of anchor-scroll: anchored elements should update location on `anchor-scroll` property changes</title>
+<link rel="author" href="mailto:xiaochengh@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/">
+<link rel="match" href="reference/anchor-scroll-ref.html">
+<link rel="stylesheet" href="/fonts/ahem.css">
+<style>
+body {
+ font: 20px/1 Ahem;
+ margin: 0;
+}
+
+#scroll-container {
+ width: 400px;
+ height: 400px;
+ overflow: scroll;
+}
+
+#scroll-contents {
+ width: 1000px;
+ height: 1000px;
+ position: relative;
+}
+
+#placefiller-above-anchor {
+ height: 500px;
+}
+
+#placefiller-before-anchor {
+ display: inline-block;
+ width: 500px;
+}
+
+#anchor {
+ anchor-name: --anchor;
+}
+
+#inner-anchored {
+ color: green;
+ position: absolute;
+ left: anchor(--anchor left);
+ bottom: anchor(--anchor top);
+}
+
+#outer-anchored {
+ color: yellow;
+ position: absolute;
+ left: anchor(--anchor left);
+ top: anchor(--anchor bottom);
+}
+</style>
+
+<div style="position: relative">
+ <div id="scroll-container">
+ <div id="scroll-contents">
+ <div id="placefiller-above-anchor"></div>
+ <div id="placefiller-before-anchor"></div>
+ <span id="anchor">anchor</span>
+ <div id="inner-anchored">inner-anchored</div>
+ </div>
+ </div>
+ <div id="outer-anchored">outer-anchored</div>
+</div>
+
+<script>
+const scroller = document.getElementById('scroll-container');
+scroller.scrollTop = 300;
+scroller.scrollLeft = 450;
+
+function raf() {
+ return new Promise(resolve => requestAnimationFrame(resolve));
+}
+
+async function runTest() {
+ await raf();
+ await raf();
+ document.getElementById('inner-anchored').style.anchorScroll = '--anchor';
+ document.getElementById('outer-anchored').style.anchorScroll = '--anchor';
+ document.documentElement.classList.remove('reftest-wait');
+}
+runTest();
+</script>
+</html>
diff --git a/testing/web-platform/tests/css/css-anchor-position/anchor-scroll-update-003.tentative.html b/testing/web-platform/tests/css/css-anchor-position/anchor-scroll-update-003.tentative.html
new file mode 100644
index 0000000000..0d3ec2830c
--- /dev/null
+++ b/testing/web-platform/tests/css/css-anchor-position/anchor-scroll-update-003.tentative.html
@@ -0,0 +1,81 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<title>Basic of anchor-scroll: anchored elements should update location on anchor's `anchor-name` property changes</title>
+<link rel="author" href="mailto:xiaochengh@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/">
+<link rel="match" href="reference/anchor-scroll-ref.html">
+<link rel="stylesheet" href="/fonts/ahem.css">
+<style>
+body {
+ font: 20px/1 Ahem;
+ margin: 0;
+}
+
+#scroll-container {
+ width: 400px;
+ height: 400px;
+ overflow: scroll;
+}
+
+#scroll-contents {
+ width: 1000px;
+ height: 1000px;
+ position: relative;
+}
+
+#placefiller-above-anchor {
+ height: 500px;
+}
+
+#placefiller-before-anchor {
+ display: inline-block;
+ width: 500px;
+}
+
+#inner-anchored {
+ color: green;
+ position: absolute;
+ left: anchor(--anchor left);
+ bottom: anchor(--anchor top);
+ anchor-scroll: --anchor;
+}
+
+#outer-anchored {
+ color: yellow;
+ position: absolute;
+ left: anchor(--anchor left);
+ top: anchor(--anchor bottom);
+ anchor-scroll: --anchor;
+}
+</style>
+
+<div style="position: relative">
+ <div id="scroll-container">
+ <div id="scroll-contents">
+ <div id="placefiller-above-anchor"></div>
+ <div id="placefiller-before-anchor"></div>
+ <span id="anchor">anchor</span>
+ <div id="inner-anchored">inner-anchored</div>
+ </div>
+ </div>
+ <div id="outer-anchored">outer-anchored</div>
+</div>
+
+<script>
+const scroller = document.getElementById('scroll-container');
+scroller.scrollTop = 300;
+scroller.scrollLeft = 450;
+
+function raf() {
+ return new Promise(resolve => requestAnimationFrame(resolve));
+}
+
+async function runTest() {
+ await raf();
+ await raf();
+ document.getElementById('anchor').style.anchorName = '--anchor';
+ document.documentElement.classList.remove('reftest-wait');
+}
+runTest();
+</script>
+</html>
diff --git a/testing/web-platform/tests/css/css-anchor-position/anchor-scroll-update-004.tentative.html b/testing/web-platform/tests/css/css-anchor-position/anchor-scroll-update-004.tentative.html
new file mode 100644
index 0000000000..7d1aadc95d
--- /dev/null
+++ b/testing/web-platform/tests/css/css-anchor-position/anchor-scroll-update-004.tentative.html
@@ -0,0 +1,93 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<title>Basic of anchor-scroll: anchored elements should update location on anchor's layout changes</title>
+<link rel="author" href="mailto:xiaochengh@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/">
+<link rel="match" href="reference/anchor-scroll-ref.html">
+<link rel="stylesheet" href="/fonts/ahem.css">
+<style>
+body {
+ font: 20px/1 Ahem;
+ margin: 0;
+}
+
+#scroll-container {
+ width: 400px;
+ height: 400px;
+ overflow: scroll;
+}
+
+#scroll-contents {
+ width: 1000px;
+ height: 1000px;
+ position: relative;
+}
+
+#anchor {
+ anchor-name: --anchor;
+}
+
+#placefiller-above-anchor {
+ height: 800px;
+}
+
+.after #placefiller-above-anchor {
+ height: 500px;
+}
+
+#placefiller-before-anchor {
+ display: inline-block;
+ width: 800px;
+}
+
+.after #placefiller-before-anchor {
+ width: 500px;
+}
+
+#inner-anchored {
+ color: green;
+ position: absolute;
+ left: anchor(--anchor left);
+ bottom: anchor(--anchor top);
+ anchor-scroll: --anchor;
+}
+
+#outer-anchored {
+ color: yellow;
+ position: absolute;
+ left: anchor(--anchor left);
+ top: anchor(--anchor bottom);
+ anchor-scroll: --anchor;
+}
+</style>
+
+<div style="position: relative">
+ <div id="scroll-container">
+ <div id="scroll-contents">
+ <div id="placefiller-above-anchor"></div>
+ <div id="placefiller-before-anchor"></div>
+ <span id="anchor">anchor</span>
+ <div id="inner-anchored">inner-anchored</div>
+ </div>
+ </div>
+ <div id="outer-anchored">outer-anchored</div>
+</div>
+
+<script>
+const scroller = document.getElementById('scroll-container');
+scroller.scrollTop = 300;
+scroller.scrollLeft = 450;
+
+function raf() {
+ return new Promise(resolve => requestAnimationFrame(resolve));
+}
+
+async function runTest() {
+ await raf();
+ await raf();
+ document.getElementById('scroll-contents').classList.add('after');
+ document.documentElement.classList.remove('reftest-wait');
+}
+runTest();
+</script>
+</html>
diff --git a/testing/web-platform/tests/css/css-anchor-position/anchor-scroll-update-005.tentative.html b/testing/web-platform/tests/css/css-anchor-position/anchor-scroll-update-005.tentative.html
new file mode 100644
index 0000000000..5675507a47
--- /dev/null
+++ b/testing/web-platform/tests/css/css-anchor-position/anchor-scroll-update-005.tentative.html
@@ -0,0 +1,56 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<title>Tests that anchored element should update location after scroll offset changes caused by scroller resizing</title>
+<link rel="author" href="mailto:xiaochengh@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/">
+<link rel="match" href="reference/anchor-scroll-update-005-ref.html">
+<style>
+ #cb {
+ position: absolute;
+ inset: 0;
+ }
+ #scroller {
+ margin-top: 300px;
+ overflow-y: scroll;
+ height: 100px;
+ }
+ #scroller.changed { height: 200px; }
+ #spacer { height: 400px; }
+ #anchor { anchor-name: --a; }
+ #anchored {
+ position: absolute;
+ width: 100px;
+ height: 100px;
+ background-color: green;
+ top: anchor(--a top);
+ left: 0;
+ anchor-scroll: --a;
+ }
+</style>
+<div id="cb">
+ <div id="scroller">
+ <div id="anchor"></div>
+ <div id="spacer"></div>
+ </div>
+ <div id="anchored"></div>
+</div>
+<script>
+function raf() {
+ return new Promise(resolve => requestAnimationFrame(resolve));
+}
+
+async function runTest() {
+ const scroller = document.getElementById('scroller');
+ scroller.scrollTop = 300;
+
+ await raf();
+ await raf();
+
+ scroller.classList.add('changed');
+ document.documentElement.classList.remove('reftest-wait');
+
+ // Should change scroll offset and anchor-scroll adjustment to 200.
+}
+runTest();
+</script>
+
diff --git a/testing/web-platform/tests/css/css-anchor-position/anchor-scroll-update-006.tentative.html b/testing/web-platform/tests/css/css-anchor-position/anchor-scroll-update-006.tentative.html
new file mode 100644
index 0000000000..7a8e675baa
--- /dev/null
+++ b/testing/web-platform/tests/css/css-anchor-position/anchor-scroll-update-006.tentative.html
@@ -0,0 +1,56 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<title>Tests that anchored element should update location after scroll offset changes caused by scroll content resizing</title>
+<link rel="author" href="mailto:xiaochengh@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/">
+<link rel="match" href="reference/anchor-scroll-update-006-ref.html">
+<style>
+ #cb {
+ position: absolute;
+ inset: 0;
+ }
+ #scroller {
+ margin-top: 300px;
+ overflow-y: scroll;
+ height: 100px;
+ }
+ #spacer { height: 400px; }
+ #spacer.changed { height: 300px; }
+ #anchor { anchor-name: --a; }
+ #anchored {
+ position: absolute;
+ width: 100px;
+ height: 100px;
+ background-color: green;
+ top: anchor(--a top);
+ left: 0;
+ anchor-scroll: --a;
+ }
+</style>
+<div id="cb">
+ <div id="scroller">
+ <div id="anchor"></div>
+ <div id="spacer"></div>
+ </div>
+ <div id="anchored"></div>
+</div>
+<script>
+function raf() {
+ return new Promise(resolve => requestAnimationFrame(resolve));
+}
+
+async function runTest() {
+ const scroller = document.getElementById('scroller');
+ scroller.scrollTop = 300;
+
+ await raf();
+ await raf();
+
+ document.getElementById('spacer').classList.add('changed');
+ document.documentElement.classList.remove('reftest-wait');
+
+ // Should change scroll offset and anchor-scroll adjustment to 200.
+}
+runTest();
+</script>
+
diff --git a/testing/web-platform/tests/css/css-anchor-position/anchor-scroll-vlr.tentative.html b/testing/web-platform/tests/css/css-anchor-position/anchor-scroll-vlr.tentative.html
new file mode 100644
index 0000000000..82d167f48d
--- /dev/null
+++ b/testing/web-platform/tests/css/css-anchor-position/anchor-scroll-vlr.tentative.html
@@ -0,0 +1,81 @@
+<!DOCTYPE html>
+<title>Tests that anchor-scroll works in vertical-lr writing mode</title>
+<link rel="author" href="mailto:xiaochengh@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/#anchor-scroll">
+<link rel="match" href="reference/anchor-scroll-vlr-ref.html">
+<link rel="stylesheet" href="/fonts/ahem.css">
+<style>
+:root {
+ /* Prevents creatings scrollbar on the viewport due to anchored element's
+ * layout position being out of the viewport.
+ * TODO(crbug.com/1309178): Revisit this behavior.
+ */
+ overflow: clip;
+}
+
+body {
+ font: 20px/1 Ahem;
+ margin: 0;
+ writing-mode: vertical-lr;
+ white-space: nowrap;
+}
+
+#scroll-container {
+ width: 400px;
+ height: 400px;
+ overflow: scroll;
+}
+
+#scroll-contents {
+ width: 1000px;
+ height: 1000px;
+ position: relative;
+}
+
+#placefiller-above-anchor {
+ width: 500px;
+}
+
+#placefiller-before-anchor {
+ display: inline-block;
+ height: 500px;
+}
+
+#anchor {
+ anchor-name: --anchor;
+}
+
+#inner-anchored {
+ color: green;
+ position: absolute;
+ top: anchor(--anchor top);
+ left: anchor(--anchor right);
+ anchor-scroll: --anchor;
+}
+
+#outer-anchored {
+ color: yellow;
+ position: absolute;
+ top: anchor(--anchor top);
+ right: anchor(--anchor left);
+ anchor-scroll: --anchor;
+}
+</style>
+
+<div style="position: relative;">
+ <div id="scroll-container">
+ <div id="scroll-contents">
+ <div id="placefiller-above-anchor"></div>
+ <div id="placefiller-before-anchor"></div>
+ <span id="anchor">anchor</span>
+ <div id="inner-anchored">inner-anchored</div>
+ </div>
+ </div>
+ <div id="outer-anchored">outer-anchored</div>
+</div>
+
+<script>
+const scroller = document.getElementById('scroll-container');
+scroller.scrollTop = 450;
+scroller.scrollLeft = 300;
+</script>
diff --git a/testing/web-platform/tests/css/css-anchor-position/anchor-scroll-vrl.tentative.html b/testing/web-platform/tests/css/css-anchor-position/anchor-scroll-vrl.tentative.html
new file mode 100644
index 0000000000..55b7355897
--- /dev/null
+++ b/testing/web-platform/tests/css/css-anchor-position/anchor-scroll-vrl.tentative.html
@@ -0,0 +1,81 @@
+<!DOCTYPE html>
+<title>Tests that anchor-scroll works in vertical-rl writing mode</title>
+<link rel="author" href="mailto:xiaochengh@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/#anchor-scroll">
+<link rel="match" href="reference/anchor-scroll-vrl-ref.html">
+<link rel="stylesheet" href="/fonts/ahem.css">
+<style>
+:root {
+ /* Prevents creatings scrollbar on the viewport due to anchored element's
+ * layout position being out of the viewport.
+ * TODO(crbug.com/1309178): Revisit this behavior.
+ */
+ overflow: clip;
+}
+
+body {
+ font: 20px/1 Ahem;
+ margin: 0;
+ writing-mode: vertical-rl;
+ white-space: nowrap;
+}
+
+#scroll-container {
+ width: 400px;
+ height: 400px;
+ overflow: scroll;
+}
+
+#scroll-contents {
+ width: 1000px;
+ height: 1000px;
+ position: relative;
+}
+
+#placefiller-above-anchor {
+ width: 500px;
+}
+
+#placefiller-before-anchor {
+ display: inline-block;
+ height: 500px;
+}
+
+#anchor {
+ anchor-name: --anchor;
+}
+
+#inner-anchored {
+ color: green;
+ position: absolute;
+ top: anchor(--anchor top);
+ left: anchor(--anchor right);
+ anchor-scroll: --anchor;
+}
+
+#outer-anchored {
+ color: yellow;
+ position: absolute;
+ top: anchor(--anchor top);
+ right: anchor(--anchor left);
+ anchor-scroll: --anchor;
+}
+</style>
+
+<div style="position: relative;">
+ <div id="scroll-container">
+ <div id="scroll-contents">
+ <div id="placefiller-above-anchor"></div>
+ <div id="placefiller-before-anchor"></div>
+ <span id="anchor">anchor</span>
+ <div id="inner-anchored">inner-anchored</div>
+ </div>
+ </div>
+ <div id="outer-anchored">outer-anchored</div>
+</div>
+
+<script>
+const scroller = document.getElementById('scroll-container');
+scroller.scrollTop = 450;
+scroller.scrollLeft = -300;
+</script>
diff --git a/testing/web-platform/tests/css/css-anchor-position/anchor-size-001.html b/testing/web-platform/tests/css/css-anchor-position/anchor-size-001.html
new file mode 100644
index 0000000000..e5a0dfde1f
--- /dev/null
+++ b/testing/web-platform/tests/css/css-anchor-position/anchor-size-001.html
@@ -0,0 +1,42 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/#propdef-anchor-name">
+<link rel="author" href="mailto:kojii@chromium.org">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/check-layout-th.js"></script>
+<style>
+.container {
+ position: relative;
+ height: 10px;
+}
+.anchor1 {
+ anchor-name: --a1;
+ width: 5px;
+ height: 7px;
+ background: orange;
+}
+.target {
+ position: absolute;
+}
+</style>
+<body onload="checkLayout('.target')">
+ <div class="container">
+ <div class="anchor1"></div>
+
+ <!-- Basic cases of all `anchor-size`s. -->
+ <div class="target" style="width: anchor-size(--a1 width)" data-expected-width=5></div>
+ <div class="target" style="height: anchor-size(--a1 height)" data-expected-height=7></div>
+ <div class="target" style="width: anchor-size(--a1 inline)" data-expected-width=5></div>
+ <div class="target" style="height: anchor-size(--a1 block)" data-expected-height=7></div>
+ <div class="target" style="width: anchor-size(--a1 self-inline)" data-expected-width=5></div>
+ <div class="target" style="height: anchor-size(--a1 self-block)" data-expected-height=7></div>
+
+ <!-- Different axes should work. -->
+ <div class="target" style="height: anchor-size(--a1 width)" data-expected-height=5></div>
+ <div class="target" style="width: anchor-size(--a1 height)" data-expected-width=7></div>
+ <div class="target" style="height: anchor-size(--a1 inline)" data-expected-height=5></div>
+ <div class="target" style="width: anchor-size(--a1 block)" data-expected-width=7></div>
+ <div class="target" style="height: anchor-size(--a1 self-inline)" data-expected-height=5></div>
+ <div class="target" style="width: anchor-size(--a1 self-block)" data-expected-width=7></div>
+ </div>
+</body>
diff --git a/testing/web-platform/tests/css/css-anchor-position/anchor-size-minmax-001.html b/testing/web-platform/tests/css/css-anchor-position/anchor-size-minmax-001.html
new file mode 100644
index 0000000000..f7fb07b0af
--- /dev/null
+++ b/testing/web-platform/tests/css/css-anchor-position/anchor-size-minmax-001.html
@@ -0,0 +1,44 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/#propdef-anchor-name">
+<link rel="author" href="mailto:kojii@chromium.org">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/check-layout-th.js"></script>
+<style>
+.container {
+ position: relative;
+ height: 10px;
+}
+.anchor1 {
+ anchor-name: --a1;
+ width: 5px;
+ height: 7px;
+ background: orange;
+}
+.target {
+ position: absolute;
+}
+</style>
+<body onload="checkLayout('.target')">
+ <div class="container">
+ <div class="anchor1"></div>
+
+ <div class="target"
+ style="min-width: anchor-size(--a1 width)"
+ data-expected-width=5></div>
+ <div class="target"
+ style="min-height: anchor-size(--a1 width)"
+ data-expected-height=5></div>
+
+ <div class="target"
+ style="max-width: anchor-size(--a1 width)"
+ data-expected-width=5>
+ <div style="width: 100px"></div>
+ </div>
+ <div class="target"
+ style="max-height: anchor-size(--a1 width)"
+ data-expected-height=5>
+ <div style="height: 100px"></div>
+ </div>
+ </div>
+</body>
diff --git a/testing/web-platform/tests/css/css-anchor-position/anchor-size-parse-invalid.html b/testing/web-platform/tests/css/css-anchor-position/anchor-size-parse-invalid.html
new file mode 100644
index 0000000000..d13f21a585
--- /dev/null
+++ b/testing/web-platform/tests/css/css-anchor-position/anchor-size-parse-invalid.html
@@ -0,0 +1,42 @@
+<!DOCTYPE html>
+<title>Tests values that are invalid at parse time for the anchor-size() function</title>
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/#anchor-size">
+<link rel="author" href="mailto:xiaochengh@chromium.org">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/parsing-testcommon.js"></script>
+
+<script>
+// anchor-size() can only be used in sizing properties
+test_invalid_value('margin-top', 'anchor-size(--foo width)');
+test_invalid_value('top', 'anchor-size(--foo width)');
+test_invalid_value('font-size', 'anchor-size(--foo width)');
+
+// Invalid parameter format
+test_invalid_value('width', 'anchor-size(--foo, width)');
+test_invalid_value('width', 'anchor-size(--foo width,)');
+test_invalid_value('width', 'anchor-size(--foo width height)');
+test_invalid_value('width', 'anchor-size(--foo width, 10px 20%)');
+test_invalid_value('width', 'anchor-size(--foo width, 10px, 20%)');
+
+// Anchor name must be a dashed ident
+test_invalid_value('width', 'anchor-size(foo width)');
+
+// Invalid anchor size values
+test_invalid_value('width', 'anchor-size(--foo top)');
+test_invalid_value('width', 'anchor-size(--foo 10em)');
+test_invalid_value('width', 'anchor-size(--foo 100s)');
+test_invalid_value('width', 'anchor-size(--foo 50%)');
+
+// Invalid fallback values
+test_invalid_value('width', 'anchor-size(--foo width, 1)');
+test_invalid_value('width', 'anchor-size(--foo width, 100s)');
+test_invalid_value('width', 'anchor-size(--foo width, height)');
+test_invalid_value('width', 'anchor-size(--foo width, anchor-size(bar width))');
+test_invalid_value('width', 'anchor-size(--foo width, anchor(--bar top))');
+
+// Invalid anchor size values in calc tree
+test_invalid_value('width', 'calc(anchor-size(foo width) + 10px + 10%)');
+test_invalid_value('width', 'calc(10px + 100 * anchor-size(--foo width, anchor-size(bar bottom)))');
+test_invalid_value('width', 'min(anchor-size(--foo width), anchor-size(--bar height), anchor(--baz top))');
+</script>
diff --git a/testing/web-platform/tests/css/css-anchor-position/anchor-size-parse-valid.html b/testing/web-platform/tests/css/css-anchor-position/anchor-size-parse-valid.html
new file mode 100644
index 0000000000..9ed4d04223
--- /dev/null
+++ b/testing/web-platform/tests/css/css-anchor-position/anchor-size-parse-valid.html
@@ -0,0 +1,65 @@
+<!DOCTYPE html>
+<title>Tests parsing of the anchor-size() function</title>
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/#anchor-size">
+<link rel="author" href="mailto:xiaochengh@chromium.org">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/parsing-testcommon.js"></script>
+
+<script>
+const anchorNames = [
+ '--foo',
+ '',
+];
+
+const sizeProperties = [
+ 'width',
+ 'min-width',
+ 'max-width',
+ 'height',
+ 'min-height',
+ 'max-height',
+ 'block-size',
+ 'min-block-size',
+ 'max-block-size',
+ 'inline-size',
+ 'min-inline-size',
+ 'max-inline-size',
+];
+
+const anchorSizes = [
+ 'width',
+ 'height',
+ 'block',
+ 'inline',
+ 'self-block',
+ 'self-inline',
+];
+
+const fallbacks = [
+ null,
+ '1px',
+ '50%',
+ 'calc(1px + 50%)',
+ 'anchor-size(block)',
+ 'anchor-size(--bar block)',
+ 'anchor-size(--bar block, anchor-size(--baz inline))',
+];
+
+// Tests basic combinations
+for (let name of anchorNames) {
+ for (let property of sizeProperties) {
+ for (let size of anchorSizes) {
+ for (let fallback of fallbacks) {
+ let value = `anchor-size(${name ? name + ' ' : ''}${size}${fallback ? ', ' + fallback : ''})`;
+ test_valid_value(property, value);
+ }
+ }
+ }
+}
+
+// Tests that anchor-size() can be used in a calc tree
+test_valid_value('width', 'calc((anchor-size(--foo width) + anchor-size(--bar height)) / 2)');
+test_valid_value('width', 'anchor-size(--foo width, calc(anchor-size(--bar height) * 0.5))');
+test_valid_value('width', 'min(100px, 10%, anchor-size(--foo width), anchor-size(--bar height))');
+</script>
diff --git a/testing/web-platform/tests/css/css-anchor-position/anchor-size-replaced-001.html b/testing/web-platform/tests/css/css-anchor-position/anchor-size-replaced-001.html
new file mode 100644
index 0000000000..e5d133acf7
--- /dev/null
+++ b/testing/web-platform/tests/css/css-anchor-position/anchor-size-replaced-001.html
@@ -0,0 +1,74 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/#propdef-anchor-name">
+<link rel="author" href="mailto:kojii@chromium.org">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/check-layout-th.js"></script>
+<style>
+.container {
+ position: relative;
+ height: 10px;
+}
+.anchor1 {
+ anchor-name: --a1;
+ width: 5px;
+ height: 24px;
+ background: orange;
+}
+.target {
+ position: absolute;
+}
+</style>
+<body onload="checkLayout('.target')">
+ <div class="container">
+ <div class="anchor1"></div>
+
+ <!-- Specifying the width or the height should scale uniformly. -->
+ <img class="target" src="support/green-16x16.png"
+ style="width: anchor-size(--a1 width)"
+ data-expected-width=5 data-expected-height=5>
+ <img class="target" src="support/green-16x16.png"
+ style="height: anchor-size(--a1 width)"
+ data-expected-width=5 data-expected-height=5>
+
+ <!-- Smaller `min-width/height` than the natural size should be ignored. -->
+ <img class="target" src="support/green-16x16.png"
+ style="min-width: anchor-size(--a1 width)"
+ data-expected-width=16 data-expected-height=16>
+ <img class="target" src="support/green-16x16.png"
+ style="min-height: anchor-size(--a1 width)"
+ data-expected-width=16 data-expected-height=16>
+
+ <!-- Larger `min-width/height` than the natural size should scale. -->
+ <img class="target" src="support/green-16x16.png"
+ style="min-width: anchor-size(--a1 height)"
+ data-expected-width=24 data-expected-height=24>
+ <img class="target" src="support/green-16x16.png"
+ style="min-height: anchor-size(--a1 height)"
+ data-expected-width=24 data-expected-height=24>
+
+ <!-- Smaller `max-width/height` than the natural size should scale. -->
+ <img class="target" src="support/green-16x16.png"
+ style="max-width: anchor-size(--a1 width)"
+ data-expected-width=5 data-expected-height=5>
+ <img class="target" src="support/green-16x16.png"
+ style="max-height: anchor-size(--a1 width)"
+ data-expected-width=5 data-expected-height=5>
+
+ <!-- Larger `min-width/height` than the natural size should be ignored. -->
+ <img class="target" src="support/green-16x16.png"
+ style="max-width: anchor-size(--a1 height)"
+ data-expected-width=16 data-expected-height=16>
+ <img class="target" src="support/green-16x16.png"
+ style="max-height: anchor-size(--a1 height)"
+ data-expected-width=16 data-expected-height=16>
+
+ <!-- The `aspect-ratio` property should be honored. -->
+ <img class="target" src="support/green-16x16.png"
+ style="width: anchor-size(--a1 width); aspect-ratio: 0.5"
+ data-expected-width=5 data-expected-height=10>
+ <img class="target" src="support/green-16x16.png"
+ style="height: anchor-size(--a1 width); aspect-ratio: 2"
+ data-expected-width=10 data-expected-height=5>
+ </div>
+</body>
diff --git a/testing/web-platform/tests/css/css-anchor-position/anchor-size-writing-modes-001.html b/testing/web-platform/tests/css/css-anchor-position/anchor-size-writing-modes-001.html
new file mode 100644
index 0000000000..c9e0619741
--- /dev/null
+++ b/testing/web-platform/tests/css/css-anchor-position/anchor-size-writing-modes-001.html
@@ -0,0 +1,67 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/#propdef-anchor-name">
+<link rel="author" href="mailto:kojii@chromium.org">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/check-layout-th.js"></script>
+<style>
+.container {
+ position: relative;
+ height: 10px;
+}
+.anchor1 {
+ anchor-name: --a1;
+ width: 5px;
+ height: 7px;
+ background: orange;
+}
+.target {
+ position: absolute;
+}
+.htb {
+ writing-mode: horizontal-tb;
+}
+.vrl {
+ writing-mode: vertical-rl;
+}
+</style>
+<body onload="checkLayout('.target')">
+ <div class="container">
+ <div class="anchor1 vrl"></div>
+
+ <!-- Anchor's `writing-mode` should not matter. -->
+ <div class="target" style="width: anchor-size(--a1 width)" data-expected-width=5></div>
+ <div class="target" style="width: anchor-size(--a1 height)" data-expected-width=7></div>
+ <div class="target" style="width: anchor-size(--a1 inline)" data-expected-width=5></div>
+ <div class="target" style="width: anchor-size(--a1 block)" data-expected-width=7></div>
+ <div class="target" style="width: anchor-size(--a1 self-inline)" data-expected-width=5></div>
+ <div class="target" style="width: anchor-size(--a1 self-block)" data-expected-width=7></div>
+
+ <!-- `self-inline` and `self-block` take target's `writing-mode` into account. -->
+ <div class="target vrl" style="width: anchor-size(--a1 width)" data-expected-width=5></div>
+ <div class="target vrl" style="width: anchor-size(--a1 height)" data-expected-width=7></div>
+ <div class="target vrl" style="width: anchor-size(--a1 inline)" data-expected-width=5></div>
+ <div class="target vrl" style="width: anchor-size(--a1 block)" data-expected-width=7></div>
+ <div class="target vrl" style="width: anchor-size(--a1 self-inline)" data-expected-width=7></div>
+ <div class="target vrl" style="width: anchor-size(--a1 self-block)" data-expected-width=5></div>
+ </div>
+ <div class="container vrl">
+ <div class="anchor1 htb"></div>
+
+ <!-- Anchor's `writing-mode` should not matter. -->
+ <div class="target" style="width: anchor-size(--a1 width)" data-expected-width=5></div>
+ <div class="target" style="width: anchor-size(--a1 height)" data-expected-width=7></div>
+ <div class="target" style="width: anchor-size(--a1 inline)" data-expected-width=7></div>
+ <div class="target" style="width: anchor-size(--a1 block)" data-expected-width=5></div>
+ <div class="target" style="width: anchor-size(--a1 self-inline)" data-expected-width=7></div>
+ <div class="target" style="width: anchor-size(--a1 self-block)" data-expected-width=5></div>
+
+ <!-- `self-inline` and `self-block` take target's `writing-mode` into account. -->
+ <div class="target htb" style="width: anchor-size(--a1 width)" data-expected-width=5></div>
+ <div class="target htb" style="width: anchor-size(--a1 height)" data-expected-width=7></div>
+ <div class="target htb" style="width: anchor-size(--a1 inline)" data-expected-width=7></div>
+ <div class="target htb" style="width: anchor-size(--a1 block)" data-expected-width=5></div>
+ <div class="target htb" style="width: anchor-size(--a1 self-inline)" data-expected-width=5></div>
+ <div class="target htb" style="width: anchor-size(--a1 self-block)" data-expected-width=7></div>
+ </div>
+</body>
diff --git a/testing/web-platform/tests/css/css-anchor-position/at-fallback-position-allowed-declarations.html b/testing/web-platform/tests/css/css-anchor-position/at-fallback-position-allowed-declarations.html
new file mode 100644
index 0000000000..873fa13140
--- /dev/null
+++ b/testing/web-platform/tests/css/css-anchor-position/at-fallback-position-allowed-declarations.html
@@ -0,0 +1,97 @@
+<!DOCTYPE html>
+<title>Tests which properties are allowed in @fallback-position</title>
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/#fallback-rule">
+<link rel="author" href="mailto:xiaochengh@chromium.org">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<style id="style"></style>
+<script>
+function cleanup() {
+ while (style.sheet.cssRules.length)
+ style.sheet.deleteRule(0);
+}
+
+function test_allowed_declaration(property, value = '1px') {
+ test(t => {
+ t.add_cleanup(cleanup);
+ const serialization = `${property}: ${value}`;
+ const rule = `@position-fallback --foo { @try { ${property}: ${value}; } }`;
+ const index = style.sheet.insertRule(rule);
+ const parsed = style.sheet.cssRules[index].cssRules[0];
+ assert_equals(parsed.cssText, `@try { ${serialization}; }`);
+ }, `${property}: ${value} is allowed in @fallback-position`);
+}
+
+function test_disallowed_declaration(property, value = '1px') {
+ test(t => {
+ t.add_cleanup(cleanup);
+ const rule = `@position-fallback --foo { @try { ${property}: ${value}; } }`;
+ const index = style.sheet.insertRule(rule);
+ const parsed = style.sheet.cssRules[index].cssRules[0];
+ assert_equals(parsed.cssText, `@try { }`);
+ }, `${property}: ${value} is disallowed in @fallback-position`);
+}
+
+// Inset properties are allowed
+test_allowed_declaration('top');
+test_allowed_declaration('bottom');
+test_allowed_declaration('left');
+test_allowed_declaration('right');
+test_allowed_declaration('inset-block-start');
+test_allowed_declaration('inset-block-end');
+test_allowed_declaration('inset-inline-start');
+test_allowed_declaration('inset-inline-end');
+test_allowed_declaration('inset-block');
+test_allowed_declaration('inset-inline');
+test_allowed_declaration('inset');
+
+// Sizing properties are allowed
+test_allowed_declaration('width');
+test_allowed_declaration('height');
+test_allowed_declaration('block-size');
+test_allowed_declaration('inline-size');
+test_allowed_declaration('min-width');
+test_allowed_declaration('min-height');
+test_allowed_declaration('min-block-size');
+test_allowed_declaration('min-inline-size');
+test_allowed_declaration('max-width');
+test_allowed_declaration('max-height');
+test_allowed_declaration('max-block-size');
+test_allowed_declaration('max-inline-size');
+
+// Box alignment properties are allowed
+test_allowed_declaration('justify-content', 'normal');
+test_allowed_declaration('align-content', 'normal');
+test_allowed_declaration('justify-items', 'normal');
+test_allowed_declaration('align-items', 'normal');
+test_allowed_declaration('justify-self', 'normal');
+test_allowed_declaration('align-self', 'normal');
+
+// Custom properties are disallowed
+test_disallowed_declaration('--custom');
+
+// Margin properties are disallowed
+test_disallowed_declaration('margin-left');
+test_disallowed_declaration('margin-right');
+test_disallowed_declaration('margin-top');
+test_disallowed_declaration('margin-bottom');
+test_disallowed_declaration('margin');
+
+// Test some other disallowed properties
+test_disallowed_declaration('font-size');
+test_disallowed_declaration('border-width');
+test_disallowed_declaration('padding');
+test_disallowed_declaration('display');
+test_disallowed_declaration('position');
+test_disallowed_declaration('float');
+
+// 'revert' and 'revert-layer' are disallowed
+test_disallowed_declaration('top', 'revert');
+test_disallowed_declaration('top', 'revert-layer');
+test_disallowed_declaration('inset', 'revert');
+test_disallowed_declaration('inset', 'revert-layer');
+
+// !important is disallowed
+test_disallowed_declaration('top', '1px !important');
+test_disallowed_declaration('inset', '1px !important');
+</script>
diff --git a/testing/web-platform/tests/css/css-anchor-position/at-fallback-position-parse.html b/testing/web-platform/tests/css/css-anchor-position/at-fallback-position-parse.html
new file mode 100644
index 0000000000..942d9a2984
--- /dev/null
+++ b/testing/web-platform/tests/css/css-anchor-position/at-fallback-position-parse.html
@@ -0,0 +1,39 @@
+<!DOCTYPE html>
+<title>Tests parsing of @fallback-position rule</title>
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/#fallback-rule">
+<link rel="author" href="mailto:xiaochengh@chromium.org">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/parsing-testcommon.js"></script>
+<script>
+test_valid_rule('@position-fallback --foo {\n}');
+test_valid_rule(`@position-fallback --foo {
+ @try { }
+}`);
+
+// @position-fallback needs exactly one <dashed-ident> as its name
+test_invalid_rule('@position-fallback {\n}');
+test_invalid_rule('@position-fallback foo {\n}');
+test_invalid_rule('@position-fallback --foo --bar {\n}');
+test_invalid_rule('@position-fallback --foo, --bar {\n}');
+
+// @position-fallback accepts only @try blocks as its child rules. Other
+// contents should be ignored.
+test_valid_rule('@position-fallback --foo { top: 1px; }',
+ '@position-fallback --foo {\n}');
+test_valid_rule('@position-fallback --foo { --bar: 1px; }',
+ '@position-fallback --foo {\n}');
+test_valid_rule('@position-fallback --foo { @keyframes bar {} }',
+ '@position-fallback --foo {\n}');
+test_valid_rule('@position-fallback --foo { @font-face {} }',
+ '@position-fallback --foo {\n}');
+test_valid_rule('@position-fallback --foo { arbitrary garbage }',
+ '@position-fallback --foo {\n}');
+
+// @try accepts only regular style declarations. Other contents should be
+// ignored.
+test_valid_rule('@position-fallback --foo { @try { @keyframes bar { } } }',
+ '@position-fallback --foo {\n @try { }\n}');
+test_valid_rule('@position-fallback --foo { @try { @font-face { } } }',
+ '@position-fallback --foo {\n @try { }\n}');
+</script>
diff --git a/testing/web-platform/tests/css/css-anchor-position/at-position-fallback-invalidation-shadow-dom.html b/testing/web-platform/tests/css/css-anchor-position/at-position-fallback-invalidation-shadow-dom.html
new file mode 100644
index 0000000000..569278ac90
--- /dev/null
+++ b/testing/web-platform/tests/css/css-anchor-position/at-position-fallback-invalidation-shadow-dom.html
@@ -0,0 +1,50 @@
+<!DOCTYPE html>
+<title>CSS Anchor Positioning Test: Dynamically change @position-fallback rules in Shadow DOM</title>
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/#fallback-rule">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/declarative-shadow-dom-polyfill.js"></script>
+<style>
+ body { margin: 0; }
+</style>
+
+<div id="host">
+ <template shadowroot="open">
+ <style>
+ ::slotted(#slotted), :host {
+ position-fallback: --pf;
+ position: absolute;
+ }
+ </style>
+ <slot></slot>
+ </template>
+ <div id="slotted"></div>
+</div>
+
+<script>
+ setup(() => {
+ polyfill_declarative_shadow_dom(host);
+ });
+
+ test(() => {
+ assert_equals(host.offsetLeft, 0);
+ }, "#host is initially left:auto");
+
+ test(() => {
+ assert_equals(slotted.offsetLeft, 0);
+ }, "#slotted is initially left:auto");
+
+ host.shadowRoot.styleSheets[0].insertRule(`
+ @position-fallback --pf {
+ @try { left: 100px; }
+ }
+ `);
+
+ test(() => {
+ assert_equals(host.offsetLeft, 100);
+ }, "#host with inserted @position-fallback applied");
+
+ test(() => {
+ assert_equals(slotted.offsetLeft, 100);
+ }, "#slotted with inserted @position-fallback applied");
+</script>
diff --git a/testing/web-platform/tests/css/css-anchor-position/at-position-fallback-invalidation.html b/testing/web-platform/tests/css/css-anchor-position/at-position-fallback-invalidation.html
new file mode 100644
index 0000000000..68a0874931
--- /dev/null
+++ b/testing/web-platform/tests/css/css-anchor-position/at-position-fallback-invalidation.html
@@ -0,0 +1,57 @@
+<!DOCTYPE html>
+<title>CSS Anchor Positioning Test: Dynamically change @position-fallback rules</title>
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/#fallback-rule">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<style>
+ body { margin: 0; }
+
+ #anchor {
+ anchor-name: --a;
+ margin-left: 100px;
+ width: 100px;
+ }
+
+ #anchored {
+ position: absolute;
+ position-fallback: --pf;
+ }
+</style>
+
+<style id="to-enable" media="print">
+ @position-fallback --pf {
+ @try { left: anchor(--a left); }
+ }
+</style>
+
+<div>
+ <div id="anchor">anchor</div>
+ <div id="anchored">anchored</div>
+</div>
+
+<script>
+ test(() => {
+ assert_equals(anchored.offsetLeft, 0);
+ }, "Position-fallback initially not matching any rules");
+
+ test(() => {
+ document.getElementById("to-enable").media = "";
+ assert_equals(anchored.offsetLeft, 100);
+ }, "Enable @position-fallback rule stylesheet");
+
+ const sheet = document.getElementById("to-enable").sheet;
+
+ test(() => {
+ sheet.insertRule(
+ `@position-fallback --pf {
+ @try { left: anchor(--a right); }
+ }`, 1);
+ assert_equals(anchored.offsetLeft, 200);
+ }, "Insert overriding @position-fallback rule");
+
+ test(() => {
+ sheet.disabled = "true";
+ assert_equals(anchored.offsetLeft, 0);
+ }, "Disable the @position-fallback rules");
+
+</script>
diff --git a/testing/web-platform/tests/css/css-anchor-position/position-fallback-001.html b/testing/web-platform/tests/css/css-anchor-position/position-fallback-001.html
new file mode 100644
index 0000000000..85f1d1d65a
--- /dev/null
+++ b/testing/web-platform/tests/css/css-anchor-position/position-fallback-001.html
@@ -0,0 +1,108 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/#fallback">
+<link rel="author" href="mailto:kojii@chromium.org">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/check-layout-th.js"></script>
+<style>
+.cb {
+ position: relative;
+ width: 190px;
+ height: 70px;
+ background: yellow;
+ border-bottom: 1px solid black;
+}
+.spacer {
+ width: 1px;
+ height: 20px;
+}
+.anchor1 {
+ anchor-name: --a1;
+ margin-left: 45px;
+ width: 100px;
+ height: 30px;
+ background: blue;
+}
+.target {
+ position: absolute;
+ position-fallback: --fallback1;
+ width: 40px;
+ height: 15px;
+ margin: 5px;
+ background: orange;
+}
+@position-fallback --fallback1 {
+ @try { /* 1: Position to the right of the anchor. */
+ left: anchor(--a1 right);
+ top: anchor(--a1 top);
+ }
+ @try { /* 2: Position to the left of the anchor. */
+ right: anchor(--a1 left);
+ top: anchor(--a1 top);
+ }
+ @try { /* 3: Position to the bottom of the anchor. */
+ left: anchor(--a1 left);
+ top: anchor(--a1 bottom);
+ }
+ @try { /* 4: Position to the top of the anchor. */
+ left: anchor(--a1 left);
+ bottom: anchor(--a1 top);
+ }
+ @try { /* 5: Position to the left with the narrower width. */
+ left: anchor(--a1 right);
+ top: anchor(--a1 top);
+ width: 35px;
+ height: 40px;
+ }
+}
+</style>
+<body onload="checkLayout('.target')">
+ <!-- If the `cb` is wider, the 1st `@try` fits. -->
+ <div class="cb" style="width: 195px">
+ <div class="spacer"></div>
+ <div class="anchor1"></div>
+ <div class="target"
+ data-offset-x=150 data-offset-y=25
+ data-expected-width=40 data-expected-height=15></div>
+ </div>
+ <!-- If the `margin-left` is wider, the 2nd `@try` fits. -->
+ <div class="cb">
+ <div class="spacer"></div>
+ <div class="anchor1" style="margin-left: 50px"></div>
+ <div class="target"
+ data-offset-x=5 data-offset-y=25
+ data-expected-width=40 data-expected-height=15></div>
+ </div>
+ <!-- Without a spacer, the 3rd `@try` fits. -->
+ <div class="cb">
+ <div class="anchor1"></div>
+ <div class="target"
+ data-offset-x=50 data-offset-y=35
+ data-expected-width=40 data-expected-height=15></div>
+ </div>
+ <!-- With two spacers, the 4th `@try` fits. -->
+ <div class="cb">
+ <div class="spacer"></div>
+ <div class="spacer"></div>
+ <div class="anchor1"></div>
+ <div class="target"
+ data-offset-x=50 data-offset-y=20
+ data-expected-width=40 data-expected-height=15></div>
+ </div>
+ <!-- With a spacer, the last `@try` fits. -->
+ <div class="cb">
+ <div class="spacer"></div>
+ <div class="anchor1"></div>
+ <div class="target"
+ data-offset-x=150 data-offset-y=25
+ data-expected-width=35 data-expected-height=40></div>
+ </div>
+ <!-- If the `cb` is narrower, no rules fit. The last rule is used. -->
+ <div class="cb" style="width: 185px">
+ <div class="spacer"></div>
+ <div class="anchor1"></div>
+ <div class="target"
+ data-offset-x=150 data-offset-y=25
+ data-expected-width=35 data-expected-height=40></div>
+ </div>
+</body>
diff --git a/testing/web-platform/tests/css/css-anchor-position/position-fallback-002.html b/testing/web-platform/tests/css/css-anchor-position/position-fallback-002.html
new file mode 100644
index 0000000000..52c964609b
--- /dev/null
+++ b/testing/web-platform/tests/css/css-anchor-position/position-fallback-002.html
@@ -0,0 +1,61 @@
+<!DOCTYPE html>
+<title>Tests that overflowing the inset-modified containing block triggers position fallback</title>
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/#fallback">
+<link rel="author" href="mailto:xiaochengh@chromium.org">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/check-layout-th.js"></script>
+<style>
+.cb {
+ width: 400px;
+ height: 400px;
+ transform: scale(1);
+ background: yellow;
+}
+.anchor1 {
+ anchor-name: --a;
+ margin-left: 100px;
+ width: 100px;
+ height: 100px;
+ background: blue;
+}
+.target {
+ position: absolute;
+ position-fallback: --fallback;
+ width: min-content;
+ height: 100px;
+ background: orange;
+}
+.inline-spacer {
+ display: inline-block;
+ width: 200px;
+ height: 100px;
+}
+@position-fallback --fallback {
+ @try { /* 1: Position to the left of the anchor. */
+ left: 0;
+ right: anchor(--a left);
+ top: anchor(--a top);
+ }
+ @try { /* 2: Position to the right of the anchor. */
+ left: anchor(--a right);
+ right: 0;
+ top: anchor(--a top);
+ }
+ @try { /* 3: Placeholder fallback that shouldn't be selected when the previous
+ ones do not overflow the available space. */
+ inset: 0;
+ }
+}
+</style>
+<body onload="checkLayout('.target')">
+ <!-- The first `@try` overflows the inset-modifed containing block -->
+ <div class="cb">
+ <div class="anchor1"></div>
+ <div class="target"
+ data-offset-x=200 data-offset-y=0
+ data-expected-width=200 data-expected-height=100>
+ <span class="inline-spacer"></span>
+ </div>
+ </div>
+</body>
diff --git a/testing/web-platform/tests/css/css-anchor-position/position-fallback-basics.html b/testing/web-platform/tests/css/css-anchor-position/position-fallback-basics.html
new file mode 100644
index 0000000000..bfeb921de1
--- /dev/null
+++ b/testing/web-platform/tests/css/css-anchor-position/position-fallback-basics.html
@@ -0,0 +1,40 @@
+<!DOCTYPE html>
+<title>Tests basics of the 'position-fallback' property</title>
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/#propdef-position-fallback">
+<link rel="author" href="mailto:xiaochengh@chromium.org">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/parsing-testcommon.js"></script>
+<script src="/css/support/computed-testcommon.js"></script>
+<script src="/css/support/inheritance-testcommon.js"></script>
+<script src="/css/support/interpolation-testcommon.js"></script>
+
+<div id="container">
+ <div id="target"></div>
+</div>
+
+<script>
+// position-fallback: none | <dashed-ident>
+test_valid_value('position-fallback', 'none');
+test_valid_value('position-fallback', '--foo');
+test_invalid_value('position-fallback', 'foo-bar');
+test_invalid_value('position-fallback', '--foo --bar')
+test_invalid_value('position-fallback', '--foo, --bar')
+test_invalid_value('position-fallback', '100px');
+test_invalid_value('position-fallback', '100%');
+
+// Computed value: as specified
+test_computed_value('position-fallback', 'none');
+test_computed_value('position-fallback', '--foo');
+
+// Initial: none
+// Inherited: no
+assert_not_inherited('position-fallback', 'none', '--foo');
+
+// Animation type: discrete
+test_no_interpolation({
+ property: 'position-fallback',
+ from: '--foo',
+ to: 'none',
+});
+</script>
diff --git a/testing/web-platform/tests/css/css-anchor-position/position-fallback-cascade-layer-reorder.html b/testing/web-platform/tests/css/css-anchor-position/position-fallback-cascade-layer-reorder.html
new file mode 100644
index 0000000000..ec1a64205c
--- /dev/null
+++ b/testing/web-platform/tests/css/css-anchor-position/position-fallback-cascade-layer-reorder.html
@@ -0,0 +1,72 @@
+<!DOCTYPE html>
+<title>Tests that @position-fallback rules are reordered by cascade layers</title>
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/#fallback-rule">
+<link rel="help" href="https://www.w3.org/TR/css-cascade-5/#layering">
+<link rel="author" href="mailto:xiaochengh@chromium.org">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<style>
+body { margin: 0; }
+#anchor {
+ width: 100px;
+ height: 100px;
+ margin-left: 200px;
+ margin-top: 200px;
+ color: orange;
+ anchor-name: --a;
+}
+
+.target {
+ position: absolute;
+ width: 100px;
+ height: 100px;
+ color: lime;
+ position-fallback: --fallback;
+}
+</style>
+
+<div id="anchor"></div>
+
+<script>
+function createTargetWithStyle(test, style) {
+ let styleElement = document.createElement('style');
+ styleElement.textContent = style;
+ let target = document.createElement('div');
+ target.classList.add('target');
+
+ test.add_cleanup(() => {
+ styleElement.remove();
+ target.remove();
+ });
+
+ document.head.appendChild(styleElement);
+ document.body.appendChild(target);
+ return target;
+}
+
+test(t => {
+ const target = createTargetWithStyle(t, `
+ @position-fallback --fallback {
+ @try { right: anchor(--a left); }
+ }
+ @position-fallback --fallback {
+ @try { left: anchor(--a right); }
+ }
+ `);
+ assert_equals(target.offsetLeft, 300);
+}, 'When in the same layer, the last rule of each name wins');
+
+test(t => {
+ const target = createTargetWithStyle(t, `
+ @position-fallback --fallback {
+ @try { bottom: anchor(--a top); }
+ }
+ @layer {
+ @position-fallback --fallback {
+ @try { top: anchor(--a bottom); }
+ }
+ }
+ `);
+ assert_equals(target.offsetTop, 100);
+}, 'When in different layers, the rule of each name in the highest layer wins');
+</script>
diff --git a/testing/web-platform/tests/css/css-anchor-position/position-fallback-custom-property.html b/testing/web-platform/tests/css/css-anchor-position/position-fallback-custom-property.html
new file mode 100644
index 0000000000..ca709af3de
--- /dev/null
+++ b/testing/web-platform/tests/css/css-anchor-position/position-fallback-custom-property.html
@@ -0,0 +1,68 @@
+<!DOCTYPE html>
+<title>Variable substitution in @try rules</title>
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/#fallback">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/check-layout-th.js"></script>
+<style>
+.cb {
+ position: relative;
+ width: 195px;
+ height: 70px;
+ background: yellow;
+ border-bottom: 1px solid black;
+}
+.spacer {
+ width: 1px;
+ height: 20px;
+}
+.anchor1 {
+ anchor-name: --a1;
+ margin-left: 45px;
+ width: 100px;
+ height: 30px;
+ background: blue;
+}
+.target {
+ position: absolute;
+ position-fallback: --fallback1;
+ width: 40px;
+ height: 15px;
+ margin: 5px;
+ background: orange;
+ --left: anchor(--a1 right);
+ --top: anchor(--a1 top);
+}
+.fallback1 {
+ position-fallback: --fallback1;
+}
+.fallback2 {
+ position-fallback: --fallback2;
+}
+@position-fallback --fallback1 {
+ @try { /* Position to the right of the anchor. */
+ left: var(--left);
+ top: var(--top);
+ }
+}
+/* Same as above, but using a shorthand. */
+@position-fallback --fallback2 {
+ @try {
+ inset: var(--top) 0px 0px var(--left);
+ }
+}
+</style>
+<body onload="checkLayout('.target')">
+ <div class="cb">
+ <div class="spacer"></div>
+ <div class="anchor1"></div>
+ <div class="target fallback1"
+ data-offset-x=150 data-offset-y=25></div>
+ </div>
+ <div class="cb">
+ <div class="spacer"></div>
+ <div class="anchor1"></div>
+ <div class="target fallback2"
+ data-offset-x=150 data-offset-y=25></div>
+ </div>
+</body>
diff --git a/testing/web-platform/tests/css/css-anchor-position/position-fallback-dynamic.html b/testing/web-platform/tests/css/css-anchor-position/position-fallback-dynamic.html
new file mode 100644
index 0000000000..f6d8210427
--- /dev/null
+++ b/testing/web-platform/tests/css/css-anchor-position/position-fallback-dynamic.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<title>CSS Anchor Positioning Test: Dynamically change position via position-fallback property</title>
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/#fallback">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<style>
+ body { margin: 0; }
+
+ @position-fallback --fallback1 {
+ @try {
+ left: anchor(--a1 right);
+ }
+ }
+ #anchor {
+ anchor-name: --a1;
+ width: 100px;
+ height: 100px;
+ }
+ #anchored {
+ position: absolute;
+ width: 100px;
+ height: 100px;
+ }
+</style>
+<div id="anchor"></div>
+<div id="anchored"></div>
+<script>
+ test(() => {
+ assert_equals(anchored.offsetLeft, 0);
+ }, "Initial static left position is 0");
+
+ test(() => {
+ anchored.style.positionFallback = "--fallback1";
+ assert_equals(anchored.offsetLeft, 100);
+ }, "Left position set to right edge of anchor with @position-fallback");
+</script>
diff --git a/testing/web-platform/tests/css/css-anchor-position/position-fallback-grid-001.html b/testing/web-platform/tests/css/css-anchor-position/position-fallback-grid-001.html
new file mode 100644
index 0000000000..f5ab4254b5
--- /dev/null
+++ b/testing/web-platform/tests/css/css-anchor-position/position-fallback-grid-001.html
@@ -0,0 +1,92 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/#anchor-pos">
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/#fallback">
+<link rel="help" href="https://drafts.csswg.org/css-grid/#abspos-items">
+<link rel="author" href="mailto:kojii@chromium.org">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/check-layout-th.js"></script>
+<style>
+.cb {
+ position: relative;
+}
+.grid {
+ display: grid;
+ grid-template-columns: repeat(4, 100px);
+ grid-template-rows: 50px 100px 50px 50px;
+}
+.item {
+ background: lightgray;
+}
+.spacer {
+ background: yellow;
+}
+.anchor1 {
+ anchor-name: --a1;
+ background: orange;
+ margin-left: 15px;
+ width: 20px;
+ height: 30px;
+}
+.target {
+ grid-column: 2 / 4;
+ grid-row: 2 / 4;
+ position: absolute;
+ position-fallback: --fallback1;
+ width: 100px;
+ height: 100px;
+ background: lime;
+ opacity: .2;
+}
+@position-fallback --fallback1 {
+ @try { /* Position to the left of the anchor. */
+ right: anchor(--a1 left);
+ top: anchor(--a1 top);
+ }
+ @try { /* Position to the right of the anchor with the wider width than CB. */
+ left: anchor(--a1 right);
+ top: anchor(--a1 top);
+ width: 250px;
+ }
+ @try { /* Position to the right of the anchor. This entry should succeed. */
+ left: anchor(--a1 right);
+ top: anchor(--a1 top);
+ }
+ @try { /* Zero-sized, the last entry wins if none succeeded. */
+ left: 0;
+ top: 0;
+ width: 0;
+ height: 0;
+ }
+}
+</style>
+<body onload="checkLayout('.target')">
+ <div>
+ <div class="spacer" style="height: 10px"></div>
+ <div class="grid cb">
+ <div class="item">1</div>
+ <div class="item">2</div>
+ <div class="item">3</div>
+ <div class="item">4</div>
+ <div class="item">5</div>
+ <div class="item">
+ <div class="spacer" style="height: 20px"></div>
+ <div class="anchor1"></div>
+ </div>
+ <div class="item">7</div>
+ <div class="item">8</div>
+ <div class="item">9</div>
+ <div class="item">10</div>
+ <div class="item">11</div>
+ <div class="item">12</div>
+ <div class="item">13</div>
+ <div class="item">14</div>
+ <div class="item">15</div>
+ <div class="item">16</div>
+
+ <div class="target"
+ data-offset-x=135 data-offset-y=70
+ data-expected-height=100></div>
+ </div>
+ </div>
+</body>
diff --git a/testing/web-platform/tests/css/css-anchor-position/position-fallback-tree-scoped.html b/testing/web-platform/tests/css/css-anchor-position/position-fallback-tree-scoped.html
new file mode 100644
index 0000000000..955c3a7c1b
--- /dev/null
+++ b/testing/web-platform/tests/css/css-anchor-position/position-fallback-tree-scoped.html
@@ -0,0 +1,159 @@
+<!DOCTYPE html>
+<title>CSS Anchor Positioning Test: @position-fallback - tree scoped names</title>
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/#fallback-rule">
+<link rel="help" href="https://drafts.csswg.org/css-scoping/#shadow-names">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/declarative-shadow-dom-polyfill.js"></script>
+
+<style>
+ body { margin: 0; }
+
+ @position-fallback --doc {
+ @try {
+ left: 100px;
+ }
+ }
+
+ .abs { position: absolute; }
+
+ #doc_pf_doc { position-fallback: --doc; }
+ #doc_pf_outer { position-fallback: --outer; }
+ #doc_pf_inner { position-fallback: --inner; }
+</style>
+
+<div id="doc_pf_doc" class="abs"></div>
+<div id="doc_pf_outer" class="abs"></div>
+<div id="doc_pf_inner" class="abs"></div>
+<div id="outer_host">
+ <template shadowroot="open">
+ <style>
+ @position-fallback --outer {
+ @try {
+ left: 200px;
+ }
+ }
+
+ .abs { position: absolute; }
+
+ #outer_pf_doc { position-fallback: --doc; }
+ #outer_pf_outer { position-fallback: --outer; }
+ #outer_pf_inner { position-fallback: --inner; }
+ </style>
+ <div id="outer_pf_doc" class="abs"></div>
+ <div id="outer_pf_outer" class="abs"></div>
+ <div id="outer_pf_inner" class="abs"></div>
+ <div id="inner_host">
+ <template shadowroot="open">
+ <style>
+ @position-fallback --inner {
+ @try {
+ left: 300px;
+ }
+ }
+
+ .abs { position: absolute; }
+
+ #inner_pf_doc { position-fallback: --doc; }
+ #inner_pf_outer { position-fallback: --outer; }
+ #inner_pf_inner { position-fallback: --inner; }
+ </style>
+ <div id="inner_pf_doc" class="abs"></div>
+ <div id="inner_pf_outer" class="abs"></div>
+ <div id="inner_pf_inner" class="abs"></div>
+ </template>
+ </div>
+ </template>
+</div>
+
+
+<style>
+ @position-fallback --host-slot-part {
+ @try {
+ left: 1px;
+ }
+ }
+ #host_slotted_part::part(part) {
+ position-fallback: --host-slot-part;
+ }
+</style>
+<div id="host_slotted_part">
+ <template shadowroot="open">
+ <style>
+ @position-fallback --host-slot-part {
+ @try {
+ left: 2px;
+ }
+ }
+ ::slotted(#slotted), :host {
+ position: absolute;
+ position-fallback: --host-slot-part;
+ }
+ #part {
+ position: absolute;
+ }
+ </style>
+ <div id="part" part="part"></div>
+ <slot></slot>
+ </template>
+ <div id="slotted"></div>
+</div>
+
+
+<script>
+ setup(() => {
+ polyfill_declarative_shadow_dom(outer_host);
+ polyfill_declarative_shadow_dom(host_slotted_part);
+ });
+
+ test(() => {
+ assert_equals(doc_pf_doc.offsetLeft, 100);
+ }, "Document position-fallback matches @position-fallback in document scope");
+
+ test(() => {
+ assert_equals(doc_pf_outer.offsetLeft, 0);
+ }, "Document position-fallback does not match @position-fallback in #outer_host scope");
+
+ test(() => {
+ assert_equals(doc_pf_inner.offsetLeft, 0);
+ }, "Document position-fallback does not match @position-fallback in #inner_host scope");
+
+ const outer_root = outer_host.shadowRoot;
+ const inner_root = outer_root.querySelector("#inner_host").shadowRoot;
+
+ test(() => {
+ assert_equals(outer_root.querySelector("#outer_pf_doc").offsetLeft, 100);
+ }, "Outer position-fallback matches @position-fallback in document scope");
+
+ test(() => {
+ assert_equals(outer_root.querySelector("#outer_pf_outer").offsetLeft, 200);
+ }, "Outer position-fallback matches @position-fallback in #outer_host scope");
+
+ test(() => {
+ assert_equals(outer_root.querySelector("#outer_pf_inner").offsetLeft, 0);
+ }, "Outer position-fallback does not match @position-fallback in #inner_host scope");
+
+ test(() => {
+ assert_equals(inner_root.querySelector("#inner_pf_doc").offsetLeft, 100)
+ }, "Inner position-fallback matches @position-fallback in document scope");
+
+ test(() => {
+ assert_equals(inner_root.querySelector("#inner_pf_outer").offsetLeft, 200);
+ }, "Inner position-fallback matches @position-fallback in #outer_host scope");
+
+ test(() => {
+ assert_equals(inner_root.querySelector("#inner_pf_inner").offsetLeft, 300);
+ }, "Inner position-fallback matches @position-fallback in #inner_host scope");
+
+ test(() => {
+ assert_equals(host_slotted_part.offsetLeft, 2);
+ }, "@position-fallback from same scope as :host rule");
+
+ test(() => {
+ assert_equals(slotted.offsetLeft, 2);
+ }, "@position-fallback from same scope as ::slotted() rule");
+
+ test(() => {
+ assert_equals(host_slotted_part.shadowRoot.querySelector("#part").offsetLeft, 1);
+ }, "@position-fallback from same scope as ::part() rule");
+</script>
diff --git a/testing/web-platform/tests/css/css-anchor-position/reference/anchor-scroll-fixedpos-ref.html b/testing/web-platform/tests/css/css-anchor-position/reference/anchor-scroll-fixedpos-ref.html
new file mode 100644
index 0000000000..e73354df72
--- /dev/null
+++ b/testing/web-platform/tests/css/css-anchor-position/reference/anchor-scroll-fixedpos-ref.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<style>
+body {
+ margin: 0;
+ height: 2000px;
+}
+
+div {
+ width: 100px;
+ height: 100px;
+}
+
+#anchor {
+ margin: 300px;
+ background: orange;
+}
+
+#anchored {
+ position: fixed;
+ left: 400px;
+ top: 100px;
+ background: green;
+}
+
+</style>
+
+<div id="anchor"></div>
+<div id="anchored"></div>
+
+<script>
+document.documentElement.scrollTop = 200;
+</script>
diff --git a/testing/web-platform/tests/css/css-anchor-position/reference/anchor-scroll-nested-ref.html b/testing/web-platform/tests/css/css-anchor-position/reference/anchor-scroll-nested-ref.html
new file mode 100644
index 0000000000..6190258f3c
--- /dev/null
+++ b/testing/web-platform/tests/css/css-anchor-position/reference/anchor-scroll-nested-ref.html
@@ -0,0 +1,74 @@
+<!DOCTYPE html>
+<title>Tests anchor-scroll with nested scroll containers</title>
+<link rel="author" href="mailto:xiaochengh@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/">
+<style>
+body {
+ margin: 0;
+ width: 1500px;
+ height: 1500px;
+ position: relative;
+}
+
+#outer-scroller {
+ margin: 500px;
+ width: 350px;
+ height: 350px;
+ outline: 1px solid black;
+ overflow: scroll;
+}
+
+#inner-scroller {
+ margin: 100px;
+ width: 250px;
+ height: 250px;
+ outline: 1px solid black;
+ overflow: scroll;
+}
+
+#anchor {
+ margin: 200px;
+ width: 50px;
+ height: 50px;
+ background-color: green;
+}
+
+.anchored {
+ position: fixed;
+ width: 50px;
+ height: 50px;
+ left: 250px;
+}
+
+.above {
+ top: 200px;
+ background-color: red;
+}
+
+.below {
+ top: 300px;
+ background-color: yellow;
+}
+</style>
+
+<div id="outer-scroller">
+ <div id="inner-scroller">
+ <div id="anchor"></div>
+ <div class="anchored above"></div>
+ </div>
+</div>
+
+<div class="anchored below"></div>
+
+<script>
+document.documentElement.scrollTop = 400;
+document.documentElement.scrollLeft = 400;
+
+let outerScroller = document.getElementById('outer-scroller');
+outerScroller.scrollTop = 50;
+outerScroller.scrollLeft = 50;
+
+let innerScroller = document.getElementById('inner-scroller');
+innerScroller.scrollTop = 100;
+innerScroller.scrollLeft = 100;
+</script>
diff --git a/testing/web-platform/tests/css/css-anchor-position/reference/anchor-scroll-ref.html b/testing/web-platform/tests/css/css-anchor-position/reference/anchor-scroll-ref.html
new file mode 100644
index 0000000000..7935f3823f
--- /dev/null
+++ b/testing/web-platform/tests/css/css-anchor-position/reference/anchor-scroll-ref.html
@@ -0,0 +1,61 @@
+<!DOCTYPE html>
+<title>Basic of anchor-scroll: anchored elements should be "pinned" to the anchor when anchor is scrolled</title>
+<link rel="stylesheet" href="/fonts/ahem.css">
+<style>
+body {
+ font: 20px/1 Ahem;
+ margin: 0;
+}
+
+#scroll-container {
+ width: 400px;
+ height: 400px;
+ overflow: scroll;
+}
+
+#scroll-contents {
+ width: 1000px;
+ height: 1000px;
+ position: relative;
+}
+
+#placefiller-above-anchor {
+ height: 500px;
+}
+
+#placefiller-before-anchor {
+ display: inline-block;
+ width: 500px;
+}
+
+#inner-anchored {
+ color: green;
+ position: fixed;
+ left: 70px;
+ top: 180px;
+}
+
+#outer-anchored {
+ color: yellow;
+ position: fixed;
+ left: 70px;
+ top: 220px;
+}
+</style>
+
+<div id="scroll-container">
+ <div id="scroll-contents">
+ <div id="placefiller-above-anchor"></div>
+ <div id="placefiller-before-anchor"></div>
+ <span id="anchor">anchor</span>
+ </div>
+</div>
+
+<div id="inner-anchored">inner-anchored</div>
+<div id="outer-anchored">outer-anchored</div>
+
+<script>
+const scroller = document.getElementById('scroll-container');
+scroller.scrollTop = 300;
+scroller.scrollLeft = 450;
+</script>
diff --git a/testing/web-platform/tests/css/css-anchor-position/reference/anchor-scroll-update-005-ref.html b/testing/web-platform/tests/css/css-anchor-position/reference/anchor-scroll-update-005-ref.html
new file mode 100644
index 0000000000..b0c3a820f8
--- /dev/null
+++ b/testing/web-platform/tests/css/css-anchor-position/reference/anchor-scroll-update-005-ref.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<style>
+ #cb {
+ position: absolute;
+ inset: 0;
+ }
+ #scroller {
+ margin-top: 300px;
+ overflow-y: scroll;
+ height: 200px;
+ }
+ #spacer { height: 400px; }
+ #anchor { anchor-name: --a; }
+ #anchored {
+ position: absolute;
+ width: 100px;
+ height: 100px;
+ background-color: green;
+ top: 100px;
+ left: 0;
+ }
+</style>
+<div id="cb">
+ <div id="scroller">
+ <div id="anchor"></div>
+ <div id="spacer"></div>
+ </div>
+ <div id="anchored"></div>
+</div>
+<script>
+const scroller = document.getElementById('scroller');
+scroller.scrollTop = 200;
+</script>
+
diff --git a/testing/web-platform/tests/css/css-anchor-position/reference/anchor-scroll-update-006-ref.html b/testing/web-platform/tests/css/css-anchor-position/reference/anchor-scroll-update-006-ref.html
new file mode 100644
index 0000000000..c7fbb57e76
--- /dev/null
+++ b/testing/web-platform/tests/css/css-anchor-position/reference/anchor-scroll-update-006-ref.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<style>
+ #cb {
+ position: absolute;
+ inset: 0;
+ }
+ #scroller {
+ margin-top: 300px;
+ overflow-y: scroll;
+ height: 100px;
+ }
+ #spacer { height: 300px; }
+ #anchor { anchor-name: --a; }
+ #anchored {
+ position: absolute;
+ width: 100px;
+ height: 100px;
+ background-color: green;
+ top: 100px;
+ left: 0;
+ }
+</style>
+<div id="cb">
+ <div id="scroller">
+ <div id="anchor"></div>
+ <div id="spacer"></div>
+ </div>
+ <div id="anchored"></div>
+</div>
+<script>
+const scroller = document.getElementById('scroller');
+scroller.scrollTop = 200;
+</script>
+
diff --git a/testing/web-platform/tests/css/css-anchor-position/reference/anchor-scroll-vlr-ref.html b/testing/web-platform/tests/css/css-anchor-position/reference/anchor-scroll-vlr-ref.html
new file mode 100644
index 0000000000..cbb249e150
--- /dev/null
+++ b/testing/web-platform/tests/css/css-anchor-position/reference/anchor-scroll-vlr-ref.html
@@ -0,0 +1,70 @@
+<!DOCTYPE html>
+<title>Tests that anchor-scroll works in vertical-lr writing mode</title>
+<link rel="author" href="mailto:xiaochengh@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/">
+<link rel="stylesheet" href="/fonts/ahem.css">
+<style>
+:root {
+ overflow: clip;
+}
+
+body {
+ font: 20px/1 Ahem;
+ margin: 0;
+ writing-mode: vertical-lr;
+ white-space: nowrap;
+}
+
+#scroll-container {
+ width: 400px;
+ height: 400px;
+ overflow: scroll;
+}
+
+#scroll-contents {
+ width: 1000px;
+ height: 1000px;
+ position: relative;
+}
+
+#placefiller-above-anchor {
+ width: 480px;
+}
+
+#placefiller-before-anchor {
+ display: inline-block;
+ height: 500px;
+}
+
+#anchor {
+ anchor-name: --anchor;
+}
+
+#inner-anchored {
+ color: green;
+ margin-top: 520px;
+}
+
+#outer-anchored {
+ color: yellow;
+ margin-top: 520px;
+}
+</style>
+
+<div style="position: relative;">
+ <div id="scroll-container">
+ <div id="scroll-contents">
+ <div id="placefiller-above-anchor"></div>
+ <div id="outer-anchored">outer-anchored</div>
+ <div id="placefiller-before-anchor"></div>
+ <span id="anchor">anchor</span>
+ <div id="inner-anchored">inner-anchored</div>
+ </div>
+ </div>
+</div>
+
+<script>
+const scroller = document.getElementById('scroll-container');
+scroller.scrollTop = 450;
+scroller.scrollLeft = 300;
+</script>
diff --git a/testing/web-platform/tests/css/css-anchor-position/reference/anchor-scroll-vrl-ref.html b/testing/web-platform/tests/css/css-anchor-position/reference/anchor-scroll-vrl-ref.html
new file mode 100644
index 0000000000..746dfee074
--- /dev/null
+++ b/testing/web-platform/tests/css/css-anchor-position/reference/anchor-scroll-vrl-ref.html
@@ -0,0 +1,70 @@
+<!DOCTYPE html>
+<title>Tests that anchor-scroll works in vertical-rl writing mode</title>
+<link rel="author" href="mailto:xiaochengh@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/#anchor-scroll">
+<link rel="stylesheet" href="/fonts/ahem.css">
+<style>
+:root {
+ overflow: clip;
+}
+
+body {
+ font: 20px/1 Ahem;
+ margin: 0;
+ writing-mode: vertical-rl;
+ white-space: nowrap;
+}
+
+#scroll-container {
+ width: 400px;
+ height: 400px;
+ overflow: scroll;
+}
+
+#scroll-contents {
+ width: 1000px;
+ height: 1000px;
+ position: relative;
+}
+
+#placefiller-above-anchor {
+ width: 480px;
+}
+
+#placefiller-before-anchor {
+ display: inline-block;
+ height: 500px;
+}
+
+#anchor {
+ anchor-name: --anchor;
+}
+
+#inner-anchored {
+ margin-top: 520px;
+ color: green;
+}
+
+#outer-anchored {
+ margin-top: 520px;
+ color: yellow;
+}
+</style>
+
+<div style="position: relative;">
+ <div id="scroll-container">
+ <div id="scroll-contents">
+ <div id="placefiller-above-anchor"></div>
+ <div id="inner-anchored">inner-anchored</div>
+ <div id="placefiller-before-anchor"></div>
+ <span id="anchor">anchor</span>
+ <div id="outer-anchored">outer-anchored</div>
+ </div>
+ </div>
+</div>
+
+<script>
+const scroller = document.getElementById('scroll-container');
+scroller.scrollTop = 450;
+scroller.scrollLeft = -300;
+</script>
diff --git a/testing/web-platform/tests/css/css-anchor-position/reference/sticky-anchor-position-invalid-ref.html b/testing/web-platform/tests/css/css-anchor-position/reference/sticky-anchor-position-invalid-ref.html
new file mode 100644
index 0000000000..3a48755874
--- /dev/null
+++ b/testing/web-platform/tests/css/css-anchor-position/reference/sticky-anchor-position-invalid-ref.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<title>Anchor queries in sticky positioning is invalid</title>
+<style>
+#scroll-container {
+ width: 200px;
+ height: 200px;
+ overflow-y: scroll;
+}
+
+#scroller {
+ height: 400px;
+}
+
+#sticky {
+ position: sticky;
+ height: 150px;
+ background: green;
+}
+</style>
+<div id="scroll-container">
+ <div id="scroller">
+ <div id="sticky">
+ </div>
+ </div>
+</div>
+<script>
+document.getElementById("scroll-container").scrollTop = 50;
+</script>
diff --git a/testing/web-platform/tests/css/css-anchor-position/sticky-anchor-position-invalid.html b/testing/web-platform/tests/css/css-anchor-position/sticky-anchor-position-invalid.html
new file mode 100644
index 0000000000..f7c1e1a374
--- /dev/null
+++ b/testing/web-platform/tests/css/css-anchor-position/sticky-anchor-position-invalid.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<title>Anchor queries in sticky positioning is invalid</title>
+<link rel="author" href="mailto:xiaochengh@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/#queries">
+<link rel="match" href="reference/sticky-anchor-position-invalid-ref.html">
+<style>
+#scroll-container {
+ width: 200px;
+ height: 200px;
+ overflow-y: scroll;
+}
+
+#scroller {
+ height: 400px;
+}
+
+#sticky {
+ position: sticky;
+ height: 150px;
+ background: green;
+ top: anchor(--invalid top); /* should be invalid and treated as auto */
+}
+</style>
+<div id="scroll-container">
+ <div id="scroller">
+ <div id="sticky">
+ </div>
+ </div>
+</div>
+<script>
+document.getElementById("scroll-container").scrollTop = 50;
+</script>
diff --git a/testing/web-platform/tests/css/css-anchor-position/support/green-16x16.png b/testing/web-platform/tests/css/css-anchor-position/support/green-16x16.png
new file mode 100644
index 0000000000..e19a3ffddd
--- /dev/null
+++ b/testing/web-platform/tests/css/css-anchor-position/support/green-16x16.png
Binary files differ
diff --git a/testing/web-platform/tests/css/css-anchor-position/support/test-common.js b/testing/web-platform/tests/css/css-anchor-position/support/test-common.js
new file mode 100644
index 0000000000..5ef7a951b4
--- /dev/null
+++ b/testing/web-platform/tests/css/css-anchor-position/support/test-common.js
@@ -0,0 +1,27 @@
+// Asserts that the anchored element is at the top/bottom/left/right of the
+// anchor.
+function assert_fallback_position(anchored, anchor, direction) {
+ let anchoredRect = anchored.getBoundingClientRect();
+ let anchorRect = anchor.getBoundingClientRect();
+ let message = `Anchored element should be at the ${direction} of anchor`;
+ switch (direction) {
+ case 'top':
+ assert_equals(anchoredRect.bottom, anchorRect.top, message);
+ return;
+ case 'bottom':
+ assert_equals(anchoredRect.top, anchorRect.bottom, message);
+ return;
+ case 'left':
+ assert_equals(anchoredRect.right, anchorRect.left, message);
+ return;
+ case 'right':
+ assert_equals(anchoredRect.left, anchorRect.right, message);
+ return;
+ default:
+ assert_unreached('unsupported direction');
+ }
+}
+
+async function waitUntilNextAnimationFrame() {
+ return new Promise(resolve => requestAnimationFrame(resolve));
+}