diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 01:47:29 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 01:47:29 +0000 |
commit | 0ebf5bdf043a27fd3dfb7f92e0cb63d88954c44d (patch) | |
tree | a31f07c9bcca9d56ce61e9a1ffd30ef350d513aa /testing/web-platform/tests/css/css-contain/container-queries | |
parent | Initial commit. (diff) | |
download | firefox-esr-0ebf5bdf043a27fd3dfb7f92e0cb63d88954c44d.tar.xz firefox-esr-0ebf5bdf043a27fd3dfb7f92e0cb63d88954c44d.zip |
Adding upstream version 115.8.0esr.upstream/115.8.0esr
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'testing/web-platform/tests/css/css-contain/container-queries')
201 files changed, 9899 insertions, 0 deletions
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/animation-container-size.html b/testing/web-platform/tests/css/css-contain/container-queries/animation-container-size.html new file mode 100644 index 0000000000..fefb721cbc --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/animation-container-size.html @@ -0,0 +1,43 @@ +<!doctype html> +<title>Container Queries - Animating container size</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#animated-containers"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/cq-testcommon.js"></script> +<style> + @keyframes anim { + from { width: 200px; } + to { width: 100px; } + } + #container { + container-type: inline-size; + animation: anim 1s linear paused; + } + #target { + background-color: green; + } + + @container (width: 200px) { + #target { + background-color: blue; + } + } +</style> +<div id=container> + <div id=target> + Test + </div> +</div> +<script> + setup(() => assert_implements_container_queries()); + + test(() => { + assert_equals(getComputedStyle(target).backgroundColor, 'rgb(0, 0, 255)'); + + assert_equals(container.getAnimations().length, 1); + let animation = container.getAnimations()[0]; + animation.currentTime = 500; + + assert_equals(getComputedStyle(target).backgroundColor, 'rgb(0, 128, 0)'); + }, 'Animation affects container query evaluation'); +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/animation-container-type-dynamic.html b/testing/web-platform/tests/css/css-contain/container-queries/animation-container-type-dynamic.html new file mode 100644 index 0000000000..835e8e1be1 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/animation-container-type-dynamic.html @@ -0,0 +1,68 @@ +<!doctype html> +<title>Container Queries - Animated container creating new containers</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#animated-containers"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/cq-testcommon.js"></script> +<style> + @keyframes anim { + from { width: 200px; } + to { width: 300px; } + } + #container { + container-type: inline-size; + animation: anim 1s linear paused; + } + #target { + background-color: red; + } + + #intermediate { + width: 100px; + } + + @container (min-width: 250px) { + #intermediate { + container-type: inline-size; + } + } + + @container (width: 200px) { + #target { + background-color: blue; + } + } + + @container (width: 100px) { + /* Initially queries #container, but later queries #intermediate, when + the other container query starts matching. */ + #target { + background-color: green; + } + } +</style> +<div id=container> + <div id=intermediate> + <div id=target> + Test + </div> + </div> +</div> +<script> + setup(() => assert_implements_container_queries()); + + test(() => { + assert_equals(getComputedStyle(target).backgroundColor, 'rgb(0, 0, 255)'); + + assert_equals(container.getAnimations().length, 1); + let animation = container.getAnimations()[0]; + + animation.currentTime = 600; + assert_equals(getComputedStyle(target).backgroundColor, 'rgb(0, 128, 0)'); + + // Verify that #intermediate is queried by changing its width. The container + // query will stop matching if #intermediate is the queried container. + intermediate.style.width = '110px'; + assert_equals(getComputedStyle(target).backgroundColor, 'rgb(255, 0, 0)'); + }, 'Animated container creating new container'); +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/animation-nested-animation.html b/testing/web-platform/tests/css/css-contain/container-queries/animation-nested-animation.html new file mode 100644 index 0000000000..7f1ae854ae --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/animation-nested-animation.html @@ -0,0 +1,47 @@ +<!DOCTYPE html> +<title>Container Queries - Animations within animating container</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#animated-containers"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/cq-testcommon.js"></script> +<style> + @keyframes outer { + from { width: 100px; } + to { width: 300px; } + } + @keyframes inner { + from { background-color: blue; } + to { background-color: yellow; } + } + #container { + container-type: inline-size; + animation: outer 1s linear paused; + } + #target { + background-color: green; + } + + @container (min-width: 200px) { + #target { + animation: inner 1s linear paused; + } + } +</style> +<div id=container> + <div id=target> + Test + </div> +</div> +<script> + setup(() => assert_implements_container_queries()); + + test(() => { + assert_equals(getComputedStyle(target).backgroundColor, 'rgb(0, 128, 0)'); + + assert_equals(container.getAnimations().length, 1); + let animation = container.getAnimations()[0]; + animation.currentTime = 600; + + assert_equals(getComputedStyle(target).backgroundColor, 'rgb(0, 0, 255)'); + }, 'Animated container can create inner animation'); +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/animation-nested-transition.html b/testing/web-platform/tests/css/css-contain/container-queries/animation-nested-transition.html new file mode 100644 index 0000000000..934f995a97 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/animation-nested-transition.html @@ -0,0 +1,44 @@ +<!doctype html> +<title>Container Queries - Animated container with inner transition</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#animated-containers"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/cq-testcommon.js"></script> +<style> + @keyframes outer { + from { width: 100px; } + to { width: 300px; } + } + #container { + container-type: inline-size; + animation: outer 1s linear paused; + } + #target { + background-color: rgb(100, 100, 100); + } + + @container (min-width: 200px) { + #target { + transition: background-color 100s steps(2, start); + background-color: rgb(200, 200, 200); + } + } +</style> +<div id=container> + <div id=target> + Test + </div> +</div> +<script> + setup(() => assert_implements_container_queries()); + + test(() => { + assert_equals(getComputedStyle(target).backgroundColor, 'rgb(100, 100, 100)'); + + assert_equals(container.getAnimations().length, 1); + let animation = container.getAnimations()[0]; + animation.currentTime = 600; + + assert_equals(getComputedStyle(target).backgroundColor, 'rgb(150, 150, 150)'); + }, 'Animated container size triggers transition'); +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/aspect-ratio-feature-evaluation.html b/testing/web-platform/tests/css/css-contain/container-queries/aspect-ratio-feature-evaluation.html new file mode 100644 index 0000000000..843f34732b --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/aspect-ratio-feature-evaluation.html @@ -0,0 +1,49 @@ +<!doctype html> +<title>@container queries with aspect-ratio</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#aspect-ratio"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/cq-testcommon.js"></script> +<style> + .container { + width: 100px; + height: 100px; + } + #inline-size { container-type: inline-size; } + #size { container-type: size; } + span { color: red } + @container (min-aspect-ratio: 1 / 1000) { + span { color: green; } + } + @container (min-aspect-ratio: 2 / 1) { + span { background-color: lime; } + } +</style> +<div id="inline-size" class="container"><span></span></div> +<div id="size" class="container"><span></span></div> +<script> + setup(() => assert_implements_container_queries()); + + const red = "rgb(255, 0, 0)"; + const green = "rgb(0, 128, 0)"; + const lime = "rgb(0, 255, 0)"; + const transparent = "rgba(0, 0, 0, 0)"; + + const inline_span = document.querySelector("#inline-size > span"); + const size_span = document.querySelector("#size > span"); + + test(() => { + assert_equals(getComputedStyle(inline_span).color, red, + "Should not match for inline-size containment"); + assert_equals(getComputedStyle(size_span).color, green, + "Should match for block-size containment"); + assert_equals(getComputedStyle(size_span).backgroundColor, transparent, + "Square should not match 2/1 min-ratio"); + }, "@container queries with aspect-ratio and size containment"); + + test(() => { + document.querySelector("#size").style.width = "200px"; + assert_equals(getComputedStyle(size_span).backgroundColor, lime, + "Should match 2/1 min-ratio"); + }, "@container query with aspect-ratio change after resize"); +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/at-container-parsing.html b/testing/web-platform/tests/css/css-contain/container-queries/at-container-parsing.html new file mode 100644 index 0000000000..b0196b5e5a --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/at-container-parsing.html @@ -0,0 +1,195 @@ +<!doctype html> +<title>@container: parsing</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-rule"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/cq-testcommon.js"></script> +<div style="container-name:name;container-type:size; width:100px; height:100px"> + <main id=main></main> +</div> +<script> + setup(() => assert_implements_container_queries()); + + function cleanup_main() { + while (main.firstChild) + main.firstChild.remove(); + } + + function set_style(text) { + let style = document.createElement('style'); + style.innerText = text; + main.append(style); + return style; + } + + function test_rule_valid(query) { + test(t => { + t.add_cleanup(cleanup_main); + let style = set_style(`@container ${query} {}`); + assert_equals(style.sheet.rules.length, 1); + }, query); + } + + function test_condition_invalid(condition) { + test(t => { + t.add_cleanup(cleanup_main); + let style = set_style(`@container name ${condition} {}`); + assert_equals(style.sheet.rules.length, 0); + }, condition); + } + + // Tests that 1) the condition parses, and 2) is either "unknown" or not, as + // specified. + function test_condition_valid(condition, unknown) { + test(t => { + t.add_cleanup(cleanup_main); + let style = set_style(` + @container name ${condition} {} + @container name (${condition}) or (not (${condition})) { main { --match:true; } } + `); + assert_equals(style.sheet.rules.length, 2); + const expected = unknown ? '' : 'true'; + assert_equals(getComputedStyle(main).getPropertyValue('--match'), expected); + }, condition); + } + + function test_condition_known(condition) { + test_condition_valid(condition, false /* unknown */); + } + + function test_condition_unknown(condition) { + test_condition_valid(condition, true /* unknown */); + } + + function test_container_name_invalid(container_name) { + test(t => { + t.add_cleanup(cleanup_main); + let style = set_style(`@container ${container_name} not (width) {}`); + assert_equals(style.sheet.rules.length, 0); + }, `Container name: ${container_name}`); + } + + function test_container_name_valid(container_name) { + test(t => { + t.add_cleanup(cleanup_main); + let style = set_style(`@container ${container_name} not (width) {}`); + assert_equals(style.sheet.rules.length, 1); + }, `Container name: ${container_name}`); + } + + test_condition_known('(width)'); + test_condition_known('(min-width: 0px)'); + test_condition_known('(max-width: 0px)'); + test_condition_known('(height)'); + test_condition_known('(min-height: 0px)'); + test_condition_known('(max-height: 0px)'); + test_condition_known('(aspect-ratio)'); + test_condition_known('(min-aspect-ratio: 1/2)'); + test_condition_known('(max-aspect-ratio: 1/2)'); + test_condition_known('(orientation: portrait)'); + test_condition_known('(inline-size)'); + test_condition_known('(min-inline-size: 0px)'); + test_condition_known('(max-inline-size: 0px)'); + test_condition_known('(block-size)'); + test_condition_known('(min-block-size: 0px)'); + test_condition_known('(max-block-size: 0px)'); + + test_condition_known('(width: 100px)'); + test_condition_known('((width: 100px))'); + test_condition_known('(not (width: 100px))'); + test_condition_known('((width: 100px) and (height: 100px))'); + test_condition_known('(((width: 40px) or (width: 50px)) and (height: 100px))'); + test_condition_known('((width: 100px) and ((height: 40px) or (height: 50px)))'); + test_condition_known('(((width: 40px) and (height: 50px)) or (height: 100px))'); + test_condition_known('((width: 50px) or ((width: 40px) and (height: 50px)))'); + test_condition_known('((width: 100px) and (not (height: 100px)))'); + test_condition_known('(width < 100px)'); + test_condition_known('(width <= 100px)'); + test_condition_known('(width = 100px)'); + test_condition_known('(width > 100px)'); + test_condition_known('(width >= 100px)'); + test_condition_known('(100px < width)'); + test_condition_known('(100px <= width)'); + test_condition_known('(100px = width)'); + test_condition_known('(100px > width)'); + test_condition_known('(100px >= width)'); + test_condition_known('(100px < width < 200px)'); + test_condition_known('(100px < width <= 200px)'); + test_condition_known('(100px <= width < 200px)'); + test_condition_known('(100px > width > 200px)'); + test_condition_known('(100px > width >= 200px)'); + test_condition_known('(100px >= width > 200px)'); + + test_condition_known('(width: calc(10px))'); + test_condition_known('(width: calc(10em))'); + test_condition_known('(width: calc(10px + 10em))'); + test_condition_known('(width < calc(10px + 10em))'); + test_condition_known('(width < max(10px, 10em))'); + test_condition_known('(calc(10px + 10em) < width)'); + test_condition_known('(calc(10px + 10em) < width < max(30px, 30em))'); + test_condition_known('(width: 100px) and (height: 100px)'); + test_condition_known('(width: 100px) or (height: 100px)'); + test_condition_known('not (width: 100px)'); + + test_condition_unknown('foo(width)'); + test_condition_unknown('size(width)'); + test_condition_unknown('(asdf)'); + test_condition_unknown('(resolution > 100dpi)'); + test_condition_unknown('(resolution: 150dpi)'); + test_condition_unknown('(resolution: calc(2x))'); + test_condition_unknown('(color)'); + test_condition_unknown('(min-color: 1)'); + test_condition_unknown('(color-index >= 1)'); + test_condition_unknown('size(grid)'); + test_condition_unknown('(grid)'); + test_condition_unknown('(width == 100px)'); + test_condition_unknown('(100px == width)'); + test_condition_unknown('(100px = width = 200px)'); + test_condition_unknown('(100px < width > 200px)'); + test_condition_unknown('(100px <= width >= 200px)'); + test_condition_unknown('(100px <= width > 200px)'); + test_condition_unknown('(100px < width >= 200px)'); + test_condition_unknown('(100px : width : 200px)'); + + test_condition_invalid('screen'); + test_condition_invalid('print'); + test_condition_invalid('not print'); + test_condition_invalid('only print'); + test_condition_invalid('screen and (width: 100px)'); + test_condition_invalid('screen or (width: 100px)'); + test_condition_invalid('not screen and (width: 100px)'); + test_condition_invalid('not screen or (width: 100px)'); + test_condition_invalid('(width: 100px), (height: 100px)'); + test_condition_invalid('foo (width: 100px)'); + + test_rule_valid('name not (width <= 500px)'); + test_rule_valid('not (width <= 500px)'); + + test_container_name_valid('foo'); + test_container_name_valid(' foo'); + test_container_name_valid(' foo '); + test_container_name_valid('normal'); + test_container_name_valid('Normal'); + test_container_name_valid('auto'); + test_container_name_valid('Auto'); + + test_container_name_invalid('foo foo'); + test_container_name_invalid('1px'); + test_container_name_invalid('50gil'); + test_container_name_invalid('name(foo)'); + test_container_name_invalid('type(inline-size)'); + test_container_name_invalid('"foo"'); + test_container_name_invalid('"inherit"'); + test_container_name_invalid('inherit'); + test_container_name_invalid('INITIAL'); + test_container_name_invalid('Unset'); + test_container_name_invalid('deFAULT'); + test_container_name_invalid('none'); + test_container_name_invalid('None'); + test_container_name_invalid('and'); + test_container_name_invalid('or'); + test_container_name_invalid('not'); + test_container_name_invalid('And'); + test_container_name_invalid('oR'); + test_container_name_invalid('nOt'); +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/at-container-serialization.html b/testing/web-platform/tests/css/css-contain/container-queries/at-container-serialization.html new file mode 100644 index 0000000000..141062a8d4 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/at-container-serialization.html @@ -0,0 +1,74 @@ +<!doctype html> +<title>CSS Container Queries: @container serialization</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-queries"> +<link rel="help" href="https://drafts.csswg.org/cssom/#serialize-a-css-rule"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/cq-testcommon.js"></script> +<style id="testSheet"> + @container (width=100px) { + @container \!-name (inline-size > 200px ) { + #id { color: lime } + } + #id { color: green } + } + @container ( wiDTh ) { } + @container (width:100px) { } + @container (min-width: 100px) { } + @container ( MAX-WIDTH:100px ) { } + @container (width > 100px) { } + @container (width < 100px) { } + @container (widTH >= 100px) { } + @container (width <= 100px) { } + @container (10px < width < 100px) { } + @container (10px <= width <= 100px) { } + @container (100px>WIDTH>10px) { } + @container ( 100px >= width >= 10px ) { } + @container (calc(1em + 1px) >= width >= max(10em, 10px)) { } +</style> +<script> + setup(() => assert_implements_container_queries()); + + let rules = testSheet.sheet.cssRules; + + test(() => { + assert_equals(rules.length, 14); + assert_equals(rules[0].cssRules.length, 2); + + assert_equals(rules[0].conditionText, "(width = 100px)"); + assert_equals(rules[0].cssRules[0].conditionText, "\\!-name (inline-size > 200px)"); + }, "Serialization of conditionText"); + + test(() => { + assert_equals(rules[0].cssRules[0].cssText, "@container \\!-name (inline-size > 200px) {\n #id { color: lime; }\n}"); + }, "Serialization of inner @container rule"); + + test(() => { + assert_equals(rules[0].cssText, "@container (width = 100px) {\n @container \\!-name (inline-size > 200px) {\n #id { color: lime; }\n}\n #id { color: green; }\n}"); + }, "Serialization of nested @container rule"); + + test(() => { + assert_equals(rules[1].conditionText, "(width)"); + }, "Serialization of boolean condition syntax"); + + test(() => { + assert_equals(rules[2].conditionText, "(width: 100px)"); + assert_equals(rules[3].conditionText, "(min-width: 100px)"); + assert_equals(rules[4].conditionText, "(max-width: 100px)"); + }, "Serialization of colon condition syntax"); + + test(() => { + assert_equals(rules[5].conditionText, "(width > 100px)"); + assert_equals(rules[6].conditionText, "(width < 100px)"); + assert_equals(rules[7].conditionText, "(width >= 100px)"); + assert_equals(rules[8].conditionText, "(width <= 100px)"); + assert_equals(rules[9].conditionText, "(10px < width < 100px)"); + assert_equals(rules[10].conditionText, "(10px <= width <= 100px)"); + assert_equals(rules[11].conditionText, "(100px > width > 10px)"); + assert_equals(rules[12].conditionText, "(100px >= width >= 10px)"); + }, "Serialization of range condition syntax"); + + test(() => { + assert_equals(rules[13].conditionText, "(calc(1em + 1px) >= width >= max(10em, 10px))"); + }, "Serialization of calc()"); +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/at-container-style-parsing.html b/testing/web-platform/tests/css/css-contain/container-queries/at-container-style-parsing.html new file mode 100644 index 0000000000..36fda2e366 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/at-container-style-parsing.html @@ -0,0 +1,75 @@ +<!doctype html> +<title>@container: style queries parsing</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-rule"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/cq-testcommon.js"></script> +<div style="container-name:name"> + <main id="main"></main> +</div> +<script> + setup(() => assert_implements_container_queries()); + + function cleanup_main() { + while (main.firstChild) + main.firstChild.remove(); + } + + function set_style(text) { + let style = document.createElement('style'); + style.innerText = text; + main.append(style); + return style; + } + + function test_rule_valid(query) { + test(t => { + t.add_cleanup(cleanup_main); + let style = set_style(`@container ${query} {}`); + assert_equals(style.sheet.rules.length, 1); + }, query); + } + + function test_condition_invalid(condition) { + test(t => { + t.add_cleanup(cleanup_main); + let style = set_style(`@container name ${condition} {}`); + assert_equals(style.sheet.rules.length, 0); + }, condition); + } + + // Tests that 1) the condition parses, and 2) is either "unknown" or not, as + // specified. + function test_condition_valid(condition, unknown) { + test(t => { + t.add_cleanup(cleanup_main); + let style = set_style(` + @container name ${condition} {} + @container name (${condition}) or (not (${condition})) { main { --match:true; } } + `); + assert_equals(style.sheet.rules.length, 2); + const expected = unknown ? '' : 'true'; + assert_equals(getComputedStyle(main).getPropertyValue('--match'), expected); + }, condition); + } + + function test_condition_known(condition) { + test_condition_valid(condition, false /* unknown */); + } + + function test_condition_unknown(condition) { + test_condition_valid(condition, true /* unknown */); + } + + test_condition_known('style(--my-prop: foo)'); + test_condition_known('style(--my-prop: foo - bar ())'); + test_condition_known('style(not ((--foo: calc(10px + 2em)) and ((--foo: url(x)))))'); + test_condition_known('style((--foo: bar) or (--bar: 10px))'); + test_condition_known('style(--my-prop:)'); + test_condition_known('style(--my-prop: )'); + test_condition_known('style(--foo: bar !important)'); + test_condition_known('style(--foo)'); + + test_condition_unknown('style(--foo: bar;)'); + test_condition_unknown('style(style(--foo: bar))'); +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/at-container-style-serialization.html b/testing/web-platform/tests/css/css-contain/container-queries/at-container-style-serialization.html new file mode 100644 index 0000000000..a4fb25378c --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/at-container-style-serialization.html @@ -0,0 +1,38 @@ +<!doctype html> +<title>CSS Container Queries: style() conditionText serialization</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-queries"> +<link rel="help" href="https://drafts.csswg.org/cssom/#serialize-a-css-rule"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/cq-testcommon.js"></script> +<style id="testSheet"> + @container style( --foo:bar) { } + @container STyle(--foo: ) { } + @container STyle(--foo:) { } + @container STyle(--foo) { } + @container style( ( --FOO: BAR) OR ( prop: val ) ) { } + @container style (--foo: bar) { } + @container style(--foo: bar baz) { } + @container style(--foo:2.100 ) { } +</style> +<script> + setup(() => { + assert_implements_container_queries(); + assert_equals(testSheet.sheet.cssRules.length, 8); + }); + + const tests = [ + ["style(--foo: bar)", "Normalize spaces"], + ["style(--foo: )", "Empty declaration value - spaces"], + ["style(--foo: )", "Empty declaration value"], + ["style(--foo)", "No declaration value"], + ["style((--FOO: BAR) or ( prop: val ))", "Unknown CSS property after 'or'"], + ["style (--foo: bar)", "Not a style function with space before '('"], + ["style(--foo: bar baz)", "Spaces preserved in custom property value"], + ["style(--foo: 2.100)", "Original string number in custom property value"] + ].map((e, i) => [testSheet.sheet.cssRules[i], ...e]); + + tests.forEach((t) => { + test(() => assert_equals(t[0].conditionText, t[1]), t[2]); + }); +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/auto-scrollbars.html b/testing/web-platform/tests/css/css-contain/container-queries/auto-scrollbars.html new file mode 100644 index 0000000000..9cf797186c --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/auto-scrollbars.html @@ -0,0 +1,53 @@ +<!doctype html> +<title>CSS Container Queries Test: scrollbar stability for @container queries and overflow:auto</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-queries"> +<link rel="help" href="https://drafts.csswg.org/css-overflow-3/#scrollbar-layout"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/cq-testcommon.js"></script> +<style> + #scroller { + height: 100px; + width: 100px; + overflow-y: auto; + } + #container { + container-type: inline-size; + } + #inner { + height: 100px; + border-bottom: 1px solid red; + } + @container (max-width: 99px) { + #inner { + height: 50px; + } + } +</style> +<div id="precondition" style="width:100px;height:100px;overflow:scroll"></div> +<div id="scroller"> + <div id="container"> + <div id="inner"></div> + </div> +</div> +<script> + setup(() => { + assert_implements_container_queries(); + assert_implements_optional(precondition.clientWidth < 100, + "Tests do not work with overlay scrollbars"); + }); + + test(() => { + assert_less_than(scroller.clientWidth, 100, "Expects a vertical scrollbar"); + assert_equals(getComputedStyle(inner).height, "50px", + "Layout with a scrollbar means the container query applies"); + }, "Initial layout - expecting a scrollbar without overflowing content instead of overflowing content without a scrollbar"); + + test(() => { + inner.style.borderBottomWidth = "2px"; + assert_less_than(scroller.clientWidth, 100, "Expects a vertical scrollbar"); + assert_equals(getComputedStyle(inner).height, "50px", + "Layout with a scrollbar means the container query applies"); + }, "Same result after a reflow"); + +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/backdrop-invalidation.html b/testing/web-platform/tests/css/css-contain/container-queries/backdrop-invalidation.html new file mode 100644 index 0000000000..6a59a2f894 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/backdrop-invalidation.html @@ -0,0 +1,51 @@ +<!doctype html> +<title>Test that ::backdrop responds to container size changes</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#size-container"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/cq-testcommon.js"></script> +<style> + :root { + color: black; + } + + #container { + container-type: size; + width: 200px; + height: 40px; + } + + ::backdrop { + background-color: black; + } + + @container (min-width: 300px) { + ::backdrop { + background-color: green; + } + } +</style> +<main id=container> + <dialog>test</dialog> +</main> +<script> + setup(() => assert_implements_container_queries()); + + let dialog = document.querySelector('dialog'); + + test(function() { + try { + dialog.showModal(); + + assert_equals(getComputedStyle(dialog, '::backdrop').backgroundColor, 'rgb(0, 0, 0)'); + + container.style.width = '300px'; + assert_equals(getComputedStyle(dialog, '::backdrop').backgroundColor, 'rgb(0, 128, 0)'); + + container.style = ''; + assert_equals(getComputedStyle(dialog, '::backdrop').backgroundColor, 'rgb(0, 0, 0)'); + } finally { + dialog.close(); + } + }, 'Pseudo-element ::backdrop responds to container size changes'); +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/calc-evaluation.html b/testing/web-platform/tests/css/css-contain/container-queries/calc-evaluation.html new file mode 100644 index 0000000000..71a5e23764 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/calc-evaluation.html @@ -0,0 +1,32 @@ +<!DOCTYPE html> +<title>CSS Container Queries Test: calc()</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#size-container"> +<link rel="help" href="https://drafts.csswg.org/mediaqueries-4/#units"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/cq-testcommon.js"></script> +<style> + :root { font-size: 10px; } + + /* To make output more readable */ + :root > * { font-size: initial; } + + #container { + container-type: size; + width: 200px; + height: 50px; + } + @container (width = calc(100px + 10rem)) { + #target { color: green; } + } +</style> +<div id=container> + <div id=target></div> +</div> +<script> + setup(() => assert_implements_container_queries()); + + test(() => { + assert_equals(getComputedStyle(target).color, 'rgb(0, 128, 0)'); + }, 'em relative inline-size'); +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/canvas-as-container-001.html b/testing/web-platform/tests/css/css-contain/container-queries/canvas-as-container-001.html new file mode 100644 index 0000000000..f904d1fe24 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/canvas-as-container-001.html @@ -0,0 +1,29 @@ +<!doctype html> +<title>CSS Container Queries Test: Canvas as size container for focusable child</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#size-container"> +<link rel="match" href="/css/reference/ref-filled-green-100px-square-only.html"> +<style> + @supports (container-type: size) { + canvas:focus-within { + border: 50px solid green; + } + canvas { + display: block; + width: 100px; + height: 100px; + box-sizing: border-box; + container-type: size; + } + } +</style> +<p>Test passes if there is a filled green square.</p> +<canvas> + <div id="target" tabIndex="1"></div> +</canvas> +<script> + requestAnimationFrame(()=> { + requestAnimationFrame(()=> { + target.focus(); + }); + }); +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/canvas-as-container-002.html b/testing/web-platform/tests/css/css-contain/container-queries/canvas-as-container-002.html new file mode 100644 index 0000000000..689feeb5ff --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/canvas-as-container-002.html @@ -0,0 +1,30 @@ +<!doctype html> +<title>CSS Container Queries Test: Absolute positioned canvas as size container for focusable child</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#size-container"> +<link rel="match" href="/css/reference/ref-filled-green-100px-square-only.html"> +<style> + @supports (container-type: size) { + canvas:focus-within { + border: 50px solid green; + } + canvas { + display: block; + position: absolute; + width: 100px; + height: 100px; + box-sizing: border-box; + container-type: size; + } + } +</style> +<p>Test passes if there is a filled green square.</p> +<canvas> + <div id="target" tabIndex="1"></div> +</canvas> +<script> + requestAnimationFrame(()=> { + requestAnimationFrame(()=> { + target.focus(); + }); + }); +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/canvas-as-container-003.html b/testing/web-platform/tests/css/css-contain/container-queries/canvas-as-container-003.html new file mode 100644 index 0000000000..74199cc72b --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/canvas-as-container-003.html @@ -0,0 +1,32 @@ +<!doctype html> +<title>CSS Container Queries Test: Canvas as size container for focusable child with display</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#size-container"> +<link rel="match" href="/css/reference/ref-filled-green-100px-square-only.html"> +<style> + @supports (container-type: size) { + canvas:focus-within { + background-color: green; + } + canvas { + display: block; + width: 100px; + height: 100px; + container-type: size; + } + #target { display: none; } + @container (width = 100px) { + #target { display: block; } + } + } +</style> +<p>Test passes if there is a filled green square.</p> +<canvas> + <div id="target" tabIndex="1"></div> +</canvas> +<script> + requestAnimationFrame(()=> { + requestAnimationFrame(()=> { + target.focus(); + }); + }); +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/canvas-as-container-004.html b/testing/web-platform/tests/css/css-contain/container-queries/canvas-as-container-004.html new file mode 100644 index 0000000000..b23846382b --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/canvas-as-container-004.html @@ -0,0 +1,33 @@ +<!doctype html> +<title>CSS Container Queries Test: Absolute positioned canvas as size container for focusable child with display</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#size-container"> +<link rel="match" href="/css/reference/ref-filled-green-100px-square-only.html"> +<style> + @supports (container-type: size) { + canvas:focus-within { + background-color: green; + } + canvas { + display: block; + position: absolute; + width: 100px; + height: 100px; + container-type: size; + } + #target { display: none; } + @container (width = 100px) { + #target { display: block; } + } + } +</style> +<p>Test passes if there is a filled green square.</p> +<canvas> + <div id="target" tabIndex="1"></div> +</canvas> +<script> + requestAnimationFrame(()=> { + requestAnimationFrame(()=> { + target.focus(); + }); + }); +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/canvas-as-container-005.html b/testing/web-platform/tests/css/css-contain/container-queries/canvas-as-container-005.html new file mode 100644 index 0000000000..9132592434 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/canvas-as-container-005.html @@ -0,0 +1,36 @@ +<!doctype html> +<title>CSS Container Queries Test: Canvas as dynamic size container for focusable child with display</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#size-container"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/cq-testcommon.js"></script> +<style> + canvas { + display: block; + width: 100px; + height: 100px; + container-type: size; + } + #target { display: none; } + @container (width = 200px) { + #target { display: block; } + } +</style> +<p>Test passes if there is a filled green square.</p> +<canvas id="canvas"> + <div id="target" tabIndex="1"></div> +</canvas> +<script> + setup(() => assert_implements_container_queries()); + + test(() => { + target.focus(); + assert_not_equals(document.activeElement, target); + }, "Initially display:none, not focusable"); + + test(() => { + canvas.style.width = "200px"; + target.focus(); + assert_equals(document.activeElement, target); + }, "Focusable after container size change"); +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/canvas-as-container-006.html b/testing/web-platform/tests/css/css-contain/container-queries/canvas-as-container-006.html new file mode 100644 index 0000000000..02dbce6275 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/canvas-as-container-006.html @@ -0,0 +1,37 @@ +<!doctype html> +<title>CSS Container Queries Test: Absolute positioned canvas as dynamic size container for focusable child with display</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#size-container"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/cq-testcommon.js"></script> +<style> + canvas { + display: block; + position: absolute; + width: 100px; + height: 100px; + container-type: size; + } + #target { display: none; } + @container (width = 200px) { + #target { display: block; } + } +</style> +<p>Test passes if there is a filled green square.</p> +<canvas id="canvas"> + <div id="target" tabIndex="1"></div> +</canvas> +<script> + setup(() => assert_implements_container_queries()); + + test(() => { + target.focus(); + assert_not_equals(document.activeElement, target); + }, "Initially display:none, not focusable"); + + test(() => { + canvas.style.width = "200px"; + target.focus(); + assert_equals(document.activeElement, target); + }, "Focusable after container size change"); +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/change-display-in-container-ref.html b/testing/web-platform/tests/css/css-contain/container-queries/change-display-in-container-ref.html new file mode 100644 index 0000000000..8dd3b8b2c1 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/change-display-in-container-ref.html @@ -0,0 +1,4 @@ +<!doctype html> +<title>CSS Test Reference</title> +<p>You should see the word PASS below.</p> +PASS diff --git a/testing/web-platform/tests/css/css-contain/container-queries/change-display-in-container.html b/testing/web-platform/tests/css/css-contain/container-queries/change-display-in-container.html new file mode 100644 index 0000000000..8c58d22b7d --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/change-display-in-container.html @@ -0,0 +1,27 @@ +<!doctype html> +<title>CSS Container Queries Test: Change display and box inside a container</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-queries"> +<link rel="match" href="change-display-in-container-ref.html"> +<style> + .fail { display: inline; } + .pass { display: none; } + #container { container-type: size; width: 100px; } + @container (min-width: 200px) { + .fail { display: none; } + .pass { display: inline; } + } +</style> +<p>You should see the word PASS below.</p> +<div id="container"> + <span> + <span class="fail">FAIL</span> + </span> + <span> + <span class="pass">PASS</span> + <span class="fail">FAIL</span> + </span> +</div> +<script> + container.offsetTop; + container.style.width = "auto"; +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/chrome-legacy-skip-recalc.html b/testing/web-platform/tests/css/css-contain/container-queries/chrome-legacy-skip-recalc.html new file mode 100644 index 0000000000..b86a4091a2 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/chrome-legacy-skip-recalc.html @@ -0,0 +1,20 @@ +<!doctype html> +<title>CSS Container Queries Test: Chrome legacy layout skipping style recalc</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#size-container"> +<link rel="help" href="https://crbug.com/1288879"> +<link rel="match" href="/css/reference/pass_if_pass_below.html"> +<style> + #container { + container-type: inline-size; + } + #multicol { + column-count: 1; + } + + @supports not (container-type: inline-size) { + #container { display: none } + } +</style> +<p>Test passes if there is the word "PASS" below.</p> +<div id="container"><span>PASS</span></div> +<span id="multicol"><table></table></span> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/column-spanner-in-container.html b/testing/web-platform/tests/css/css-contain/container-queries/column-spanner-in-container.html new file mode 100644 index 0000000000..d494e28504 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/column-spanner-in-container.html @@ -0,0 +1,41 @@ +<!doctype html> +<title>CSS Container Queries Test: Column-spanner depending on container in column</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#size-container"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/cq-testcommon.js"></script> +<style> + #multicol { + container-type: inline-size; + width: 600px; + columns: 2; + column-gap: 0; + height: 200px; + } + #spanner { height: 100px; } + @container (width = 600px) { + #spanner { + column-span: all; + } + } +</style> +<div id="multicol"> + <div id="spanner"></div> +</div> +<script> + setup(() => assert_implements_container_queries()); + + test(() => { + assert_equals(getComputedStyle(spanner).width, "600px"); + }, "#spanner matching container with column-width 300px, getting column-span:all"); + + test(() => { + multicol.style.width = "500px"; + assert_equals(getComputedStyle(spanner).width, "250px"); + }, "Reducing #multicol width means #spanner no longer gets column-span:all"); + + test(() => { + multicol.style.width = ""; + assert_equals(getComputedStyle(spanner).width, "600px"); + }, "Back to matching 300px and column-span:all"); +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/conditional-container-status.html b/testing/web-platform/tests/css/css-contain/container-queries/conditional-container-status.html new file mode 100644 index 0000000000..e9762f9323 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/conditional-container-status.html @@ -0,0 +1,28 @@ +<!doctype html> +<title>Conditionally removing container status</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-type"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/cq-testcommon.js"></script> +<style> + .parent { width: 300px; } + .child { width: 100px; } + .parent, .child { container-type: inline-size; } + @container (min-width: 200px) { + .child { container-type: initial; } + .grandchild { border: 3px solid green } + } +</style> +<div class="parent"> + <div class="child"> + <div class="grandchild">You should see a green border around this text</div> + </div> +</div> +<script> + setup(() => assert_implements_container_queries()); + + test(function() { + let s = getComputedStyle(document.querySelector('.grandchild')); + assert_equals(s.getPropertyValue('border-color'), 'rgb(0, 128, 0)'); + }, 'Conditionally applying container-type:initial'); +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/container-computed.html b/testing/web-platform/tests/css/css-contain/container-queries/container-computed.html new file mode 100644 index 0000000000..2be304481b --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/container-computed.html @@ -0,0 +1,28 @@ +<!doctype html> +<meta charset="utf-8"> +<title>CSS Containment Test: Computed values of container</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-name"> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-type"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/css/support/computed-testcommon.js"></script> +<script src="support/cq-testcommon.js"></script> +<div id="target"></div> +<script> +setup(() => assert_implements_container_queries()); + +test_computed_value('container', 'initial', 'none'); +test_computed_value('container', 'inherit', 'none'); +test_computed_value('container', 'unset', 'none'); +test_computed_value('container', 'none / inline-size'); +test_computed_value('container', 'none / size'); +test_computed_value('container', 'inline-size / inline-size'); +test_computed_value('container', 'block-size / size'); +test_computed_value('container', 'foo / inline-size'); +test_computed_value('container', 'foo /inline-size', 'foo / inline-size'); +test_computed_value('container', 'foo/ inline-size', 'foo / inline-size'); +test_computed_value('container', 'foo/inline-size', 'foo / inline-size'); +test_computed_value('container', 'FoO / size'); +test_computed_value('container', 'foo bar / size', 'foo bar / size'); +test_computed_value('container', 'foo / normal', 'foo'); +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/container-for-cue-ref.html b/testing/web-platform/tests/css/css-contain/container-queries/container-for-cue-ref.html new file mode 100644 index 0000000000..48b2622363 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/container-for-cue-ref.html @@ -0,0 +1,23 @@ +<!doctype html> +<html class="reftest-wait"> +<head> + <title>CSS Test Reference</title> + <script src="/common/reftest-wait.js"></script> + <style> + video { + contain: size; + width: 200px; + height: 200px; + } + video::cue { background-color: green } + video::cue(b) { color: lime } + </style> +</head> +<body> + <video autoplay onplaying="this.onplaying = null; this.pause(); takeScreenshot();"> + <track default src="support/test.vtt"> + <source src="/media/white.webm" type="video/webm"> + <source src="/media/white.mp4" type="video/mp4"> + </video> +</body> +</html> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/container-for-cue.html b/testing/web-platform/tests/css/css-contain/container-queries/container-for-cue.html new file mode 100644 index 0000000000..f53d161db0 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/container-for-cue.html @@ -0,0 +1,27 @@ +<!doctype html> +<html class="reftest-wait"> +<head> + <title>CSS Container Queries Test: Container for pseudo elements</title> + <link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-queries"> + <link rel="match" href="container-for-cue-ref.html"> + <script src="/common/reftest-wait.js"></script> + <style> + video { + container-type: size; + width: 200px; + height: 200px; + } + @container (width = 200px) { + video::cue { background-color: green } + video::cue(b) { color: lime } + } + </style> +</head> +<body> + <video autoplay onplaying="this.onplaying = null; this.pause(); takeScreenshot();"> + <source src="/media/white.webm" type="video/webm"> + <source src="/media/white.mp4" type="video/mp4"> + <track default src="support/test.vtt"> + </video> +</body> +</html> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/container-for-shadow-dom.html b/testing/web-platform/tests/css/css-contain/container-queries/container-for-shadow-dom.html new file mode 100644 index 0000000000..d1a0c3b568 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/container-for-shadow-dom.html @@ -0,0 +1,345 @@ +<!doctype html> +<meta charset="utf-8"> +<title>CSS Container Queries Test: query container for Shadow DOM</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#query-container"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/declarative-shadow-dom-polyfill.js"></script> +<script src="support/cq-testcommon.js"></script> +<style> + #inclusive-ancestor-across-root, + #inclusive-ancestor-skip-slotting, + #inclusive-ancestor-slotted, + #inclusive-ancestor-host, + #inclusive-ancestor-part, + #inclusive-ancestor-slotted-before, + #inclusive-ancestor-host-before, + #inclusive-ancestor-part-before, + #inclusive-ancestor-inner-part, + #inclusive-ancestor-slot-fallback, + #inner-scope-host-part { + width: 400px; + container-type: inline-size; + } +</style> + +<div id="inclusive-ancestor-across-root"> + <div> + <template shadowrootmode="open"> + <style> + @container (width = 400px) { + #t1 { color: green; } + } + </style> + <div id="t1"></div> + </template> + </div> +</div> + +<div id="inclusive-ancestor-skip-slotting"> + <div> + <template shadowrootmode="open"> + <style> + div { + width: 200px; + container-type: inline-size; + } + </style> + <div> + <slot></slot> + </div> + </template> + <style> + @container (width = 400px) { + #t2 { color: green; } + } + </style> + <div id="t2"></div> + </div> +</div> + +<div id="inclusive-ancestor-slotted"> + <div> + <template shadowrootmode="open"> + <style> + slot { + display: block; + width: 200px; + container-type: inline-size; + } + @container (width = 200px) { + ::slotted(#t3) { color: green; } + } + </style> + <slot></slot> + </template> + <div id="t3"></div> + </div> +</div> + +<div id="inclusive-ancestor-host"> + <div id="t4"> + <template shadowrootmode="open"> + <style> + @container (width = 400px) { + :host(#t4) { color: green; } + } + </style> + </template> + </div> +</div> + +<div id="inclusive-ancestor-part"> + <div> + <template shadowrootmode="open"> + <style> + div { + width: 200px; + container-type: inline-size; + } + </style> + <div> + <span id="t5" part="part"></span> + </div> + </template> + <style> + @container (width = 400px) { + #inclusive-ancestor-part > div::part(part) { color: green; } + } + </style> + </div> +</div> + +<div id="inclusive-ancestor-slotted-before"> + <div> + <template shadowrootmode="open"> + <style> + slot { + display: block; + width: 200px; + container-type: inline-size; + } + @container (width = 200px) { + ::slotted(#t6)::before { + content: "X"; + color: green; + } + } + </style> + <slot></slot> + </template> + <style> + #t6 { + width: 400px; + container-type: inline-size; + } + </style> + <div id="t6"></div> + </div> +</div> + +<div id="inclusive-ancestor-host-before"> + <div id="t7"> + <template shadowrootmode="open"> + <style> + :host { + width: 200px; + container-type: inline-size; + } + @container (width = 200px) { + :host(#t7)::before { + content: "X"; + color: green; + } + } + </style> + </template> + </div> +</div> + +<div id="inclusive-ancestor-part-before"> + <style> + @container (width = 400px) { + #inclusive-ancestor-part-before > div::part(part)::before { + content: "X"; + color: green; + } + } + </style> + <div> + <template shadowrootmode="open"> + <style> + div { + width: 200px; + container-type: inline-size; + } + </style> + <div> + <span id="t8" part="part"></span> + </div> + </template> + </div> +</div> + +<div id="inclusive-ancestor-inner-part"> + <style> + @container (width = 400px) { + #inclusive-ancestor-inner-part > div::part(inner-part) { color: green; } + } + </style> + <div> + <template shadowrootmode="open"> + <style> + div { + width: 200px; + container-type: inline-size; + } + </style> + <div exportparts="inner-part"> + <template shadowrootmode="open"> + <style> + div { + width: 200px; + container-type: inline-size; + } + </style> + <div> + <span id="t9" part="inner-part"></span> + </div> + </template> + </div> + </template> + </div> +</div> + +<div id="inclusive-ancestor-slot-fallback"> + <div><template shadowrootmode="open"> + <style> + div { + width: 200px; + container-type: inline-size; + } + @container (width = 200px) { + #t10 { color: green; } + } + </style> + <div> + <slot><span id="t10"></span></slot> + </div> + </template></div> +</div> + +<div id="no-container-for-part"> + <div> + <template shadowrootmode="open"> + <style> + div { + width: 200px; + container-type: inline-size; + } + #t11 { color: green; } + </style> + <div> + <span id="t11" part="part"></span> + </div> + </template> + <style> + @container (width = 200px) { + #no-container-for-part > div::part(part) { color: red; } + } + </style> + </div> +</div> + +<div id="inner-scope-host-part"> + <div> + <template shadowrootmode="open"> + <style> + div { + width: 200px; + container-type: inline-size; + } + @container (width = 400px) { + :host::part(part) { color: green; } + } + </style> + <div> + <span id="t12" part="part"></span> + </div> + </template> + <style> + </style> + </div> +</div> + +<script> + setup(() => { + assert_implements_container_queries(); + polyfill_declarative_shadow_dom(document); + }); + + const green = "rgb(0, 128, 0)"; + + test(() => { + const t1 = document.querySelector("#inclusive-ancestor-across-root > div").shadowRoot.querySelector("#t1"); + assert_equals(getComputedStyle(t1).color, green); + }, "Match container in outer tree"); + + test(() => { + const t2 = document.querySelector("#t2"); + assert_equals(getComputedStyle(t2).color, green); + }, "Match container in same tree, not walking flat tree ancestors"); + + test(() => { + const t3 = document.querySelector("#t3"); + assert_equals(getComputedStyle(t3).color, green); + }, "Match container in ::slotted selector's originating element tree"); + + test(() => { + const t4 = document.querySelector("#t4"); + assert_equals(getComputedStyle(t4).color, green); + }, "Match container in outer tree for :host"); + + test(() => { + const t5 = document.querySelector("#inclusive-ancestor-part > div").shadowRoot.querySelector("#t5"); + assert_equals(getComputedStyle(t5).color, green); + }, "Match container in ::part selector's originating element tree"); + + test(() => { + const t6 = document.querySelector("#t6"); + assert_equals(getComputedStyle(t6, "::before").color, green); + }, "Match container for ::before in ::slotted selector's originating element tree"); + + test(() => { + const t7 = document.querySelector("#t7"); + assert_equals(getComputedStyle(t7, "::before").color, green); + }, "Match container in outer tree for :host::before"); + + test(() => { + const t8 = document.querySelector("#inclusive-ancestor-part-before > div").shadowRoot.querySelector("#t8"); + assert_equals(getComputedStyle(t8, "::before").color, green); + }, "Match container for ::before in ::part selector's originating element tree"); + + test(() => { + const outerhost = document.querySelector("#inclusive-ancestor-inner-part > div"); + const innerhost = outerhost.shadowRoot.querySelector("div"); + const t9 = innerhost.shadowRoot.querySelector("#t9"); + assert_equals(getComputedStyle(t9).color, green); + }, "Match container for ::part selector's originating element tree for exportparts"); + + test(() => { + const t10 = document.querySelector("#inclusive-ancestor-slot-fallback > div").shadowRoot.querySelector("#t10"); + assert_equals(getComputedStyle(t10).color, green); + }, "Match container for slot light tree child fallback"); + + test(() => { + const t11 = document.querySelector("#no-container-for-part > div").shadowRoot.querySelector("#t11"); + assert_equals(getComputedStyle(t11).color, green); + }, "Should not match container inside shadow tree for ::part()"); + + test(() => { + const t12 = document.querySelector("#inner-scope-host-part > div").shadowRoot.querySelector("#t12"); + assert_equals(getComputedStyle(t12).color, green); + }, "A :host::part rule should match containers in the originating element tree"); + +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/container-inheritance.html b/testing/web-platform/tests/css/css-contain/container-queries/container-inheritance.html new file mode 100644 index 0000000000..b333b691fd --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/container-inheritance.html @@ -0,0 +1,18 @@ +<!doctype html> +<meta charset="utf-8"> +<title>CSS Containment Test: Inheritance of container-*</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-name"> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-type"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/css/support/inheritance-testcommon.js"></script> +<script src="support/cq-testcommon.js"></script> +<div id="container"> + <div id="target"></div> +</div> +<script> +setup(() => assert_implements_container_queries()); + +assert_not_inherited('container-name', 'none', 'foo'); +assert_not_inherited('container-type', 'normal', 'inline-size'); +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/container-inner-at-rules.html b/testing/web-platform/tests/css/css-contain/container-queries/container-inner-at-rules.html new file mode 100644 index 0000000000..ac18002929 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/container-inner-at-rules.html @@ -0,0 +1,196 @@ +<!doctype html> +<title>@container: inner at-rules</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-rule"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/cq-testcommon.js"></script> +<style> + #container { + container-type: size; + width: 100px; + height: 100px; + } + +</style> +<div id=container> + <div id=child></div> +</div> + +<script> + setup(() => assert_implements_container_queries()); +</script> + +<style> + @container (width: 100px) { + @keyframes anim1 { + from { --anim1:true; } + to { --anim1:true; } + } + } + + @container (width: 200px) { + @keyframes anim2 { + from { --anim2:true; } + to { --anim2:true; } + } + } + + #child { animation: anim1 10s paused, anim2 10s paused; } +</style> +<script> + test(() => { + assert_equals(getComputedStyle(child).getPropertyValue('--anim1'), 'true'); + assert_equals(getComputedStyle(child).getPropertyValue('--anim2'), 'true'); + }, '@keyframes is defined regardless of evaluation'); +</script> + + +<style> + @container (width: 100px) { + @property --prop1 { + syntax: "<length>"; + inherits: false; + initial-value: 0px; + } + } + + @container (width: 200px) { + @property --prop2 { + syntax: "<length>"; + inherits: false; + initial-value: 0px; + } + } + + #child { + font-size: 20px; + --prop1:1em; + --prop2:2em; + } +</style> +<script> + test(() => { + assert_equals(getComputedStyle(child).getPropertyValue('--prop1'), '20px'); + assert_equals(getComputedStyle(child).getPropertyValue('--prop2'), '40px'); + }, '@property is defined regardless of evaluation'); +</script> + + +<style> + @container (width: 100px) { + @layer a; + } + + @container (width: 200px) { + @layer b; + } + + @layer b { + #child { --layer:b; } + } + + @layer a { + #child { --layer:a; } + } + +</style> +<script> + test(() => { + assert_equals(getComputedStyle(child).getPropertyValue('--layer'), 'b'); + }, '@layer order respected regardless of evaluation'); +</script> + + +<style> + @container (width: 100px) { + @font-face { + font-family: Font1; + font-stretch: 50% 200%; + src: url(/fonts/Ahem.ttf); + } + } + + @container (width: 200px) { + @font-face { + font-family: Font2; + font-stretch: 40% 190%; + src: url(/fonts/Ahem.ttf); + } + } + +</style> +<script> + promise_test(async (t) => { + const fonts1 = await document.fonts.load("20px Font1"); + assert_not_equals(fonts1[0], undefined); + assert_equals(fonts1[0].stretch, "50% 200%"); + + const fonts2 = await document.fonts.load("20px Font2"); + assert_not_equals(fonts2[0], undefined); + assert_equals(fonts2[0].stretch, "40% 190%"); + }, '@font-face is defined regardless of evaluation'); +</script> + + +<style> + @container (width: 100px) { + /* Assumed to be false */ + @media (width: 0px) { + #child { --media1:true; } + } + /* Assumed to be true */ + @media (min-width: 0px) { + #child { --media2:true; } + } + } + + /* Same again, but with failing container query. */ + @container (width: 200px) { + @media (width: 0px) { + #child { --media3:true; } + } + @media (min-width: 0px) { + #child { --media4:true; } + } + } + +</style> +<script> + test(() => { + assert_equals(getComputedStyle(child).getPropertyValue('--media1'), ''); + assert_equals(getComputedStyle(child).getPropertyValue('--media2'), 'true'); + assert_equals(getComputedStyle(child).getPropertyValue('--media3'), ''); + assert_equals(getComputedStyle(child).getPropertyValue('--media4'), ''); + }, '@media works inside @container'); +</script> + + +<style> + @container (width: 100px) { + @supports (width: 500kg) { + #child { --supports1:true; } + } + @supports (width: 500px) { + #child { --supports2:true; } + } + } + + /* Same again, but with failing container query. */ + @container (width: 200px) { + @supports (width: 500kg) { + #child { --supports3:true; } + } + @supports (width: 500px) { + #child { --supports4:true; } + } + } + +</style> +<script> + test(() => { + assert_equals(getComputedStyle(child).getPropertyValue('--supports1'), ''); + assert_equals(getComputedStyle(child).getPropertyValue('--supports2'), 'true'); + assert_equals(getComputedStyle(child).getPropertyValue('--supports3'), ''); + assert_equals(getComputedStyle(child).getPropertyValue('--supports4'), ''); + }, '@supports works inside @container'); +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/container-inside-multicol-with-table.html b/testing/web-platform/tests/css/css-contain/container-queries/container-inside-multicol-with-table.html new file mode 100644 index 0000000000..8688159da3 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/container-inside-multicol-with-table.html @@ -0,0 +1,41 @@ +<!doctype html> +<title>CSS Container Queries Test: container inside multicol with table</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#size-container"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/cq-testcommon.js"></script> +<style> + #multicol { + columns: 2; + } + .container { + container-type: inline-size; + width: 100px; + } + @container (width = 100px) { + #t1, #t2 { color: green; } + } +</style> +<div id="multicol"> + <div class="container"> + <div id="t1"></div> + </div> + <table> + <div class="container"> + <div id="t2"></div> + </div> + </table> +</div> +<script> + setup(() => assert_implements_container_queries()); + + const green = "rgb(0, 128, 0)"; + + test(() => { + assert_equals(getComputedStyle(t1).color, green); + }, "Matching size container inside table inside multicol"); + + test(() => { + assert_equals(getComputedStyle(t2).color, green); + }, "Matching size container inside multicol with table sibling"); +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/container-longhand-animation-type.html b/testing/web-platform/tests/css/css-contain/container-queries/container-longhand-animation-type.html new file mode 100644 index 0000000000..aded2a3ec8 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/container-longhand-animation-type.html @@ -0,0 +1,45 @@ +<!doctype html> +<title>Container Queries - The container longhands are not animatable</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#propdef-container-name"> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#propdef-container-type"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/cq-testcommon.js"></script> +<style> + @keyframes anim { + from { + --ref:PASS; + container-name: FAIL; + container-type: size; + } + to { + --ref:PASS; + container-name: FAIL; + container-type: size; + } + } + #container { + --ref:FAIL; + container-name: PASS; + container-type: inline-size; + animation: anim 1s linear paused; + } +</style> +<div id=container> +</div> +<script> + setup(() => assert_implements_container_queries()); + + test(() => { + assert_equals(getComputedStyle(container).getPropertyValue('--ref'), 'PASS'); + }, 'Reference variable is applied'); + + test(() => { + assert_equals(getComputedStyle(container).getPropertyValue('container-name'), 'PASS'); + }, 'container-name is not animatable'); + + test(() => { + assert_equals(getComputedStyle(container).getPropertyValue('container-type'), 'inline-size'); + }, 'container-type is not animatable'); + +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/container-name-computed.html b/testing/web-platform/tests/css/css-contain/container-queries/container-name-computed.html new file mode 100644 index 0000000000..f58d54744e --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/container-name-computed.html @@ -0,0 +1,23 @@ +<!doctype html> +<meta charset="utf-8"> +<title>CSS Containment Test: Computed values of container-name</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-name"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/css/support/computed-testcommon.js"></script> +<script src="support/cq-testcommon.js"></script> +<div id="target"></div> +<script> +setup(() => assert_implements_container_queries()); + +test_computed_value('container-name', 'initial', 'none'); +test_computed_value('container-name', 'unset', 'none'); +test_computed_value('container-name', 'foo'); +test_computed_value('container-name', 'FoO'); +test_computed_value('container-name', 'foo bar'); +test_computed_value('container-name', 'bar foo'); +test_computed_value('container-name', 'foo foo bar'); +test_computed_value('container-name', 'foo bar foo'); +test_computed_value('container-name', 'bar foo foo'); +test_computed_value('container-name', '\\!escaped'); +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/container-name-invalidation.html b/testing/web-platform/tests/css/css-contain/container-queries/container-name-invalidation.html new file mode 100644 index 0000000000..aad225def9 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/container-name-invalidation.html @@ -0,0 +1,74 @@ +<!doctype html> +<title>container-name invalidation</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-name"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/cq-testcommon.js"></script> +<style> + div { + color: black; + } + #outer { + container-name: c1; + container-type: inline-size; + width: 300px; + } + + #inner { + container-name: c2; + container-type: inline-size; + width: 200px; + } + + #intermediate { + width: 250px; + } + + @container c1 (width: 250px) { + #child { + color: green; + } + } +</style> +<div id=outer> + <div id=intermediate> + <div id=inner> + <div id=child>Test</div> + </div> + </div> +</div> +<script> + setup(() => assert_implements_container_queries()); + + test(function(t) { + t.add_cleanup(() => { outer.style = ''; }); + + assert_equals(getComputedStyle(child).color, 'rgb(0, 0, 0)'); + + outer.style.width = '250px'; + assert_equals(getComputedStyle(child).color, 'rgb(0, 128, 0)'); + + outer.style.width = '251px'; + assert_equals(getComputedStyle(child).color, 'rgb(0, 0, 0)'); + }, 'Changing a named container invalidates relevant descendants'); + + test(function(t) { + t.add_cleanup(() => { + outer.style = ''; + intermediate.style = ''; + }); + + assert_equals(getComputedStyle(child).color, 'rgb(0, 0, 0)'); + + // #intermediate becomes the new container. + intermediate.style = 'container-name:c1; container-type:inline-size'; + assert_equals(getComputedStyle(child).color, 'rgb(0, 128, 0)'); + + // #outer becomes the container again. + intermediate.style = ''; + assert_equals(getComputedStyle(child).color, 'rgb(0, 0, 0)'); + + outer.style.width = '250px'; + assert_equals(getComputedStyle(child).color, 'rgb(0, 128, 0)'); + }, 'Changing container-name invalidates relevant descendants'); +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/container-name-parsing.html b/testing/web-platform/tests/css/css-contain/container-queries/container-name-parsing.html new file mode 100644 index 0000000000..4f385cca52 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/container-name-parsing.html @@ -0,0 +1,45 @@ +<!doctype html> +<meta charset="utf-8"> +<title>CSS Containment Test: Parsing of container-name</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-name"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/css/support/parsing-testcommon.js"></script> +<script src="support/cq-testcommon.js"></script> +<div id="target"></div> +<script> +setup(() => assert_implements_container_queries()); + +test_valid_value('container-name', 'initial'); +test_valid_value('container-name', 'inherit'); +test_valid_value('container-name', 'unset'); +test_valid_value('container-name', 'revert'); +test_valid_value('container-name', 'none'); +test_valid_value('container-name', 'foo'); +test_valid_value('container-name', 'BAR'); +test_valid_value('container-name', 'foo bar'); +test_valid_value('container-name', 'foo foo'); +test_valid_value('container-name', '\\!escaped'); +test_valid_value('container-name', 'auto'); +test_valid_value('container-name', 'normal'); + +test_invalid_value('container-name', 'none none'); +test_invalid_value('container-name', 'foo, bar'); +test_invalid_value('container-name', '#fff'); +test_invalid_value('container-name', '1px'); +test_invalid_value('container-name', 'default'); /* reserved */ + +test_invalid_value('container-name', '"initial"'); +test_invalid_value('container-name', '"inherit"'); +test_invalid_value('container-name', '"unset"'); +test_invalid_value('container-name', '"revert"'); +test_invalid_value('container-name', '"none"'); +test_invalid_value('container-name', '"foo"'); + +test_invalid_value('container-name', 'not'); +test_invalid_value('container-name', 'and'); +test_invalid_value('container-name', 'or'); +test_invalid_value('container-name', 'Not'); +test_invalid_value('container-name', 'aNd'); +test_invalid_value('container-name', 'oR'); +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/container-name-tree-scoped.html b/testing/web-platform/tests/css/css-contain/container-queries/container-name-tree-scoped.html new file mode 100644 index 0000000000..e66f51d035 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/container-name-tree-scoped.html @@ -0,0 +1,73 @@ +<!doctype html> +<meta charset="utf-8"> +<title>CSS Container Queries Test: Tree scoped container-name</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#query-container"> +<link rel="help" href="https://drafts.csswg.org/css-scoping-1/#shadow-names"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/declarative-shadow-dom-polyfill.js"></script> +<script src="support/cq-testcommon.js"></script> + +<div id="container-name-host"> + <div> + <template shadowrootmode="open"> + <style> + :host { container-name: foo; } + </style> + <slot></slot> + </template> + <div id="t1"></div> + </div> + <style> + #container-name-host > div { + container-type: inline-size; + } + #t1 { color: green; } + @container foo (width > 0px) { + #t1 { color: red; } + } + </style> +</div> + +<div id="container-name-slotted"> + <div> + <template shadowrootmode="open"> + <style> + ::slotted(div) { + container-name: foo; + } + </style> + <slot></slot> + </template> + <div> + <div id="t2"></div> + </div> + </div> + <style> + #container-name-slotted > div > div { + container-type: inline-size; + } + #t2 { color: green; } + @container foo (width > 0px) { + #t2 { color: red; } + } + </style> +</div> + +<script> + setup(() => { + assert_implements_container_queries(); + polyfill_declarative_shadow_dom(document); + }); + + const green = "rgb(0, 128, 0)"; + + test(() => { + assert_equals(getComputedStyle(t1).color, green); + }, "Outer scope query should not match container-name set by :host rule in shadow tree"); + + test(() => { + assert_equals(getComputedStyle(t2).color, green); + }, "Outer scope query should not match container-name set by ::slotted rule in shadow tree"); + +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/container-nested.html b/testing/web-platform/tests/css/css-contain/container-queries/container-nested.html new file mode 100644 index 0000000000..3ad35bd2be --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/container-nested.html @@ -0,0 +1,239 @@ +<!doctype html> +<title>@container (nested)</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-rule"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/cq-testcommon.js"></script> +<style> + +#outer { + container-name: outer; + container-type: size; + width: 100px; + height: 100px; +} + +#inner { + container-name: inner; + container-type: size; + width: 50px; + height: 50px; +} +</style> +<div id=outer> + <div id=inner> + <div id=child></div> + </div> +</div> +<script> + setup(() => assert_implements_container_queries()); +</script> + +<!-- + "Implicit" refers to implicit container selection, i.e. understanding which + container to evaluate against by looking at the features used. +--> + +<style> + @container (width: 50px) { + @container (height: 50px) { + #child { --implicit:true; } + } + } +</style> +<script> + test(() => { + assert_equals(getComputedStyle(child).getPropertyValue('--implicit'), 'true'); + }, 'Implicit'); +</script> + + +<style> + @container (width: 70px) { + @container (height: 50px) { + #child { --implicit-outer-fail:true; } + } + } +</style> +<script> + test(() => { + assert_equals(getComputedStyle(child).getPropertyValue('--implicit-outer-fail'), ''); + }, 'Implicit, outer failing'); +</script> + + +<style> + @container (width: 50px) { + @container (height: 70px) { + #child { --implicit-inner-fail:true; } + } + } +</style> +<script> + test(() => { + assert_equals(getComputedStyle(child).getPropertyValue('--implicit-inner-fail'), ''); + }, 'Implicit, inner failing'); +</script> + + +<style> + @container outer (width: 100px) { + @container inner (height: 50px) { + #child { --named-outer-inner:true; } + } + } +</style> +<script> + test(() => { + assert_equals(getComputedStyle(child).getPropertyValue('--named-outer-inner'), 'true'); + }, 'Outer named, inner named'); +</script> + + +<style> + @container inner (width: 50px) { + @container outer (height: 100px) { + #child { --named-outer-inner-reverse:true; } + } + } +</style> +<script> + test(() => { + assert_equals(getComputedStyle(child).getPropertyValue('--named-outer-inner-reverse'), 'true'); + }, 'Outer named, inner named (reverse)'); +</script> + + +<style> + @container unknown (width: 100px) { + @container inner (height: 50px) { + #child { --named-failing-outer:true; } + } + } +</style> +<script> + test(() => { + assert_equals(getComputedStyle(child).getPropertyValue('--named-failing-outer'), ''); + }, 'Failing outer name'); +</script> + +<style> + @container outer (width: 100px) { + @container unknown (height: 50px) { + #child { --named-failing-inner:true; } + } + } +</style> +<script> + test(() => { + assert_equals(getComputedStyle(child).getPropertyValue('--named-failing-inner'), ''); + }, 'Failing inner name'); +</script> + + +<style> + @container outer (width: 100px) { + @container (height: 50px) { + #child { --named-outer-inner-implicit:true; } + } + } +</style> +<script> + test(() => { + assert_equals(getComputedStyle(child).getPropertyValue('--named-outer-inner-implicit'), 'true'); + }, 'Outer named, inner implicit'); +</script> + + +<style> + @container (width: 50px) { + @container inner (height: 50px) { + #child { --implicit-outer-inner-named:true; } + } + } +</style> +<script> + test(() => { + assert_equals(getComputedStyle(child).getPropertyValue('--implicit-outer-inner-named'), 'true'); + }, 'Inner named, outer implicit'); +</script> + + +<style> + @container (width: 50px) { + @container outer (height: 100px) { + #child { --implicit-outer-inner-named-reverse:true; } + } + } +</style> +<script> + test(() => { + assert_equals(getComputedStyle(child).getPropertyValue('--implicit-outer-inner-named-reverse'), 'true'); + }, 'Inner named, outer implicit (reverse)'); +</script> + + +<style> + @container (width > 1px) { + @container (width > 2px) { + @container (width > 3px) { + #child { --three-levels:true; } + } + } + } +</style> +<script> + test(() => { + assert_equals(getComputedStyle(child).getPropertyValue('--three-levels'), 'true'); + }, 'Three levels'); +</script> + + +<style> + @container (width > 1px) { + @container (width > 2000px) { + @container (width > 3px) { + #child { --three-levels-middle-fail:true; } + } + } + } +</style> +<script> + test(() => { + assert_equals(getComputedStyle(child).getPropertyValue('--three-levels-middle-fail'), ''); + }, 'Three levels, middle fail'); +</script> + + +<style> + @container (width: 50px) { + @container outer (height: 100px) { + #child { --inner-named-invalidation:true; } + } + } +</style> +<script> + test((t) => { + t.add_cleanup(() => { outer.style = ''; }); + assert_equals(getComputedStyle(child).getPropertyValue('--inner-named-invalidation'), 'true'); + outer.style.height = '200px'; + assert_equals(getComputedStyle(child).getPropertyValue('--inner-named-invalidation'), ''); + }, 'Named inner invalidation'); +</script> + + +<style> + @container (width: 50px) { + @container outer (height: 100px) { + #child { --outer-implicit-invalidation:true; } + } + } +</style> +<script> + test((t) => { + t.add_cleanup(() => { inner.style = ''; }); + assert_equals(getComputedStyle(child).getPropertyValue('--outer-implicit-invalidation'), 'true'); + inner.style.width = '200px'; + assert_equals(getComputedStyle(child).getPropertyValue('--outer-implicit-invalidation'), ''); + }, 'Implicit outer invalidation'); +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/container-parsing.html b/testing/web-platform/tests/css/css-contain/container-queries/container-parsing.html new file mode 100644 index 0000000000..87b3bdd48c --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/container-parsing.html @@ -0,0 +1,63 @@ +<!doctype html> +<meta charset="utf-8"> +<title>CSS Containment Test: Parsing of container</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-name"> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-type"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/css/support/parsing-testcommon.js"></script> +<script src="support/cq-testcommon.js"></script> +<div id="target"></div> +<script> +setup(() => assert_implements_container_queries()); + +test_valid_value('container', 'initial'); +test_valid_value('container', 'inherit'); +test_valid_value('container', 'unset'); +test_valid_value('container', 'revert'); +test_valid_value('container', 'none'); +test_valid_value('container', 'none / normal', 'none'); +test_valid_value('container', 'inline-size'); +test_valid_value('container', 'none / inline-size', 'none / inline-size'); +test_valid_value('container', 'size'); +test_valid_value('container', 'block-size / size'); +test_valid_value('container', 'inline-size / inline-size'); +test_valid_value('container', 'size / size'); +test_valid_value('container', 'foo'); +test_valid_value('container', 'foo / normal', 'foo'); +test_valid_value('container', 'foo bar / size'); +test_valid_value('container', 'foo bar / normal', 'foo bar'); +test_valid_value('container', 'FOO / size'); +test_valid_value('container', 'FOO/size', 'FOO / size'); +test_valid_value('container', ' FOO /size', 'FOO / size'); +test_valid_value('container', 'normal / size'); +test_valid_value('container', 'auto / size'); + +test_invalid_value('container', 'none none'); +test_invalid_value('container', 'none inline-size'); +test_invalid_value('container', 'none / inline-size none'); +test_invalid_value('container', 'none / inline-size normal'); +test_invalid_value('container', 'none / inline-size inline-size'); +test_invalid_value('container', 'none / inline-size block-size unknown'); +test_invalid_value('container', 'none / inline-size block-size'); +test_invalid_value('container', 'none / size block-size'); +test_invalid_value('container', 'none, none'); +test_invalid_value('container', 'none, normal'); +test_invalid_value('container', 'none / none'); +test_invalid_value('container', 'none / auto'); +test_invalid_value('container', 'none / foo'); +test_invalid_value('container', 'none / foo, bar'); +test_invalid_value('container', '#fff'); +test_invalid_value('container', '1px'); +test_invalid_value('container', 'default'); +test_invalid_value('container', '10px / inline-size'); +test_invalid_value('container', '#fefefe / inline-size'); +test_invalid_value('container', 'calc(3px) / inline-size'); +test_invalid_value('container', 'size 1 / name'); +test_invalid_value('container', 'none / block-size'); +test_invalid_value('container', 'name / block-size'); +test_invalid_value('container', ' NAME / block-size', 'NAME / block-size'); +test_invalid_value('container', 'NAME/block-size','NAME / block-size'); +test_invalid_value('container', 'block-size / block-size'); +test_invalid_value('container', 'none / size style'); +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/container-selection.html b/testing/web-platform/tests/css/css-contain/container-queries/container-selection.html new file mode 100644 index 0000000000..cef20f85a2 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/container-selection.html @@ -0,0 +1,183 @@ +<!doctype html> +<title>@container: selection using name and implicit selection</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-rule"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/cq-testcommon.js"></script> +<style> + + main { background-color: lightgray; } + main > div { background-color: skyblue; } + main > div > div { background-color: seagreen; } + main > div > div > div { background-color: tomato; } + + main { + width: 64px; + height: 64px; + } + + main div { + width: 50%; + height: 50%; + } + + .inline { container-type: inline-size; } + .size { container-type: size; } + + .a-inline { container: a / inline-size; } + .a-size { container: a / size; } + + .b-size { container: inline- b / size; } + .b-size { container: b / size; } + + .ab-size { container: a b / size; } + + .a { container-name: a; contain: strict; } + +</style> + +<main> + <div class="inline"> + <div class="size"> + <span></span> + </div> + </div> +</main> + +<main> + <div class="size"> + <div class="inline"> + <span></span> + </div> + </div> +</main> + +<main> + <div class="inline"> + <div class="inline"> + <span></span> + </div> + </div> +</main> + +<main> + <div class="a-size"> + <div class="b-size"> + <span></span> + </div> + </div> +</main> + +<main> + <div class="a-size"> + <div class="a-size"> + <span></span> + </div> + </div> +</main> + +<main> + <div class="a-size"> + <div class="a"> + <span></span> + </div> + </div> +</main> + +<main> + <div class="a-size"> + <div class="b-size"> + <div class="a-inline"> + <span></span> + </div> + </div> + </div> +</main> + +<main> + <div class="a-inline"> + <div class="b-size"> + <span></span> + </div> + </div> +</main> + +<main> + <div class="ab-size"> + <div class="size"> + <span></span> + </div> + </div> +</main> + +<script> + setup(() => assert_implements_container_queries()); + + function test_query(prelude, selector, expected) { + test(t => { + let elements = document.querySelectorAll(selector); + assert_equals(elements.length, 1); + let element = elements[0]; + + let style = document.createElement('style'); + t.add_cleanup(() => { style.remove(); }); + style.innerText = `@container ${prelude} { span { --match:true; } } `; + document.body.append(style); + + assert_equals(getComputedStyle(element).getPropertyValue('--match'), expected); + }, `${prelude} for ${selector}`); + } + + // Test that a given container query applies to the specified element. + // The provided selector must unique identify the element. + function test_applied(prelude, selector) { + test_query(prelude, selector, 'true'); + } + + function test_rejected(prelude, selector) { + test_query(prelude, selector, ''); + } + + // For the following tests, the inner container has a size of 16x16px, + // and the outer container has a size of 32x32px. + + // Implicit selection: + test_applied('(width: 16px)', '.size > .inline > span'); + test_applied('(height: 16px)', '.inline > .size > span'); + test_applied('(width: 16px)', '.inline > .size > span'); + test_applied('(height: 32px)', '.size > .inline > span'); + test_rejected('(height: 16px)', '.size > .inline > span'); + + // Name selection: + test_applied('a (width: 32px)', '.a-size > .b-size > span'); + test_applied('b (width: 16px)', '.a-size > .b-size > span'); + test_rejected('c (width)', '.a-size > .b-size > span'); + test_applied('a (width: 16px)', '.a-size > .a-size > span'); + + // container-name alone does not establish a container: + test_applied('a (width: 32px)', '.a-size > .a > span'); + + // Can query container with multiple names: + test_applied('a (width: 32px)', '.ab-size > .size > span'); + test_applied('b (width: 32px)', '.ab-size > .size > span'); + test_rejected('c (width)', '.ab-size > .size > span'); + + // The following tests have three containers: + // + // outer -> 32x32px + // middle -> 16x16px + // inner -> 8x8px + + // Combinations of name and implicit selection: + test_applied('a (width: 8px)', '.a-size > .b-size > .a-inline > span'); + test_applied('b (width: 16px)', '.a-size > .b-size > .a-inline > span'); + test_applied('a (height: 32px)', '.a-size > .b-size > .a-inline > span'); + test_rejected('a (height)', '.a-inline > .b-size'); + + // Same tests as above, but logical versions: + test_applied('a (inline-size: 8px)', '.a-size > .b-size > .a-inline > span'); + test_applied('b (inline-size: 16px)', '.a-size > .b-size > .a-inline > span'); + test_applied('a (block-size: 32px)', '.a-size > .b-size > .a-inline > span'); + test_rejected('a (block-size)', '.a-inline > .b-size'); + +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/container-size-invalidation-after-load.html b/testing/web-platform/tests/css/css-contain/container-queries/container-size-invalidation-after-load.html new file mode 100644 index 0000000000..cf5687aa39 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/container-size-invalidation-after-load.html @@ -0,0 +1,39 @@ +<!DOCTYPE html> +<title>@container: invalidation of container size after load event</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#size-container"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/cq-testcommon.js"></script> +<style> + #container { + container-type: size; + width: 200px; + height: 4em; + border: 1px solid black; + } + @container (width > 300px) { + #child { color: green; } + } +</style> +<div id=container> + <div id=child> + Green + </div> +</div> +<script> + setup(() => assert_implements_container_queries()); + + function waitForLoad(w) { + return new Promise(resolve => w.addEventListener('load', resolve)); + } + + promise_test(async () => { + await waitForLoad(window); + container.offsetTop; + + container.style.width = '400px'; + container.style.setProperty('--x', 'x'); // crbug.com/1321010 + + assert_equals(getComputedStyle(child).color, 'rgb(0, 128, 0)'); + }); +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/container-size-invalidation.html b/testing/web-platform/tests/css/css-contain/container-queries/container-size-invalidation.html new file mode 100644 index 0000000000..ab26971749 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/container-size-invalidation.html @@ -0,0 +1,39 @@ +<!doctype html> +<title>@container-dependent elements respond to container size changes</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#size-container"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/cq-testcommon.js"></script> +<style> + #container { + container-type: size; + width: 200px; + height: 50px; + } + div { color: red; } + @container (min-width: 300px) { + div { color: green; } + } +</style> +<main id=container> + <div id=child> + Test + <p><span id=descendant>Deep</span></p> + </div> +</main> +<script> + setup(() => assert_implements_container_queries()); + + test(function() { + assert_equals(getComputedStyle(child).color, 'rgb(255, 0, 0)'); + container.style.width = '300px'; + assert_equals(getComputedStyle(child).color, 'rgb(0, 128, 0)'); + }, 'Children respond to changes in container size'); + + test(function() { + container.style = ''; + assert_equals(getComputedStyle(descendant).color, 'rgb(255, 0, 0)'); + container.style.width = '300px'; + assert_equals(getComputedStyle(descendant).color, 'rgb(0, 128, 0)'); + }, 'Descendants respond to changes in container size'); +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/container-size-nested-invalidation.html b/testing/web-platform/tests/css/css-contain/container-queries/container-size-nested-invalidation.html new file mode 100644 index 0000000000..a549f6d848 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/container-size-nested-invalidation.html @@ -0,0 +1,62 @@ +<!doctype html> +<title>Nested @container-dependent elements respond to outer container size changes</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#size-container"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/cq-testcommon.js"></script> +<style> + #outer { + container-type: size; + container-name: outer; + width: 100px; + height: 100px; + } + + /* Note that it's intentional that nothing queries this container. */ + #inner { + container-type: size; + width: 42px; + height: 42px; + } + + @container (width > 90px) { + #outer_child { + --outer:true; + } + } + + @container outer (width > 70px) { + #inner_child { + --inner:true; + } + } +</style> +<div id=outer> + <div id=outer_child></div> + <div id=inner> + <div id=inner_child></div> + </div> +</div> +<script> + setup(() => assert_implements_container_queries()); + + test(function() { + assert_equals(getComputedStyle(outer_child).getPropertyValue('--outer'), 'true'); + assert_equals(getComputedStyle(inner_child).getPropertyValue('--inner'), 'true'); + + outer.style.width = '80px'; + + assert_equals(getComputedStyle(outer_child).getPropertyValue('--outer'), ''); + assert_equals(getComputedStyle(inner_child).getPropertyValue('--inner'), 'true'); + + outer.style.width = '60px'; + + assert_equals(getComputedStyle(outer_child).getPropertyValue('--outer'), ''); + assert_equals(getComputedStyle(inner_child).getPropertyValue('--inner'), ''); + + outer.style.width = '100px'; + + assert_equals(getComputedStyle(outer_child).getPropertyValue('--outer'), 'true'); + assert_equals(getComputedStyle(inner_child).getPropertyValue('--inner'), 'true'); + }, 'Queries that skip a container are invalidated correctly'); +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/container-size-shadow-invalidation.html b/testing/web-platform/tests/css/css-contain/container-queries/container-size-shadow-invalidation.html new file mode 100644 index 0000000000..35773b3006 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/container-size-shadow-invalidation.html @@ -0,0 +1,55 @@ +<!doctype html> +<meta charset="utf-8"> +<title>CSS Container Queries Test: Invalidate size container query for Shadow DOM</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#query-container"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/declarative-shadow-dom-polyfill.js"></script> +<script src="support/cq-testcommon.js"></script> +<style> + .container { + container-type: inline-size; + width: 100px; + } + @container (width = 200px) { + .target { color: green; } + } +</style> +<div id="host_container" class="container"> + <template shadowrootmode="open"> + <div class="container"> + <slot></slot> + </div> + </template> + <div class="target">Green</div> +</div> +<div id="non_host_container" class="container"> + <div> + <template shadowrootmode="open"> + <div class="container"> + <slot></slot> + </div> + </template> + <div class="target">Green</div> + </div> +</div> +<script> + setup(() => { + assert_implements_container_queries(); + polyfill_declarative_shadow_dom(document); + }); + + const green = "rgb(0, 128, 0)"; + + test(() => { + document.body.offsetTop; + host_container.style.width = "200px"; + assert_equals(getComputedStyle(document.querySelector("#host_container .target")).color, green); + }, "Host container child invalidated with container in shadow tree"); + + test(() => { + document.body.offsetTop; + non_host_container.style.width = "200px"; + assert_equals(getComputedStyle(document.querySelector("#non_host_container .target")).color, green); + }, "Non-host container child invalidated with container in shadow tree"); +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/container-type-computed.html b/testing/web-platform/tests/css/css-contain/container-queries/container-type-computed.html new file mode 100644 index 0000000000..0b5e033a0f --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/container-type-computed.html @@ -0,0 +1,18 @@ +<!doctype html> +<meta charset="utf-8"> +<title>Computed values of container-type</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-type"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/css/support/computed-testcommon.js"></script> +<script src="support/cq-testcommon.js"></script> +<div id="target"></div> +<script> +setup(() => assert_implements_container_queries()); + +test_computed_value('container-type', 'initial', 'normal'); +test_computed_value('container-type', 'unset', 'normal'); +test_computed_value('container-type', 'inline-size'); +test_computed_value('container-type', 'size'); +test_computed_value('container-type', 'normal'); +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/container-type-containment.html b/testing/web-platform/tests/css/css-contain/container-queries/container-type-containment.html new file mode 100644 index 0000000000..66500a6a71 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/container-type-containment.html @@ -0,0 +1,85 @@ +<!doctype html> +<title>CSS Container Queries Test: applied containment for container-type</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-type"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/cq-testcommon.js"></script> +<script> + setup(() => assert_implements_container_queries()); +</script> + +<style> + /* Note: background colors have no impact on the test result. They are + present to make it easier to visually verify that the test + does the right thing. */ + .square { + width: 50px; + height: 50px; + background: tomato; + } + .half { + width: 25px; + height: 50px; + background: red; + } + div > div:nth-of-type(1) { background: skyblue; } + div > div:nth-of-type(2) { background: hotpink; } +</style> + +<div id=test1 class=square> + <div id=float1 class=half style="float:left"></div> + <div id=child1 class=half style="container-type:inline-size"></div> +</div> +<script> + test(() => { + assert_equals(child1.offsetLeft, test1.offsetLeft + float1.offsetWidth); + }, 'container-type:inline-size turns on layout containment'); +</script> + +<hr> + +<div id=test2 class=square> + <div id=ref2 style="float:left">A</div> + <div id=child2 style="float:left; container-type:inline-size">A</div> +</div> +<script> + test(() => { + assert_equals(child2.offsetWidth, 0); + assert_equals(child2.offsetHeight, ref2.offsetHeight); + }, 'container-type:inline-size turns on inline-size containment'); +</script> + +<hr> + +<div id=test3 class=square> + <div id=child3 style="float:left; container-type:size">A</div> +</div> +<script> + test(() => { + assert_equals(child3.offsetHeight, 0); + assert_equals(child3.offsetWidth, 0); + }, 'container-type:size turns on full size containment'); +</script> + +<hr> + +<style> + #ref4::before, #child4::before { + content: counter(foo); + } +</style> +<div id=test4 class=square style="counter-set: foo 5"> + <div id=ref4 style="float:left"></div> + <section style="container-type:inline-size"> + <span style="counter-increment: foo 1000;"></span> + </section> + <section style="container-type:size"> + <span style="counter-increment: foo 1000;"></span> + </section> + <div id=child4 style="float:left"></div> +</div> +<script> + test(() => { + assert_equals(child4.offsetWidth, ref4.offsetWidth); + }, 'container-type:inline/size turns on style containment'); +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/container-type-invalidation.html b/testing/web-platform/tests/css/css-contain/container-queries/container-type-invalidation.html new file mode 100644 index 0000000000..90e0b4acd1 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/container-type-invalidation.html @@ -0,0 +1,70 @@ +<!doctype html> +<title>container-type invalidation</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-type"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/cq-testcommon.js"></script> +<style> + div { + color: black; + } + #outer { + width: 300px; + } + + #intermediate { + width: 250px; + } + + #inner { + width: 200px; + } + + .container { + container-type: inline-size; + } + + @container ((max-width: 200px) or (min-width: 300px)) { + #child { color: green; } + } + +</style> +<div id=outer> + <div id=intermediate> + <div id=inner> + <div id=child>Test</div> + </div> + </div> +</div> +<script> + setup(() => assert_implements_container_queries()); + + test(function(t) { + t.add_cleanup(() => { + for (let e of [outer, intermediate, inner]) + e.classList.remove('container'); + }); + + // No container. + assert_equals(getComputedStyle(child).color, 'rgb(0, 0, 0)'); + + outer.classList.add('container'); + assert_equals(getComputedStyle(child).color, 'rgb(0, 128, 0)'); + + // The container query does not match widths in the range [201, 299], + // and #intermediate has width:250px. + intermediate.classList.add('container'); + assert_equals(getComputedStyle(child).color, 'rgb(0, 0, 0)'); + + inner.classList.add('container'); + assert_equals(getComputedStyle(child).color, 'rgb(0, 128, 0)'); + + // Should have no effect, #inner is the container. + outer.classList.remove('container'); + intermediate.classList.remove('container'); + assert_equals(getComputedStyle(child).color, 'rgb(0, 128, 0)'); + + inner.classList.remove('container'); + assert_equals(getComputedStyle(child).color, 'rgb(0, 0, 0)'); + }, 'Changing the container type invalidates relevant descendants'); +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/container-type-layout-invalidation.html b/testing/web-platform/tests/css/css-contain/container-queries/container-type-layout-invalidation.html new file mode 100644 index 0000000000..3103de81f7 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/container-type-layout-invalidation.html @@ -0,0 +1,29 @@ +<!doctype html> +<title>container-type layout invalidation</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#size-container"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/cq-testcommon.js"></script> +<style> + #div { + width: fit-content; + } +</style> +<div id=div> + content +</div> +<script> + setup(() => assert_implements_container_queries()); + + test(function(t) { + t.add_cleanup(() => { div.style = ''; }); + + assert_greater_than(div.offsetWidth, 0); + assert_greater_than(div.offsetHeight, 0); + + div.style.containerType = 'size'; + + assert_equals(div.offsetWidth, 0); + assert_equals(div.offsetHeight, 0); + }, 'Changing container-type invalidates layout'); +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/container-type-parsing.html b/testing/web-platform/tests/css/css-contain/container-queries/container-type-parsing.html new file mode 100644 index 0000000000..5805a927b3 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/container-type-parsing.html @@ -0,0 +1,44 @@ +<!doctype html> +<meta charset="utf-8"> +<title>CSS Containment Test: Parsing of container-type</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-type"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/css/support/parsing-testcommon.js"></script> +<script src="support/cq-testcommon.js"></script> +<div id="target"></div> +<script> +setup(() => assert_implements_container_queries()); + +test_valid_value('container-type', 'initial'); +test_valid_value('container-type', 'inherit'); +test_valid_value('container-type', 'unset'); +test_valid_value('container-type', 'revert'); +test_valid_value('container-type', 'normal'); +test_valid_value('container-type', 'size'); +test_valid_value('container-type', 'inline-size'); + +test_invalid_value('container-type', 'none'); +test_invalid_value('container-type', 'auto'); +test_invalid_value('container-type', 'block-size'); +test_invalid_value('container-type', 'normal normal'); +test_invalid_value('container-type', 'normal inline-size'); +test_invalid_value('container-type', 'inline-size normal'); +test_invalid_value('container-type', 'inline-size inline-size'); +test_invalid_value('container-type', 'inline-size block-size'); +test_invalid_value('container-type', 'block-size inline-size'); +test_invalid_value('container-type', 'size inline-size'); +test_invalid_value('container-type', 'inline-size size'); +test_invalid_value('container-type', 'normal, normal'); +test_invalid_value('container-type', 'foo'); +test_invalid_value('container-type', '"foo"'); +test_invalid_value('container-type', 'foo, bar'); +test_invalid_value('container-type', '#fff'); +test_invalid_value('container-type', '1px'); +test_invalid_value('container-type', 'default'); +test_invalid_value('container-type', 'size nonsense'); +test_invalid_value('container-type', 'style'); +test_invalid_value('container-type', 'inline-size style', 'style inline-size'); +test_invalid_value('container-type', 'style inline-size'); +test_invalid_value('container-type', 'style size'); +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/container-units-animation.html b/testing/web-platform/tests/css/css-contain/container-queries/container-units-animation.html new file mode 100644 index 0000000000..cf1b9a8f34 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/container-units-animation.html @@ -0,0 +1,70 @@ +<!doctype html> +<title>Container Relative Units: Animation</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-lengths"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/cq-testcommon.js"></script> +<style> + #container { + container-type: size; + width: 200px; + height: 200px; + } + + @keyframes anim_cqw { from { top: 20cqw; } to { top: 40cqw; } } + @keyframes anim_cqh { from { top: 20cqh; } to { top: 40cqh; } } + @keyframes anim_cqi { from { top: 20cqi; } to { top: 40cqi; } } + @keyframes anim_cqb { from { top: 20cqb; } to { top: 40cqb; } } + @keyframes anim_cqmin { from { top: 20cqmin; } to { top: 40cqmin; } } + @keyframes anim_cqmax { from { top: 20cqmax; } to { top: 40cqmax; } } + + #container > div { + animation-delay: -5s; + animation-play-state: paused; + animation-duration: 10s; + animation-timing-function: linear; + } + + #element_cqw { animation-name: anim_cqw; } + #element_cqh { animation-name: anim_cqh; } + #element_cqi { animation-name: anim_cqi; } + #element_cqb { animation-name: anim_cqb; } + #element_cqmin { animation-name: anim_cqmin; } + #element_cqmax { animation-name: anim_cqmax; } + +</style> +<div id=container> + <div id=element_cqw></div> + <div id=element_cqh></div> + <div id=element_cqi></div> + <div id=element_cqb></div> + <div id=element_cqmin></div> + <div id=element_cqmax></div> +</div> +<script> + setup(() => assert_implements_container_queries()); + + const units = ['cqw', 'cqh', 'cqi', 'cqb', 'cqmin', 'cqmax']; + + for (let unit of units) { + test(() => { + let element = document.getElementById(`element_${unit}`) + assert_equals(getComputedStyle(element).top, '60px'); + }, `Animation using ${unit} unit`); + + test(() => { + let element = document.getElementById(`element_${unit}`) + assert_equals(getComputedStyle(element).top, '60px'); + try { + container.style.width = '300px'; + container.style.height = '300px'; + assert_equals(getComputedStyle(element).top, '90px'); + } finally { + container.style = ''; + } + + assert_equals(getComputedStyle(element).top, '60px'); + }, `Animation using ${unit} unit responds to changing container size`); + } + +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/container-units-basic.html b/testing/web-platform/tests/css/css-contain/container-queries/container-units-basic.html new file mode 100644 index 0000000000..166a003a29 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/container-units-basic.html @@ -0,0 +1,54 @@ +<!doctype html> +<title>Container Relative Units: cqi, cqb, etc</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-lengths"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/cq-testcommon.js"></script> +<style> + .inline { container-type: inline-size; } + .size { container-type: size; } + .inline.outer { width: 500px; } + .size.outer { height: 400px; } + .inline.inner { width: 300px; } +</style> +<div id=ref></div> +<div class="inline outer"> + <div class="size outer"> + <div class="inline inner"> + <div id=child>Test</div> + </div> + </div> +</div> +<script> + setup(() => assert_implements_container_queries()); + + function assert_unit_equals(element, actual, expected) { + try { + element.style.padding = actual; + ref.style.padding = expected; + assert_equals(getComputedStyle(element).paddingLeft, + getComputedStyle(ref).paddingLeft); + } finally { + element.style = ''; + ref.style = ''; + } + } + + test(function() { + assert_unit_equals(child, '0cqi', '0px'); + assert_unit_equals(child, '1cqi', '3px'); + assert_unit_equals(child, '10cqi', '30px'); + assert_unit_equals(child, '10cqw', '30px'); + assert_unit_equals(child, '10cqb', '40px'); + assert_unit_equals(child, '10cqh', '40px'); + assert_unit_equals(child, '10cqmin', '30px'); + assert_unit_equals(child, '10cqmax', '40px'); + }, 'Container relative units'); + + test(function() { + assert_unit_equals(child, '10cqi', '30px'); + assert_unit_equals(child, '10cqb', '40px'); + assert_unit_equals(child, 'calc(10cqi + 10cqb)', '70px'); + assert_unit_equals(child, 'max(10cqi, 10cqb)', '40px'); + }, 'Container relative units in math functions'); +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/container-units-computational-independence.html b/testing/web-platform/tests/css/css-contain/container-queries/container-units-computational-independence.html new file mode 100644 index 0000000000..694b665c79 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/container-units-computational-independence.html @@ -0,0 +1,20 @@ +<!doctype html> +<title>Container Relative Units: Computationally independent</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-lengths"> +<link rel="help" href="https://drafts.css-houdini.org/css-properties-values-api-1/#computationally-independent"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/cq-testcommon.js"></script> +<script> + setup(() => assert_implements_container_queries()); + + const units = ['cqw', 'cqh', 'cqi', 'cqb', 'cqmin', 'cqmax']; + + for (let unit of units) { + test(function() { + assert_throws_dom('SyntaxError', () => { + CSS.registerProperty({ name: '--x', inherits: false, syntax: '<length>', initialValue: `1${unit}` }); + }); + }, `Container relative unit ${unit} is not computationally independent`); + } +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/container-units-content-box.html b/testing/web-platform/tests/css/css-contain/container-queries/container-units-content-box.html new file mode 100644 index 0000000000..89a76e868c --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/container-units-content-box.html @@ -0,0 +1,58 @@ +<!doctype html> +<title>Container Relative Units: evaluate against the content box</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-lengths"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/cq-testcommon.js"></script> +<style> +.size { + container-type: size; + width:100px; + height:50px; + border: 10px solid green; + padding: 10px; +} +.border-box { + box-sizing: border-box; +} +</style> +<div id=ref></div> +<div class="size"> + <div id=child></div> +</div> +<div class="size border-box"> + <div id=child2></div> +</div> +<script> + setup(() => assert_implements_container_queries()); + + function assert_unit_equals(element, actual, expected) { + try { + element.style.padding = actual; + ref.style.padding = expected; + assert_equals(getComputedStyle(element).paddingLeft, + getComputedStyle(ref).paddingLeft); + } finally { + element.style = ''; + ref.style = ''; + } + } + + test(function() { + assert_unit_equals(child, '10cqi', '10px'); + assert_unit_equals(child, '10cqw', '10px'); + assert_unit_equals(child, '10cqb', '5px'); + assert_unit_equals(child, '10cqh', '5px'); + assert_unit_equals(child, '10cqmin', '5px'); + assert_unit_equals(child, '10cqmax', '10px'); + }, 'Container units are relative to the content box of the container'); + + test(function() { + assert_unit_equals(child2, '10cqi', '6px'); + assert_unit_equals(child2, '10cqw', '6px'); + assert_unit_equals(child2, '10cqb', '1px'); + assert_unit_equals(child2, '10cqh', '1px'); + assert_unit_equals(child2, '10cqmin', '1px'); + assert_unit_equals(child2, '10cqmax', '6px'); + }, 'Container units are relative to the content box of the container (box-sizing: border-box)'); +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/container-units-gradient-invalidation.html b/testing/web-platform/tests/css/css-contain/container-queries/container-units-gradient-invalidation.html new file mode 100644 index 0000000000..665a14dcaa --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/container-units-gradient-invalidation.html @@ -0,0 +1,38 @@ +<!DOCTYPE html> +<html class=reftest-wait> +<title>Container Relative Units in gradients</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-lengths"> +<link rel="match" href="container-units-gradient-ref.html"> +<script src="/common/reftest-wait.js"></script> +<script src="/common/rendering-utils.js"></script> +<style> + .container { + container-type: size; + width: 500px; + height: 400px; + display: flex; + flex-wrap: wrap; + } + .smaller { + width: 400px; + height: 300px; + } + .box { + width: 100px; + height: 100px; + margin: 5px; + } +</style> +<div class=container> + <div class=box style="background:linear-gradient(green 5cqw, blue 10cqh)"></div> + <div class=box style="background:linear-gradient(green 5cqi, blue 10cqb)"></div> + <div class=box style="background:linear-gradient(green 5cqmin, blue 10cqmax)"></div> + <div class=box style="background:radial-gradient(green 5cqw, blue 10cqh)"></div> + <div class=box style="background:conic-gradient(from 180deg at 10cqh, green, blue)"></div> +</div> +<script> + document.body.offsetTop; + document.querySelector('.container').classList.add('smaller'); + waitForAtLeastOneFrame().then(takeScreenshot); +</script> +</html> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/container-units-gradient-ref.html b/testing/web-platform/tests/css/css-contain/container-queries/container-units-gradient-ref.html new file mode 100644 index 0000000000..dbdabd9bc4 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/container-units-gradient-ref.html @@ -0,0 +1,21 @@ +<!DOCTYPE html> +<style> + .container { + width: 400px; + height: 300px; + display: flex; + flex-wrap: wrap; + } + .box { + width: 100px; + height: 100px; + margin: 5px; + } +</style> +<div class=container> + <div class=box style="background:linear-gradient(green 20px, blue 30px)"></div> + <div class=box style="background:linear-gradient(green 20px, blue 30px)"></div> + <div class=box style="background:linear-gradient(green 15px, blue 40px)"></div> + <div class=box style="background:radial-gradient(green 20px, blue 30px)"></div> + <div class=box style="background:conic-gradient(from 180deg at 30px, green, blue);"></div> +</div> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/container-units-gradient.html b/testing/web-platform/tests/css/css-contain/container-queries/container-units-gradient.html new file mode 100644 index 0000000000..3d6f5378c2 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/container-units-gradient.html @@ -0,0 +1,25 @@ +<!DOCTYPE html> +<title>Container Relative Units in gradients</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-lengths"> +<link rel="match" href="container-units-gradient-ref.html"> +<style> + .container { + container-type: size; + width: 400px; + height: 300px; + display: flex; + flex-wrap: wrap; + } + .box { + width: 100px; + height: 100px; + margin: 5px; + } +</style> +<div class=container> + <div class=box style="background:linear-gradient(green 5cqw, blue 10cqh)"></div> + <div class=box style="background:linear-gradient(green 5cqi, blue 10cqb)"></div> + <div class=box style="background:linear-gradient(green 5cqmin, blue 10cqmax)"></div> + <div class=box style="background:radial-gradient(green 5cqw, blue 10cqh)"></div> + <div class=box style="background:conic-gradient(from 180deg at 10cqh, green, blue);"></div> +</div> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/container-units-in-at-container-dynamic.html b/testing/web-platform/tests/css/css-contain/container-queries/container-units-in-at-container-dynamic.html new file mode 100644 index 0000000000..c1f929241c --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/container-units-in-at-container-dynamic.html @@ -0,0 +1,37 @@ +<!doctype html> +<title>Container Relative Units: in @container prelude (dynamic)</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-lengths"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/cq-testcommon.js"></script> +<style> + #outer { + container-type: size; + width: 40px; + height: 40px; + } + #container { + container-type: size; + width: 16px; + height: 16px; + } + + @container ((width = 16px) and (width = 50cqw)) { #child { --cqw:true; } } + +</style> + +<div id=outer> + <div id=container> + <div id=child>Test</div> + </div> +</div> + +<script> + setup(() => assert_implements_container_queries()); + + test(() => { + assert_equals(getComputedStyle(child).getPropertyValue('--cqw'), ''); + outer.style.width = '32px'; + assert_equals(getComputedStyle(child).getPropertyValue('--cqw'), 'true'); + }, 'Query with container-relative units are responsive to changes'); +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/container-units-in-at-container-fallback.html b/testing/web-platform/tests/css/css-contain/container-queries/container-units-in-at-container-fallback.html new file mode 100644 index 0000000000..3784499c38 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/container-units-in-at-container-fallback.html @@ -0,0 +1,68 @@ +<!DOCTYPE html> +<title>Container Relative Units: container relative units fall back to small viewport</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-lengths"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/cq-testcommon.js"></script> +<style> + iframe { + width: 200px; + height: 320px; + } +</style> +<iframe id=iframe srcdoc=" + <style> + #parent { + container-type: inline-size; + width: 64px; + height: 50px; + } + #container { + container-type: size; + width: 32px; + height: 32px; + } + + #target1, #target2 { color: green; } + + /* Unit should evaluate against width of #parent */ + @container ((height = 32px) and (height = 50cqw)) { + #target1 { color: blue; } + } + + /* Unit should evaluate against height of iframe */ + @container ((height = 32px) and (height = 10cqh)) { + #target2 { color: blue; } + } + + </style> + <div id=parent> + <div id=container> + <div id=target1></div> + <div id=target2></div> + </div> + </div> +"></iframe> +<script> + setup(() => assert_implements_container_queries()); + + function waitForLoad(w) { + return new Promise(resolve => w.addEventListener('load', resolve)); + } + + promise_test(async () => { + await waitForLoad(window); + let inner_target1 = iframe.contentDocument.querySelector('#target1'); + let inner_target2 = iframe.contentDocument.querySelector('#target2'); + assert_equals(getComputedStyle(inner_target1).color, 'rgb(0, 0, 255)'); + assert_equals(getComputedStyle(inner_target2).color, 'rgb(0, 0, 255)'); + + iframe.style = 'height:400px'; + + // #target1 is not affected since it evaluated against another container. + // #target2 *is* affected, because it evaluated against the iframe size + // which just changed. + assert_equals(getComputedStyle(inner_target1).color, 'rgb(0, 0, 255)'); + assert_equals(getComputedStyle(inner_target2).color, 'rgb(0, 128, 0)'); + }, 'Use small viewport size as fallback'); +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/container-units-in-at-container.html b/testing/web-platform/tests/css/css-contain/container-queries/container-units-in-at-container.html new file mode 100644 index 0000000000..9ddca55ec1 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/container-units-in-at-container.html @@ -0,0 +1,111 @@ +<!doctype html> +<title>Container Relative Units: in @container prelude</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-lengths"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/cq-testcommon.js"></script> +<style> + .size { container-type: size; } + .inline { container-type: inline-size; } + .ancestor { + container-type: size; + width: 64px; + height: 160px; + } + .parent { + container-type: inline-size; + width: 32px; + height: 77px; + } + .container { + container-type: size; + width: 16px; + height: 16px; + } + + /* Unit should resolve against .parent width. */ + @container ((width = 16px) and (width = 50cqw)) { #child1 { --cqw:true; } } + + /* Unit should resolve against .ancestor height. */ + @container ((width = 16px) and (width = 10cqh)) { #child1 { --cqh:true; } } + + /* Unit should resolve against .parent width. */ + @container ((width = 16px) and (width = 50cqi)) { #child1 { --cqi:true; } } + + /* Unit should resolve against .ancestor height. */ + @container ((width = 16px) and (width = 10cqb)) { #child1 { --cqb:true; } } + + /* Unit should resolve against biggest of w/h. */ + @container ((width = 16px) and (width = 10cqmax)) { #child1 { --cqmax:true; } } + + /* Unit should resolve against smallest of w/h. */ + @container ((width = 16px) and (width = 50cqmin)) { #child1 { --cqmin:true; } } + + /* Flipped writing mode: */ + + /* Non-logical units are the same as above */ + @container ((width = 16px) and (width = 50cqw)) { #child2 { --cqw:true; } } + @container ((width = 16px) and (width = 10cqh)) { #child2 { --cqh:true; } } + @container ((width = 16px) and (width = 10cqmax)) { #child2 { --cqmax:true; } } + @container ((width = 16px) and (width = 50cqmin)) { #child2 { --cqmin:true; } } + + /* Unit should resolve against .ancestor height. */ + @container ((width = 16px) and (width = 50cqb)) { #child2 { --cqi:true; } } + + /* Unit should resolve against .parent width. */ + @container ((width = 16px) and (width = 10cqi)) { #child2 { --cqb:true; } } +</style> + +<div class=ancestor> + <div class=parent> + <div class=container> + <div id=child1>Test1</div> + </div> + </div> +</div> + +<div class=ancestor> + <div class=parent> + <div class=container style="writing-mode:vertical-rl;"> + <div id=child2>Test1</div> + </div> + </div> +</div> + +<script> + setup(() => assert_implements_container_queries()); + + let units = [ + 'cqw', + 'cqh', + 'cqi', + 'cqb', + 'cqmin', + 'cqmax', + ]; + + for (let unit of units) { + test(() => { + assert_equals(getComputedStyle(child1).getPropertyValue(`--${unit}`), 'true'); + }, `${unit} unit resolves against appropriate container`); + } + + // Ensure that the writing mode of the subject element is not relevant for + // container-relative units in the @container prelude. + for (let unit of units) { + test((t) => { + t.add_cleanup(() => { + child1.style = ''; + }); + child1.style.writingMode = 'vertical-rl'; + assert_equals(getComputedStyle(child1).getPropertyValue(`--${unit}`), 'true'); + }, `${unit} unit resolves against appropriate container (vertical writing-mode on subject)`); + } + + for (let unit of units) { + test(() => { + assert_equals(getComputedStyle(child2).getPropertyValue(`--${unit}`), 'true'); + }, `${unit} unit resolves against appropriate container (vertical writing-mode on container)`); + } + +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/container-units-ineligible-container.html b/testing/web-platform/tests/css/css-contain/container-queries/container-units-ineligible-container.html new file mode 100644 index 0000000000..8882d4a38b --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/container-units-ineligible-container.html @@ -0,0 +1,44 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>Container Relative Units: ineligible container</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-lengths"> +<link rel="author" title="Oriol Brufau" href="mailto:obrufau@igalia.com"> +<style> + #grandparent, #parent { container-type: size; } + #grandparent { width: 300px; height: 250px; } + #parent { width: 200px; height: 150px; } + #target { width: 10cqw; height: 10cqh; } +</style> +<div id="log"></div> +<div id="grandparent"> + <div id="parent"> + <div id="target"></div> + </div> +</div> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/cq-testcommon.js"></script> +<script> + setup(() => assert_implements_container_queries()); + const cases = { + "/* basic */": [20, 15], + "display: table": [30, 25], + "display: table-cell": [30, 25], + "display: inline": [30, 25], + "display: contents": [30, 25], + "display: none": [30, 25], + "container-type: normal": [30, 25], + "container-type: inline-size": [20, 25], + "container-type: inline-size; writing-mode: vertical-lr": [30, 15], + }; + const parent = document.getElementById("parent"); + const target = document.getElementById("target"); + const cs = getComputedStyle(target); + for (let [style, [width, height]] of Object.entries(cases)) { + test(() => { + parent.style.cssText = style; + assert_equals(cs.width, width + "px", "width"); + assert_equals(cs.height, height + "px", "height"); + }, style); + } +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/container-units-invalidation.html b/testing/web-platform/tests/css/css-contain/container-queries/container-units-invalidation.html new file mode 100644 index 0000000000..abb766cd0c --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/container-units-invalidation.html @@ -0,0 +1,119 @@ +<!doctype html> +<title>Container Relative Units: Invalidation</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-lengths"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/cq-testcommon.js"></script> +<style> + #inline { container-type: inline-size; } + #size, #outer { container-type: size; } + .h600 { height: 600px; } + .w500 { width: 500px; } + .h400 { height: 400px; } + .w300 { width: 300px; } + .child { + padding-left: 10cqi; + padding-right: 10cqb; + } +</style> +<div id=ref></div> +<div id=outer class="h600"> + <div id=size class="w500 h400"> + <div id=inline class="w300"> + <div id=child class="child">Test</div> + <div><div id=deeper class="child">Test</div></div> + </div> + </div> +</div> +<script> + setup(() => assert_implements_container_queries()); + + function assert_cqi_equals(element, expected) { + assert_equals(getComputedStyle(element).paddingLeft, expected); + } + + function assert_cqb_equals(element, expected) { + assert_equals(getComputedStyle(element).paddingRight, expected); + } + + test(function(t) { + assert_cqi_equals(child, '30px'); + assert_cqi_equals(deeper, '30px'); + + try { + inline.style.containerType = 'normal'; + assert_cqi_equals(child, '50px'); + assert_cqi_equals(deeper, '50px'); + } finally { + inline.style = ''; + } + + assert_cqi_equals(child, '30px'); + assert_cqi_equals(deeper, '30px'); + }, `cqi respond when selected container changes type (inline-size -> normal)`); + + test(function() { + assert_cqb_equals(child, '40px'); + assert_cqb_equals(deeper, '40px'); + + try { + size.style.containerType = 'normal'; + assert_cqb_equals(child, '60px'); + assert_cqb_equals(deeper, '60px'); + } finally { + size.style = ''; + } + + assert_cqb_equals(child, '40px'); + assert_cqb_equals(deeper, '40px'); + }, `cqb respond when selected container changes type (size -> normal)`); + + test(function() { + assert_cqb_equals(child, '40px'); + assert_cqb_equals(deeper, '40px'); + + try { + inline.style.containerType = 'size'; + inline.style.height = '200px'; + assert_cqb_equals(child, '20px'); + assert_cqb_equals(deeper, '20px'); + } finally { + inline.style = ''; + } + + assert_cqb_equals(child, '40px'); + assert_cqb_equals(deeper, '40px'); + }, `cqb respond when intermediate container changes type (inline-size -> size)`); + + test(function() { + assert_cqi_equals(child, '30px'); + assert_cqi_equals(deeper, '30px'); + + try { + inline.style.width = '50px'; + assert_cqi_equals(child, '5px'); + assert_cqi_equals(deeper, '5px'); + } finally { + inline.style = ''; + } + + assert_cqi_equals(child, '30px'); + assert_cqi_equals(deeper, '30px'); + }, 'cqi respond when selected container changes inline-size'); + + test(function() { + assert_cqb_equals(child, '40px'); + assert_cqb_equals(deeper, '40px'); + + try { + size.style.height = '50px'; + assert_cqb_equals(child, '5px'); + assert_cqb_equals(deeper, '5px'); + } finally { + size.style = ''; + } + + assert_cqb_equals(child, '40px'); + assert_cqb_equals(deeper, '40px'); + }, 'cqb respond when selected container changes block-size'); +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/container-units-media-queries.html b/testing/web-platform/tests/css/css-contain/container-queries/container-units-media-queries.html new file mode 100644 index 0000000000..7b76f654e5 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/container-units-media-queries.html @@ -0,0 +1,61 @@ +<!DOCTYPE html> +<title>Container-relative units in @media</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-lengths"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/cq-testcommon.js"></script> + +<style> + iframe { + width: 200px; + height: 100px; + } +</style> + +<iframe id=iframe></iframe> + +<script> +setup(() => assert_implements_container_queries()); + +const doc = iframe.contentDocument; +const win = iframe.contentWindow; + +function test_media_query(feature, result, description) { + test((t) => { + t.add_cleanup(() => { doc.body.innerHTML = ''; }) + doc.body.innerHTML = ` + <style> + body { + color: red; + } + @media (${feature}) { + body { + color: green; + } + } + </style> + `; + assert_equals(win.getComputedStyle(doc.body).color, result); + }, description); +} + +function test_media_query_applies(feature) { + test_media_query(feature, 'rgb(0, 128, 0)', `@media(${feature}) applies`); +} + +function test_media_query_does_not_apply(feature) { + test_media_query(feature, 'rgb(255, 0, 0)', `@media(${feature}) does not apply`); +} + +// Container-relative units resolve against the "small viewport size" for +// media queries. +test_media_query_applies('width:100cqw'); +test_media_query_applies('width:100cqi'); +test_media_query_applies('width:100cqmax'); +test_media_query_applies('height:100cqh'); +test_media_query_applies('height:100cqb'); +test_media_query_applies('height:100cqmin'); +test_media_query_does_not_apply('width:90cqw'); +test_media_query_does_not_apply('height:90cqh'); + +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/container-units-rule-cache-ref.html b/testing/web-platform/tests/css/css-contain/container-queries/container-units-rule-cache-ref.html new file mode 100644 index 0000000000..6c8261959f --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/container-units-rule-cache-ref.html @@ -0,0 +1,18 @@ +<!doctype html> +<meta charset="utf-8"> +<style> + .container { + width: 100px; + } + + .half { + height: 50%; + background-color: green; + } +</style> +<div class="container" style="height: 100px"> + <div class="half"></div> +</div> +<div class="container" style="height: 200px"> + <div class="half"></div> +</div> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/container-units-rule-cache.html b/testing/web-platform/tests/css/css-contain/container-queries/container-units-rule-cache.html new file mode 100644 index 0000000000..cc93f7793a --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/container-units-rule-cache.html @@ -0,0 +1,24 @@ +<!doctype html> +<meta charset="utf-8"> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-lengths"> +<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1832481"> +<link rel="author" href="mailto:emilio@crisal.io" title="Emilio Cobos Álvarez"> +<link rel="author" href="https://mozilla.org" title="Mozilla"> +<link rel="match" href="container-units-rule-cache-ref.html"> +<style> + .container { + width: 100px; + container-type: size; + } + + .half { + height: 50cqh; + background-color: green; + } +</style> +<div class="container" style="height: 100px"> + <div class="half"></div> +</div> +<div class="container" style="height: 200px"> + <div class="half"></div> +</div> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/container-units-selection.html b/testing/web-platform/tests/css/css-contain/container-queries/container-units-selection.html new file mode 100644 index 0000000000..16a44cd176 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/container-units-selection.html @@ -0,0 +1,101 @@ +<!doctype html> +<title>Container Relative Units: Advanced Container Selection</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-lengths"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/cq-testcommon.js"></script> +<style> + * { writing-mode: initial; } + .inline { container-type: inline-size; } + .size { container-type: size; } + .vertical { writing-mode: vertical-rl; } + .w500 { width: 500px; } + .h400 { height: 400px; } + .w300 { width: 300px; } + .h200 { height: 200px; } + .w100 { width: 100px; } +</style> +<div id=ref></div> +<div id=c1> + <div id=c2> + <div id=c3> + <div id=c4> + <div id=child>Test</div> + </div> + </div> + </div> +</div> +<script> + setup(() => assert_implements_container_queries()); + + function assert_unit_equals(element, actual, expected) { + try { + element.style.padding = actual; + ref.style.padding = expected; + assert_equals(getComputedStyle(element).paddingLeft, + getComputedStyle(ref).paddingLeft); + } finally { + element.style = ''; + ref.style = ''; + } + } + + test(() => { + try { + c1.className = 'inline w500'; // Selected by nothing. + c2.className = 'size h400 w300'; // Selected by cqh, cqb. + c3.className = 'inline w100'; // Selected by cqw, cqi. + assert_unit_equals(child, '10cqw', '10px'); + assert_unit_equals(child, '10cqi', '10px'); + assert_unit_equals(child, '10cqh', '40px'); + assert_unit_equals(child, '10cqb', '40px'); + assert_unit_equals(child, '10cqmin', '10px'); + assert_unit_equals(child, '10cqmax', '40px'); + + c3.className = ''; // cqw, cqi now selects c2 instead. + assert_unit_equals(child, '10cqw', '30px'); + assert_unit_equals(child, '10cqi', '30px'); + assert_unit_equals(child, '10cqh', '40px'); + assert_unit_equals(child, '10cqb', '40px'); + assert_unit_equals(child, '10cqmin', '30px'); + assert_unit_equals(child, '10cqmax', '40px'); + + } finally { + for (let c of [c1, c2, c3, c4, child]) + c.className = ''; + } + }, 'Container units select the proper container'); + + test(() => { + try { + c1.className = 'size w500 h400'; + c2.className = 'inline w300 h200'; + + // [cqi, cqb] corresponds to [cqw, cqh]. + assert_unit_equals(child, '10cqw', '30px'); + assert_unit_equals(child, '10cqi', '30px'); + assert_unit_equals(child, '10cqh', '40px'); + assert_unit_equals(child, '10cqb', '40px'); + + child.className = 'vertical'; + // [cqi, cqb] now corresponds to [cqh, cqw]. + assert_unit_equals(child, '10cqw', '30px'); + assert_unit_equals(child, '10cqi', '40px'); + assert_unit_equals(child, '10cqh', '40px'); + assert_unit_equals(child, '10cqb', '30px'); + + c2.classList.add('vertical'); + // The inline containment on #c2 now applies to the vertical axis. + // [cqi, cqb] still corresponds to [cqh, cqw], but we now expect + // cqh to resolve against #c2, and cqw to resolve against #c1. + assert_unit_equals(child, '10cqw', '50px'); + assert_unit_equals(child, '10cqi', '20px'); + assert_unit_equals(child, '10cqh', '20px'); + assert_unit_equals(child, '10cqb', '50px'); + + } finally { + for (let c of [c1, c2, c3, c4, child]) + c.className = ''; + } + }, 'Units respond to the writing-mode of the element'); +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/container-units-shadow.html b/testing/web-platform/tests/css/css-contain/container-queries/container-units-shadow.html new file mode 100644 index 0000000000..c7fd0500f2 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/container-units-shadow.html @@ -0,0 +1,65 @@ +<!doctype html> +<title>Container Relative Units: Shadow DOM</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-lengths"> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-queries"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/declarative-shadow-dom-polyfill.js"></script> +<script src="support/cq-testcommon.js"></script> +<style> + #outer { + container-type: size; + width: 200px; + height: 200px; + } + #direct { + container-type: inline-size; + width: 50cqw; + height: 50cqh; + } + #nondirect { + width: 10cqw; + height: 10cqh; + background: green; + } +</style> +<div id=outer> + <div> + <template shadowrootmode="open"> + <style> + #inner { + container-type: size; + width: 30px; + height: 30px; + } + </style> + <div id=inner> + <slot></slot> + </div> + </template> + <div> + <div id=direct> + <div id=nondirect> + </div> + </div> + </div> + </div> +</div> +<script> + setup(() => { + assert_implements_container_queries(); + polyfill_declarative_shadow_dom(document); + }); + + test(() => { + let cs = getComputedStyle(direct); + assert_equals(cs.width, '100px'); + assert_equals(cs.height, '100px'); + }, 'Direct slotted child queries shadow-including ancestors'); + + test(() => { + let cs = getComputedStyle(nondirect); + assert_equals(cs.width, '10px'); // #direct + assert_equals(cs.height, '20px'); // #outer + }, 'Nondirect slotted child queries shadow-including ancestors'); +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/container-units-small-viewport-fallback.html b/testing/web-platform/tests/css/css-contain/container-queries/container-units-small-viewport-fallback.html new file mode 100644 index 0000000000..6c8851681f --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/container-units-small-viewport-fallback.html @@ -0,0 +1,70 @@ +<!doctype html> +<title>Container Relative Units: fall back to small viewport</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-lengths"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/cq-testcommon.js"></script> +<style> + iframe { + width: 200px; + height: 40px; + } +</style> +<iframe id=iframe srcdoc=" + <style> + #container { + container-type: inline-size; + width: 70px; + height: 30px; + } + #target { + left: 10cqw; + top: 10cqh; + right: 10cqi; + bottom: 10cqb; + margin-left: 10cqmax; + margin-right: 10cqmin; + } + </style> + <div id=container> + <div id=target></div> + </div> +"></iframe> + +<script> + setup(() => assert_implements_container_queries()); + + function waitForLoad(w) { + return new Promise(resolve => w.addEventListener('load', resolve)); + } + + promise_test(async () => { + await waitForLoad(window); + let inner_target = iframe.contentDocument.querySelector('#target'); + + // Since there's an inline-size container, cqw/cqi should evaluate against + // that. + assert_equals(getComputedStyle(inner_target).left, '7px'); // 10cqw + assert_equals(getComputedStyle(inner_target).right, '7px'); // 10cqi + + // However, there is no size container, so cqh/cqb should evaluate against + // the small viewport size. + assert_equals(getComputedStyle(inner_target).top, '4px'); // 10cqh + assert_equals(getComputedStyle(inner_target).bottom, '4px'); // 10cqb + + assert_equals(getComputedStyle(inner_target).marginLeft, '7px'); // 10cqmax + assert_equals(getComputedStyle(inner_target).marginRight, '4px'); // 10cqmin + + iframe.style = 'width:400px;height:80px'; + + // Not affected by resize: + assert_equals(getComputedStyle(inner_target).left, '7px'); // 10cqw + assert_equals(getComputedStyle(inner_target).right, '7px'); // 10cqi + + // Affected: + assert_equals(getComputedStyle(inner_target).top, '8px'); // 10cqh + assert_equals(getComputedStyle(inner_target).bottom, '8px'); // 10cqb + assert_equals(getComputedStyle(inner_target).marginLeft, '8px'); // 10cqmax + assert_equals(getComputedStyle(inner_target).marginRight, '7px'); // 10cqmin + }, 'Use small viewport size as fallback'); +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/container-units-svglength.html b/testing/web-platform/tests/css/css-contain/container-queries/container-units-svglength.html new file mode 100644 index 0000000000..8bb227c049 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/container-units-svglength.html @@ -0,0 +1,95 @@ +<!DOCTYPE html> +<title>CSS Container Queries Test: container-relative units in SVGLength</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-lengths"> +<link rel="help" href="https://svgwg.org/svg2-draft/types.html#InterfaceSVGLength"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/cq-testcommon.js"></script> +<script src="/resources/SVGAnimationTestCase-testharness.js"></script> +<style> + #container { + container-type: size; + width: 200px; + height: 150px; + } +</style> +<div id=container> + <svg id=rootSVGElement> + <rect id="rect1" width="10cqw" height="10cqh"/> + <rect id="rect2" width="10cqi" height="10cqb"/> + <rect id="rect3" width="10cqmin" height="10cqmax"/> + <rect id="rect4" width="calc(10cqmin + 10cqmax)" height="calc(10cqw + 3px)"/> + <rect id="rect_dynamic"/> + <rect id="rect_animated" width="42px" height="42px" fill="green"> + <animate id=animation attributeName=width from="5cqw" to="10cqw" begin="0s" dur="4s"/> + </rect> + </svg> +</div> +<script> + setup(() => { + assert_implements_container_queries(); + container.offsetTop; + }); + + function cleanup() { + rect_dynamic.removeAttribute('width'); + rect_dynamic.removeAttribute('height'); + } + + test(() => { + assert_equals(rect1.width.baseVal.unitType, SVGLength.SVG_LENGTHTYPE_UNKNOWN); + }, 'unitType with container-relative units'); + + test(() => { + assert_equals(rect1.width.baseVal.value, 20); + assert_equals(rect1.height.baseVal.value, 15); + }, 'cqw,cqh can be resolved'); + + test(() => { + assert_equals(rect2.width.baseVal.value, 20); + assert_equals(rect2.height.baseVal.value, 15); + }, 'cqi,cqb can be resolved'); + + test(() => { + assert_equals(rect3.width.baseVal.value, 15); + assert_equals(rect3.height.baseVal.value, 20); + }, 'cqmin,cqmax can be resolved'); + + test(() => { + assert_equals(rect4.width.baseVal.value, 35); + assert_equals(rect4.height.baseVal.value, 23); + }, 'calc() with container-relative units can be resolved'); + + test((t) => { + t.add_cleanup(cleanup); + rect_dynamic.setAttribute('width', '20cqw'); + rect_dynamic.setAttribute('height', '20cqh'); + assert_equals(rect_dynamic.width.baseVal.value, 40); + assert_equals(rect_dynamic.height.baseVal.value, 30); + + rect_dynamic.width.baseVal.value = 80; + rect_dynamic.height.baseVal.value = 45; + assert_equals(rect_dynamic.getAttribute('width'), '80'); + assert_equals(rect_dynamic.getAttribute('height'), '45'); + }, 'Can modify value with container-relative units'); + + smil_async_test((t) => { + t.add_cleanup(cleanup); + let assert_width = (expected) => { + let epsilon = 1.0; + return () => { + assert_approx_equals(rect_animated.width.animVal.value, expected, epsilon); + }; + }; + const expectedValues = [ + // [animationId, time, sampleCallback] + ["animation", 0.0, assert_width(10)], + ["animation", 2.0, assert_width(15)], + ["animation", 3.999, assert_width(20)], + ["animation", 4, assert_width(42)], + ]; + + runAnimationTest(t, expectedValues); + }); + +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/container-units-typed-om.html b/testing/web-platform/tests/css/css-contain/container-queries/container-units-typed-om.html new file mode 100644 index 0000000000..6da3306fdf --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/container-units-typed-om.html @@ -0,0 +1,59 @@ +<!doctype html> +<title>Container Relative Units: CSS Typed OM</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-lengths"> +<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#stylepropertymap"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/cq-testcommon.js"></script> +<div id=element></div> +<script> + setup(() => assert_implements_container_queries()); + + const units = ['cqw', 'cqh', 'cqi', 'cqb', 'cqmin', 'cqmax']; + const functions = { + cqw: CSS.cqw, + cqh: CSS.cqh, + cqi: CSS.cqi, + cqb: CSS.cqb, + cqmin: CSS.cqmin, + cqmax: CSS.cqmax, + }; + + for (let unit of units) { + let func = functions[unit]; + + test(() => { + assert_equals(`${func(10)}`, `10${unit}`); + }, `CSS.${unit} function`); + + test(() => { + try { + element.style.top = `10${unit}`; + let value = element.attributeStyleMap.get('top'); + assert_equals(value.value, 10); + assert_equals(value.unit, unit); + } finally { + element.style = ''; + } + }, `Reify value with ${unit} unit`); + + test(() => { + try { + element.attributeStyleMap.set('top', `10${unit}`); + assert_equals(element.style.top, `10${unit}`); + } finally { + element.style = ''; + } + }, `Set value with ${unit} unit (string)`); + + test(() => { + try { + element.attributeStyleMap.set('top', func(10)); + assert_equals(element.style.top, `10${unit}`); + } finally { + element.style = ''; + } + }, `Set value with ${unit} unit (CSS.${unit})`); + } + +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/counters-flex-circular.html b/testing/web-platform/tests/css/css-contain/container-queries/counters-flex-circular.html new file mode 100644 index 0000000000..d60049e26c --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/counters-flex-circular.html @@ -0,0 +1,76 @@ +<!doctype html> +<title>CSS Container Queries Test: counters inside container should not affect container size via flex layout</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-type"> +<link rel="stylesheet" href="/fonts/ahem.css"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/cq-testcommon.js"></script> +<style> + #flex { + width: 200px; + display: flex; + flex-direction: row; + counter-reset: my-count 0; + } + /* #item1 grows to use remaining space given #item2's content */ + #item1 { + flex-grow: 1; + height: 100px; + } + #container { + container-type: size; + } + #item2 { + flex-grow: 0; + font: 50px/1 Ahem; + } + /* #item2 size depends on generated content which depends on my-count + counter. */ + #item2::before { + display: inline-block; + content: counter(my-count); + } + /* The counter-increment inside the container should not affect the size of + #item2 because of style containment. Otherwise we would have a + circularity. */ + @container (min-width: 125px) { + #inner { + counter-increment: my-count 10; + background-color: green; + } + } +</style> +<div id="flex"> + <div id="item1"> + <div id="container"> + <div id="inner"></div> + </div> + </div> + <div id="item2"></div> +</div> +<script> + setup(() => assert_implements_container_queries()); + + const item1_width = parseInt(getComputedStyle(item1).width); + const item2_width = parseInt(getComputedStyle(item2).width); + const container_width = parseInt(getComputedStyle(container).width); + const inner_width = parseInt(getComputedStyle(inner).width); + + test(() => { + assert_equals(item1_width, container_width); + assert_equals(item1_width, inner_width); + }, "#item1, #container, and #inner should all have the same width: " + item1_width); + + test(() => { + let expected_background = container_width >= 125 ? "rgb(0, 128, 0)" : "rgba(0, 0, 0, 0)"; + assert_equals(getComputedStyle(inner).backgroundColor, expected_background); + }, "The container query should match the layed out width"); + + test(() => { + assert_equals(item1_width + item2_width, 200); + }, "The sum of the item widths should match the flexbox width"); + + test(() => { + assert_equals(parseInt(getComputedStyle(item2, "::before").width), item2_width); + }, "The size of the flex item #2 should be given by its contents"); +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/counters-in-container-dynamic.html b/testing/web-platform/tests/css/css-contain/container-queries/counters-in-container-dynamic.html new file mode 100644 index 0000000000..d85ab6cb42 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/counters-in-container-dynamic.html @@ -0,0 +1,29 @@ +<!doctype html> +<title>CSS Container Queries Test: counter updates</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-type"> +<link rel="match" href="counters-ref.html"> +<style> + #container { + container-type: size; + width: 200px; + height: 200px; + } + + #counter::before { + content: counter(my-counter); + } + + @container (min-width: 300px) { + #counter { + counter-reset: my-counter 100; + } + } +</style> +<p>Pass if you see the number 100 below.</p> +<div id="container"> + <div id="counter"></div> +</div> +<script> + container.offsetTop; + container.style.width = "400px"; +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/counters-in-container.html b/testing/web-platform/tests/css/css-contain/container-queries/counters-in-container.html new file mode 100644 index 0000000000..376f52ea7c --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/counters-in-container.html @@ -0,0 +1,25 @@ +<!doctype html> +<title>CSS Container Queries Test: counters depending on container queries</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-type"> +<link rel="match" href="counters-ref.html"> +<style> + #container { + container-type: size; + width: 200px; + height: 200px; + } + + #counter::before { + content: counter(my-counter); + } + + @container (min-width: 200px) { + #counter { + counter-reset: my-counter 100; + } + } +</style> +<p>Pass if you see the number 100 below.</p> +<div id="container"> + <div id="counter"></div> +</div> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/counters-ref.html b/testing/web-platform/tests/css/css-contain/container-queries/counters-ref.html new file mode 100644 index 0000000000..303c1e89bd --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/counters-ref.html @@ -0,0 +1,4 @@ +<!doctype html> +<title>CSS Test Reference</title> +<p>Pass if you see the number 100 below.</p> +<div>100</div> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/crashtests/br-crash.html b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/br-crash.html new file mode 100644 index 0000000000..6631ba2fd5 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/br-crash.html @@ -0,0 +1,6 @@ +<!DOCTYPE html> +<title>Don't crash for blocky <br> (etc) with inline-size containment</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#contain-property"> +<link rel="help" href="https://crbug.com/1313444"> +<br style="container-type:inline-size; display:block;"> +<wbr style="container-type:inline-size; display:block;"> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/crashtests/canvas-as-container-crash.html b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/canvas-as-container-crash.html new file mode 100644 index 0000000000..ae7fe8dc16 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/canvas-as-container-crash.html @@ -0,0 +1,10 @@ +<!doctype html> +<title>CSS Container Queries Test: Absolute positioned canvas container crash</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#size-container"> +<link rel="help" href="https://crbug.com/1289850"> +<p>Pass if there is no crash.</p> +<canvas id="canv" style="display:block;position:absolute;container-type:inline-size"></canvas> +<script> + canv.offsetTop; + canv.appendChild(document.createElement("span")); +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/crashtests/chrome-bug-1289718-000-crash.html b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/chrome-bug-1289718-000-crash.html new file mode 100644 index 0000000000..f30461919a --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/chrome-bug-1289718-000-crash.html @@ -0,0 +1,6 @@ +<!DOCTYPE html> +<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org"> +<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1289718"> +<div style="container-type:inline-size;"> + <span style="columns:2;"></span> +</div> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/crashtests/chrome-bug-1289718-001-crash.html b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/chrome-bug-1289718-001-crash.html new file mode 100644 index 0000000000..ce530fb2c8 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/chrome-bug-1289718-001-crash.html @@ -0,0 +1,6 @@ +<!DOCTYPE html> +<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org"> +<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1289718"> +<div style="container-type:inline-size;"> + <video style="columns:2;"></video> +</div> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/crashtests/chrome-bug-1346969-crash.html b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/chrome-bug-1346969-crash.html new file mode 100644 index 0000000000..37c74cf8cb --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/chrome-bug-1346969-crash.html @@ -0,0 +1,14 @@ +<!doctype html> +<title>Chrome crash bug 1346969</title> +<link rel="help" href="https://crbug.com/1346969"> +<table id="table"> </table> +<script> + document.body.offsetTop; + table.style.containerType = "inline-size"; + table.style.appearance = "auto"; + table.style.columnCount = 2; + table.createTBody(); + table.createCaption(); + document.body.offsetTop; + table.style.whiteSpace = "pre-wrap"; +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/crashtests/chrome-bug-1362391-crash.html b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/chrome-bug-1362391-crash.html new file mode 100644 index 0000000000..d4e1fec400 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/chrome-bug-1362391-crash.html @@ -0,0 +1,8 @@ +<!doctype html> +<title>DCHECK failure for style recalc from layout tree rebuild</title> +<link rel="help" href="https://crbug.com/1362391"> +<div style="display:table-column-group"> + <div style="container-type:size"> + <image title="crash"></image> + </div> +</div> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/crashtests/chrome-bug-1429955-crash.html b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/chrome-bug-1429955-crash.html new file mode 100644 index 0000000000..bdf4002753 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/chrome-bug-1429955-crash.html @@ -0,0 +1,5 @@ +<!DOCTYPE html> +<link rel="help" href="https://crbug.com/1429955.html"> +<div id="mc" style="display:list-item; width:0; columns:2; container-type:size;"> + <div id="abs" style="position:absolute; container-type:inline-size;">line</div> +</div> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/crashtests/chrome-layout-root-crash.html b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/chrome-layout-root-crash.html new file mode 100644 index 0000000000..e3e709a240 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/chrome-layout-root-crash.html @@ -0,0 +1,17 @@ +<!doctype html> +<html class="reftest-wait"> +<link rel="help" href="https://crbug.com/1371820"> +<style> + body, div, img { container-type: size; } +</style> +<p>Pass if no crash.</p> +<div id="div"><img id="img" alt="a"></div> +<script> + requestAnimationFrame(() => requestAnimationFrame(() => { + // Adds a layout root inside the div size container. + img.alt = img.src = "b"; + // Marks div size container for layout which skips style recalc for the sub-tree. + div.style.width = "500px"; + document.documentElement.classList.remove("reftest-wait"); + })); +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/crashtests/chrome-quotes-crash.html b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/chrome-quotes-crash.html new file mode 100644 index 0000000000..363f96fd02 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/chrome-quotes-crash.html @@ -0,0 +1,11 @@ +<!doctype html> +<title>Container Queries Test: Quotes update outside container being laid out causes crash</title> +<link rel="help" href="https://crbug.com/1313003"> +<style> + div { container-type: size } +</style> +<div style="float: right"> + <span></span> + <div style="position:absolute"><q></q></div> + <q></q> +</div> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/crashtests/chrome-remove-insert-evaluator-crash.html b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/chrome-remove-insert-evaluator-crash.html new file mode 100644 index 0000000000..986f6b0bf6 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/chrome-remove-insert-evaluator-crash.html @@ -0,0 +1,15 @@ +<!doctype html> +<title>Removing and re-inserting a container should crash</title> +<link rel="help" href="https://crbug.com/1342750"> +<style> + #container { container-type: inline-size } +</style> +<div id="outer"> + <div id="container"></div> +</div> +<script> + container.offsetTop; + let removed = container; + container.remove(); + outer.appendChild(removed); +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/crashtests/columns-in-table-001-crash.html b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/columns-in-table-001-crash.html new file mode 100644 index 0000000000..fe421500da --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/columns-in-table-001-crash.html @@ -0,0 +1,10 @@ +<!doctype html> +<title>CSS Container Queries Test: TR container with multicol TD crashes Chrome</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#size-container"> +<link rel="help" href="https://crbug.com/1291471"> +<p>Pass if test does not crash.</p> +<table> + <tr style="container-type:size;"> + <td style="columns:2"></td> + </tr> +</table> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/crashtests/columns-in-table-002-crash.html b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/columns-in-table-002-crash.html new file mode 100644 index 0000000000..24b9f1aab2 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/columns-in-table-002-crash.html @@ -0,0 +1,15 @@ +<!doctype html> +<title>CSS Container Queries Test: container with multicol table-header-group crashes Chrome</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#size-container"> +<link rel="help" href="https://crbug.com/1307656"> +<p>Pass if test does not crash.</p> +<div id="container" style="container-type:inline-size"> + <span style="display:table-header-group;columns:1"></span> + <span style="display:table-header-group;"></span> +</div> +<script> + // This originally caused a crash. + document.body.offsetTop; + // Additionally make sure we don't crash when the container is re-attached. + container.style.display = "inline-block"; +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/crashtests/container-in-canvas-crash.html b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/container-in-canvas-crash.html new file mode 100644 index 0000000000..215c6a04db --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/container-in-canvas-crash.html @@ -0,0 +1,11 @@ +<!DOCTYPE html> +<title>Don't crash with a container query container inside canvas</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3"> +<link rel="help" href="https://crbug.com/1321471"> +<canvas> + <div> + <div style="container-type: size"> + <div>Test</div> + </div> + </div> +</canvas> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/crashtests/container-type-change-chrome-legacy-crash.html b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/container-type-change-chrome-legacy-crash.html new file mode 100644 index 0000000000..609142a2c5 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/container-type-change-chrome-legacy-crash.html @@ -0,0 +1,16 @@ +<!doctype html> +<title>CSS Container Queries Test: Changing container-type in Chrome legacy layout</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#size-container"> +<link rel="help" href="https://crbug.com/1286773"> +<p>Pass if there is no crash.</p> +<span style="column-count: 1"><table></table></span> +<video id="video"></video> +<input id="input"></input> +<script> + document.body.offsetTop; + video.style.containerType = "inline-size"; + document.body.offsetLeft; + video.style.columnCount = "1"; + input.setAttribute("type", "button"); + document.body.offsetTop; +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/crashtests/dialog-backdrop-crash.html b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/dialog-backdrop-crash.html new file mode 100644 index 0000000000..3bbdf160cf --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/dialog-backdrop-crash.html @@ -0,0 +1,25 @@ +<!DOCTYPE html> +<style> + html { + overflow: hidden; + } + + dialog { + container-type: size; + width: 100px; + height: 100px; + } + + @container (width > 1px) { + dialog::backdrop { + margin: 10px; + background-color: green; + } + } +</style> +<dialog id=dialog> + Hello World +</dialog> +<script> + dialog.showModal(); +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/crashtests/dirty-rowgroup-crash.html b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/dirty-rowgroup-crash.html new file mode 100644 index 0000000000..2a66cd452a --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/dirty-rowgroup-crash.html @@ -0,0 +1,18 @@ +<!DOCTYPE html> +<div style='container-type: size;'></div> +<table> + <tbody id='id_0'></tbody> + <th id='id_1'> + <tr> + <th></th> + </tr> + </th> +</table> +<script> + const tbody = document.getElementById('id_0') + tbody.getBoundingClientRect(); + const theader = document.getElementById('id_1') + tbody.outerText = 'foo'; + theader.setAttribute('rowspan', 100) + tbody.getBoundingClientRect(); +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/crashtests/flex-in-columns-000-crash.html b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/flex-in-columns-000-crash.html new file mode 100644 index 0000000000..e7b789345c --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/flex-in-columns-000-crash.html @@ -0,0 +1,17 @@ +<!DOCTYPE html> +<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org"> +<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1276898"> +<style> + @container (max-width: 500px) { + #target { + display: flex; + } + } +</style> +<div id="container" style="columns:2; container-type:inline-size; width:600px;"> + <div id="target"></div> +</div> +<script> + document.body.offsetTop; + container.style.width = "400px"; +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/crashtests/flex-in-columns-001-crash.html b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/flex-in-columns-001-crash.html new file mode 100644 index 0000000000..0c0648c15b --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/flex-in-columns-001-crash.html @@ -0,0 +1,17 @@ +<!DOCTYPE html> +<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org"> +<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1276898"> +<style> + @container (max-width: 500px) { + #target { + display: flex; + } + } +</style> +<div id="container" style="columns:2; container-type:inline-size; width:400px;"> + <div id="target"></div> +</div> +<script> + document.body.offsetTop; + container.style.width = "600px"; +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/crashtests/flex-in-columns-002-crash.html b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/flex-in-columns-002-crash.html new file mode 100644 index 0000000000..ef3052d2c9 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/flex-in-columns-002-crash.html @@ -0,0 +1,19 @@ +<!DOCTYPE html> +<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org"> +<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1276898"> +<style> + @container (max-width: 250px) { + #target { + display: flex; + } + } +</style> +<div id="ancestor" style="columns:2; column-gap:0; width:600px;"> + <div style="container-type:inline-size;"> + <div id="target"></div> + </div> +</div> +<script> + document.body.offsetTop; + ancestor.style.width = "400px"; +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/crashtests/flex-in-columns-003-crash.html b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/flex-in-columns-003-crash.html new file mode 100644 index 0000000000..a86f25a773 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/flex-in-columns-003-crash.html @@ -0,0 +1,19 @@ +<!DOCTYPE html> +<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org"> +<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1276898"> +<style> + @container (max-width: 250px) { + #target { + display: flex; + } + } +</style> +<div id="ancestor" style="columns:2; column-gap:0; width:400px;"> + <div style="container-type:inline-size;"> + <div id="target"></div> + </div> +</div> +<script> + document.body.offsetTop; + ancestor.style.width = "600px"; +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/crashtests/focus-inside-content-visibility-crash.html b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/focus-inside-content-visibility-crash.html new file mode 100644 index 0000000000..1bf68d6686 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/focus-inside-content-visibility-crash.html @@ -0,0 +1,42 @@ +<!doctype html> +<title>Container Queries Test: size change detected while focusing inside content-visibility: auto container</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-queries"> +<link rel="help" href="https://drafts.csswg.org/css-contain-2/#using-cv-auto"> +<link rel="help" href="https://crbug.com/1270848"> +<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org"> + +<style> +.spacer { height: 3000px; } +.auto { content-visibility: auto; } +#container { + border: 1px solid black; + width: 100px; + height: 100px; + + container-type: size; +} +#input { + width: 100%; + visibility: hidden; +} +@container (min-width: 150px) { + #input { visibility: visible; } +} + +</style> + +<div class=spacer></div> +<div class=auto> + <div id=container> + <input id=input type=text></input> + </div> +</div> + +<script> +function focus() { + container.style.width = "200px"; + input.focus(); +} + +onload = () => requestAnimationFrame(() => requestAnimationFrame(focus)); +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/crashtests/force-sibling-style-crash.html b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/force-sibling-style-crash.html new file mode 100644 index 0000000000..093a01b809 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/force-sibling-style-crash.html @@ -0,0 +1,16 @@ +<!DOCTYPE html> +<title>getComputedStyle on sibling of style-dirty container</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#size-container"> +<link rel="help" href="https://crbug.com/1306385"> +<div id=ancestor style="--x:foo"> + <div id=container style="container-type:size;width:100px;"> + <span>Test</span> + </div> + <div id=target></div> +</div> +<script> + ancestor.offsetTop; + ancestor.style.setProperty('--x', 'bar'); + container.style.width = '200px'; + getComputedStyle(target).getPropertyValue('--x'); +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/crashtests/grid-in-columns-000-crash.html b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/grid-in-columns-000-crash.html new file mode 100644 index 0000000000..56cf6cfdbb --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/grid-in-columns-000-crash.html @@ -0,0 +1,17 @@ +<!DOCTYPE html> +<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org"> +<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1276898"> +<style> + @container (max-width: 500px) { + #target { + display: grid; + } + } +</style> +<div id="container" style="columns:2; container-type:inline-size; width:600px;"> + <div id="target"></div> +</div> +<script> + document.body.offsetTop; + container.style.width = "400px"; +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/crashtests/grid-in-columns-001-crash.html b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/grid-in-columns-001-crash.html new file mode 100644 index 0000000000..b9cf100533 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/grid-in-columns-001-crash.html @@ -0,0 +1,17 @@ +<!DOCTYPE html> +<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org"> +<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1276898"> +<style> + @container (max-width: 500px) { + #target { + display: grid; + } + } +</style> +<div id="container" style="columns:2; container-type:inline-size; width:400px;"> + <div id="target"></div> +</div> +<script> + document.body.offsetTop; + container.style.width = "600px"; +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/crashtests/grid-in-columns-002-crash.html b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/grid-in-columns-002-crash.html new file mode 100644 index 0000000000..762ad44f24 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/grid-in-columns-002-crash.html @@ -0,0 +1,19 @@ +<!DOCTYPE html> +<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org"> +<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1276898"> +<style> + @container (max-width: 250px) { + #target { + display: grid; + } + } +</style> +<div id="ancestor" style="columns:2; column-gap:0; width:600px;"> + <div style="container-type:inline-size;"> + <div id="target"></div> + </div> +</div> +<script> + document.body.offsetTop; + ancestor.style.width = "400px"; +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/crashtests/grid-in-columns-003-crash.html b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/grid-in-columns-003-crash.html new file mode 100644 index 0000000000..11089e6902 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/grid-in-columns-003-crash.html @@ -0,0 +1,19 @@ +<!DOCTYPE html> +<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org"> +<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1276898"> +<style> + @container (max-width: 250px) { + #target { + display: grid; + } + } +</style> +<div id="ancestor" style="columns:2; column-gap:0; width:400px;"> + <div style="container-type:inline-size;"> + <div id="target"></div> + </div> +</div> +<script> + document.body.offsetTop; + ancestor.style.width = "600px"; +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/crashtests/iframe-init-crash.html b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/iframe-init-crash.html new file mode 100644 index 0000000000..e915c2479f --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/iframe-init-crash.html @@ -0,0 +1,3 @@ +<!DOCTYPE html> +<audio controls style='container-type: size'></audio> +<iframe> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/crashtests/inline-multicol-inside-container-crash.html b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/inline-multicol-inside-container-crash.html new file mode 100644 index 0000000000..7e209f7ffd --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/inline-multicol-inside-container-crash.html @@ -0,0 +1,21 @@ +<!doctype html> +<title>CSS Container Queries Test: Inline multicol inside size container - crash</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#size-container"> +<link rel="help" href="https://crbug.com/829028"> +<style> + #container { + container-type: size; + width: 200px; + height: 100px; + } + @container (width <= 200px) { + #multicol { + column-count: 2; + column-gap: 0; + } + } +</style> +<p>Test passes if it doesn't crash.</p> +<div id="container"> + <span id="multicol"><div></div></span> +</div> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/crashtests/inline-with-columns-000-crash.html b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/inline-with-columns-000-crash.html new file mode 100644 index 0000000000..733b2c4ee9 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/inline-with-columns-000-crash.html @@ -0,0 +1,17 @@ +<!DOCTYPE html> +<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org"> +<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1276898"> +<style> + @container (max-width: 500px) { + #target { + columns: 2; + } + } +</style> +<div id="container" style="container-type:inline-size; width:600px;"> + <span id="target"></span> +</div> +<script> + document.body.offsetTop; + container.style.width = "400px"; +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/crashtests/inline-with-columns-001-crash.html b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/inline-with-columns-001-crash.html new file mode 100644 index 0000000000..3b9bdf32bd --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/inline-with-columns-001-crash.html @@ -0,0 +1,17 @@ +<!DOCTYPE html> +<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org"> +<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1276898"> +<style> + @container (max-width: 500px) { + #target { + columns: 2; + } + } +</style> +<div id="container" style="container-type:inline-size; width:400px;"> + <span id="target"></span> +</div> +<script> + document.body.offsetTop; + container.style.width = "600px"; +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/crashtests/input-column-group-container-crash.html b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/input-column-group-container-crash.html new file mode 100644 index 0000000000..5e520a45cf --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/input-column-group-container-crash.html @@ -0,0 +1,14 @@ +<!doctype html> +<title>CSS Container Queries Test: </title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-queries"> +<link rel="help" href="https://crbug.com/1282782"> +<p>Pass if this test does not crash</p> +<span style="column-count: 1"> + <span style="display:table-column-group"></span> + <input id="inp"> +</span> +<script> + document.body.offsetTop; + document.body.style.setProperty("container", "inline-size"); + inp.setAttribute("type", "image"); +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/crashtests/input-placeholder-inline-size-crash.html b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/input-placeholder-inline-size-crash.html new file mode 100644 index 0000000000..4b1284e5cb --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/input-placeholder-inline-size-crash.html @@ -0,0 +1,12 @@ +<!doctype html> +<title>CSS Container Queries Test: Crash: input inline-size container with placeholder</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#size-container"> +<link rel="help" href="https://crbug.com/1288692"> +<p>Pass if this test does not crash</p> +<input id="input" style="container-type:size"> +<script> + document.body.offsetTop; + input.style.position = "absolute"; + input.setAttribute("placeholder", "placeholder"); + document.body.offsetTop; +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/crashtests/marker-gcs-after-disconnect-crash.html b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/marker-gcs-after-disconnect-crash.html new file mode 100644 index 0000000000..3680c79512 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/marker-gcs-after-disconnect-crash.html @@ -0,0 +1,26 @@ +<!DOCTYPE html> +<title>Don't crash during getComputedStyle which removes ::marker</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3"> +<link rel="help" href="https://crbug.com/1349732"> +<style> +#container { + width: 100px; + height: 100px; + container-type: size; +} +@container (width) { + span { color: green; } +} +</style> +<ul> + <li id="target"></li> +</ul> +<div id=container> + <span>PASS if no crash</span> +</div> +<script> +let li = document.querySelector('li'); +getComputedStyle(target, '::marker').width; +li.style.listStyleType = 'none'; +getComputedStyle(target, '::marker').width; +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/crashtests/math-block-container-child-crash.html b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/math-block-container-child-crash.html new file mode 100644 index 0000000000..00b6836655 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/math-block-container-child-crash.html @@ -0,0 +1,14 @@ +<!doctype html> +<title>CSS Container Queries Test: Math block container child crash</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#size-container"> +<link rel="help" href="https://crbug.com/1294268"> +<p>Pass if there is no crash.</p> +<math id="m" style="display:block math"></math> +<script> + let div = document.createElement("div"); + div.style.containerType = "size"; + m.appendChild(div); + div.appendChild(document.createElement("span")); + document.body.offsetTop; + div.style.color = "green"; +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/crashtests/orthogonal-replaced-crash.html b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/orthogonal-replaced-crash.html new file mode 100644 index 0000000000..10474fd984 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/orthogonal-replaced-crash.html @@ -0,0 +1,11 @@ +<!doctype html> +<title>Chrome crash for replaced in orthogonal flow query container</title> +<link rel="help" href="https://crbug.com/1325673"> +<p>Pass if no crash.</p> +<iframe></iframe> +<style> + body { + container-type: size; + writing-mode: vertical-rl; + } +</style> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/crashtests/pseudo-container-crash.html b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/pseudo-container-crash.html new file mode 100644 index 0000000000..f998c3a446 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/pseudo-container-crash.html @@ -0,0 +1,14 @@ +<!doctype html> +<title>CSS Container Queries Test: No crash when ::after is a container</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#query-container"> +<link rel="help" href="https://crbug.com/1225381"> +<style> + div::after { + container-type: size; + content: ''; + display: block; + } +</style> +<div> + PASS if no crash +</div> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/crashtests/reversed-ol-crash.html b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/reversed-ol-crash.html new file mode 100644 index 0000000000..fa4d35380c --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/reversed-ol-crash.html @@ -0,0 +1,29 @@ +<!DOCTYPE html> +<title>Don't crash with intermediate container in reversed list</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-2/#containment-style"> +<link rel="help" href="https://drafts.csswg.org/css-contain-2/#containment-style"> +<link rel="help" href="https://crbug.com/1377644"> +<style> +.container { + container-type: size; +} + +/* Prevent double layout due to scrollbar speculation */ +html { + overflow: hidden; +} + +@container (width > 1px) { + .item { + display: list-item; + } +} +</style> +<ol reversed> + <li>A</li> + <div class=container> + <div class=item> + B + </div> + </div> +</ol> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/crashtests/svg-layout-root-crash.html b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/svg-layout-root-crash.html new file mode 100644 index 0000000000..75a3839add --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/svg-layout-root-crash.html @@ -0,0 +1,22 @@ +<!doctype html> +<title>@container changing display of SVG element should not crash</title> +<link rel="help" href="https://crbug.com/1245689"> +<iframe id="frame" style="width: 200px"></iframe> +<script> + frame.srcdoc = ` + <style> + #container { + container-type: inline-size; + } + @container (min-width: 300px) { + .hide { display: none; } + } + </style> + <div id="container"> + <div class="hide"><svg></svg></div> + </div>`; + + requestAnimationFrame(() => + requestAnimationFrame(() => + requestAnimationFrame(() => frame.style.width = "400px"))); +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/crashtests/svg-text-crash.html b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/svg-text-crash.html new file mode 100644 index 0000000000..aadba08679 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/svg-text-crash.html @@ -0,0 +1,8 @@ +<!doctype html> +<title>SVG text element with size container-type should not crash</title> +<link rel="help" href="https://crbug.com/1298319"> +<style> + text { container-type: inline-size; } +</style> +<p>Pass if no crash.</p> +<svg><text></text></svg> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/crashtests/table-in-columns-000-crash.html b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/table-in-columns-000-crash.html new file mode 100644 index 0000000000..566a4eb1eb --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/table-in-columns-000-crash.html @@ -0,0 +1,17 @@ +<!DOCTYPE html> +<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org"> +<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1276898"> +<style> + @container (max-width: 500px) { + #target { + display: table; + } + } +</style> +<div id="container" style="columns:2; container-type:inline-size; width:600px;"> + <div id="target"></div> +</div> +<script> + document.body.offsetTop; + container.style.width = "400px"; +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/crashtests/table-in-columns-001-crash.html b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/table-in-columns-001-crash.html new file mode 100644 index 0000000000..4fab9de88f --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/table-in-columns-001-crash.html @@ -0,0 +1,17 @@ +<!DOCTYPE html> +<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org"> +<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1276898"> +<style> + @container (max-width: 500px) { + #target { + display: table; + } + } +</style> +<div id="container" style="columns:2; container-type:inline-size; width:400px;"> + <div id="target"></div> +</div> +<script> + document.body.offsetTop; + container.style.width = "600px"; +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/crashtests/table-in-columns-002-crash.html b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/table-in-columns-002-crash.html new file mode 100644 index 0000000000..4f0cdc0740 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/table-in-columns-002-crash.html @@ -0,0 +1,19 @@ +<!DOCTYPE html> +<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org"> +<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1276898"> +<style> + @container (max-width: 250px) { + #target { + display: table; + } + } +</style> +<div id="ancestor" style="columns:2; column-gap:0; width:600px;"> + <div style="container-type:inline-size;"> + <div id="target"></div> + </div> +</div> +<script> + document.body.offsetTop; + ancestor.style.width = "400px"; +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/crashtests/table-in-columns-003-crash.html b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/table-in-columns-003-crash.html new file mode 100644 index 0000000000..436da592d9 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/table-in-columns-003-crash.html @@ -0,0 +1,19 @@ +<!DOCTYPE html> +<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org"> +<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1276898"> +<style> + @container (max-width: 250px) { + #target { + display: table; + } + } +</style> +<div id="ancestor" style="columns:2; column-gap:0; width:400px;"> + <div style="container-type:inline-size;"> + <div id="target"></div> + </div> +</div> +<script> + document.body.offsetTop; + ancestor.style.width = "600px"; +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/crashtests/table-in-columns-004-crash.html b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/table-in-columns-004-crash.html new file mode 100644 index 0000000000..daed42f009 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/table-in-columns-004-crash.html @@ -0,0 +1,16 @@ +<!doctype html> +<title>CSS Container Queries Crash Test</title> +<link rel="help" href="https://crbug.com/1338055"> +<p>Pass if no crash</p> +<div style="container-type:inline-size"> + <span style="columns: 1"> + <canvas> + <script> + document.body.offsetTop; + </script> + <div style="container-type:inline-size"> + <span style="display:table-column-group"></span> + </div> + </canvas> + </span> +</div> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/crashtests/table-in-columns-005-crash.html b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/table-in-columns-005-crash.html new file mode 100644 index 0000000000..60d6f9d3a1 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/table-in-columns-005-crash.html @@ -0,0 +1,8 @@ +<!doctype html> +<title>CSS Container Queries Crash Test</title> +<link rel="help" href="https://crbug.com/1336334"> +<li style="container-type:inline-size"> + <span style="columns:2"> + <table></table> + </span> +</li> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/custom-layout-container-001.https.html b/testing/web-platform/tests/css/css-contain/container-queries/custom-layout-container-001.https.html new file mode 100644 index 0000000000..8f301e8ebf --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/custom-layout-container-001.https.html @@ -0,0 +1,66 @@ +<!doctype html> +<html class=reftest-wait> +<title>CSS Container Queries Test: Size queries on CSS Layout API containers</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#size-container"> +<link rel="help" href="https://drafts.css-houdini.org/css-layout-api/"> +<link rel="match" href="/css/reference/ref-filled-green-100px-square-only.html"> +<script src="/common/reftest-wait.js"></script> +<script src="/common/worklet-reftest.js"></script> +<style> + #test1 { + width: 400px; + height: 100px; + } + #outer { + display: inline; /* Shouldn't pass without layout api support */ + display: layout(half); + height: 100px; + container-type: inline-size; + } + @container (width = 400px) { + #inner { + display: inline; /* Shouldn't pass without layout api support */ + display: layout(half); + height: 100px; + container-type: inline-size; + } + } + @container (width = 200px) { + #green { + background-color: green; + height: 100px; + } + } +</style> +<p>Test passes if there is a filled green square.</p> +<div id="test1"> + <div id="outer"> + <div id="inner"> + <div id="green"></div> + </div> + </div> +</div> + +<script id="code" type="text/worklet"> + registerLayout("half", class { + async intrinsicSizes() {} + async layout(children, edges, constraints, styleMap) { + const childInlineSize = constraints.fixedInlineSize / 2; + const childFragments = await Promise.all(children.map((child) => { + return child.layoutNextFragment({fixedInlineSize: childInlineSize}); + })); + + for (let childFragment of childFragments) { + childFragment.inlineOffset = 0; + childFragment.blockOffset = 0; + } + const autoBlockSize = 100; + return {autoBlockSize, childFragments}; + } + }); +</script> + +<script> + importWorkletAndTerminateTestAfterAsyncPaint(CSS.layoutWorklet, document.getElementById("code").textContent); +</script> +</html> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/custom-property-style-queries.html b/testing/web-platform/tests/css/css-contain/container-queries/custom-property-style-queries.html new file mode 100644 index 0000000000..29b5004af0 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/custom-property-style-queries.html @@ -0,0 +1,436 @@ +<!doctype html> +<title>CSS Container Queries Test: custom property style queries</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#style-container"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/cq-testcommon.js"></script> +<style> + #outer { + container-name: outer; + --inner: false; + --outer: true; + --inner-no-space:false; + --outer-no-space:true; + --inner-space-after:false ; + --outer-space-after:true ; + } + #inner { + --inner: true; + --outer: false; + --inner-no-space:true; + --outer-no-space:false; + --inner-space-after:true ; + --outer-space-after:false ; + } +</style> +<div id="outer"> + <div id="inner"> + <div id="target"></div> + </div> +</div> +<script> + const green = "rgb(0, 128, 0)"; + + function test_evaluation(query, expected) { + test((t) => { + let style_node = document.createElement('style'); + t.add_cleanup(() => { + style_node.remove(); + }); + style_node.innerText = `@container ${query} { #target { --applied:true; } }`; + + assert_equals(getComputedStyle(target).getPropertyValue('--applied'), ''); + document.head.append(style_node); + assert_equals(getComputedStyle(target).getPropertyValue('--applied'), expected ? 'true' : ''); + }, `${query}`); + } + + setup(() => assert_implements_container_queries()); + + test_evaluation('style(--inner: true)', true); + test_evaluation('style(--inner:true)', true); + test_evaluation('style(--inner:true )', true); + test_evaluation('style(--inner: true )', true); + test_evaluation('style(--inner-no-space: true)', true); + test_evaluation('style(--inner-no-space:true)', true); + test_evaluation('style(--inner-no-space:true )', true); + test_evaluation('style(--inner-no-space: true )', true); + test_evaluation('style(--inner-space-after: true)', true); + test_evaluation('style(--inner-space-after:true)', true); + test_evaluation('style(--inner-space-after:true )', true); + test_evaluation('style(--inner-space-after: true )', true); + test_evaluation('style(--outer: true)', false); + test_evaluation('style(--outer:true)', false); + test_evaluation('style(--outer:true )', false); + test_evaluation('style(--outer: true )', false); + test_evaluation('style(--outer-no-space: true)', false); + test_evaluation('style(--outer-no-space:true)', false); + test_evaluation('style(--outer-no-space:true )', false); + test_evaluation('style(--outer-no-space: true )', false); + test_evaluation('style(--outer-space-after: true)', false); + test_evaluation('style(--outer-space-after:true)', false); + test_evaluation('style(--outer-space-after:true )', false); + test_evaluation('style(--outer-space-after: true )', false); + test_evaluation('outer style(--inner: true)', false); + test_evaluation('outer style(--inner:true)', false); + test_evaluation('outer style(--inner:true )', false); + test_evaluation('outer style(--inner: true )', false); + test_evaluation('outer style(--inner-no-space: true)', false); + test_evaluation('outer style(--inner-no-space:true)', false); + test_evaluation('outer style(--inner-no-space:true )', false); + test_evaluation('outer style(--inner-no-space: true )', false); + test_evaluation('outer style(--inner-space-after: true)', false); + test_evaluation('outer style(--inner-space-after:true)', false); + test_evaluation('outer style(--inner-space-after:true )', false); + test_evaluation('outer style(--inner-space-after: true )', false); + test_evaluation('outer style(--outer: true)', true); + test_evaluation('outer style(--outer:true)', true); + test_evaluation('outer style(--outer:true )', true); + test_evaluation('outer style(--outer: true )', true); + test_evaluation('outer style(--outer-no-space: true)', true); + test_evaluation('outer style(--outer-no-space:true)', true); + test_evaluation('outer style(--outer-no-space:true )', true); + test_evaluation('outer style(--outer-no-space: true )', true); + test_evaluation('outer style(--outer-space-after: true)', true); + test_evaluation('outer style(--outer-space-after:true)', true); + test_evaluation('outer style(--outer-space-after:true )', true); + test_evaluation('outer style(--outer-space-after: true )', true); +</script> + +<style> + #important { + --foo: bar; + } + @container style(--foo: bar !important) { + #important-child { color: green; } + } +</style> +<div id="important"> + <div id="important-child"></div> +</div> +<script> + test(() => { + assert_equals(getComputedStyle(document.querySelector("#important-child")).color, green); + }, "Query custom property with !important declaration"); +</script> + +<style> + #var-query { + --foo: baz; + --bar: baz; + } + @container style(--foo: var(--bar)) { + #var-subst { color: green; } + } + @container not style(--foo: var(--unknown)) { + #var-subst-unknown { color: green; } + } + @container not style(--foo: var(--unknown, nomatch)) { + #var-subst-unknown-fallback { color: green; } + } + @container style(--foo: var(--unknown, baz)) { + #var-subst-matching-fallback { color: green; } + } + @container style(--baz: var(--unknown)) { + #var-subst-unknown-matching { color: green; } + } +</style> +<div id="var-query"> + <div id="var-subst"></div> + <div id="var-subst-unknown"></div> + <div id="var-subst-unknown-fallback"></div> + <div id="var-subst-matching-fallback"></div> + <div id="var-subst-unknown-matching"></div> +</div> +<script> + test(() => { + assert_equals(getComputedStyle(document.querySelector("#var-subst")).color, green); + }, "Query custom property using var()"); + + test(() => { + assert_equals(getComputedStyle(document.querySelector("#var-subst-unknown")).color, green); + }, "Query custom property including unknown var() reference"); + + test(() => { + assert_equals(getComputedStyle(document.querySelector("#var-subst-unknown-fallback")).color, green); + }, "Query custom property including unknown var() reference with non-matching fallback"); + + test(() => { + assert_equals(getComputedStyle(document.querySelector("#var-subst-matching-fallback")).color, green); + }, "Query custom property including unknown var() reference with matching fallback"); + + test(() => { + assert_equals(getComputedStyle(document.querySelector("#var-subst-unknown-matching")).color, green); + }, "Query custom property matching guaranteed-invalid values"); +</script> + +<style> + #revert { + --foo: revert; + } + #revert-layer { + --foo: revert-layer; + } + #revert-child, #revert-layer-child { + color: green; + } + @container style(--foo: revert) { + #revert-child { color: red; } + } + @container style(--foo: revert-layer) { + #revert-layer-child { color: red; } + } +</style> +<div id="revert"> + <div id="revert-child"></div> +</div> +<div id="revert-layer"> + <div id="revert-layer-child"></div> +</div> +<script> + test(() => { + assert_equals(getComputedStyle(document.querySelector("#revert-child")).color, green); + }, "Style query with revert keyword is false"); + + test(() => { + assert_equals(getComputedStyle(document.querySelector("#revert-layer-child")).color, green); + }, "Style query with revert-layer keyword is false"); +</script> + +<style> + #defaulting { + --inherit: baz; + --inherit-no: baz; + } + #defaulting-container { + --inherit-no: bar; + --unset-no: baz; + --initial-no: baz; + } + @container style(--initial: initial) { + #initial { color: green; } + } + @container not style(--initial) { + #initial-implicit { color: green; } + } + @container not style(--initial-no: initial) { + #initial-no { color: green; } + } + @container style(--initial-no) { + #initial-no-implicit { color: green; } + } + @container style(--inherit: inherit) { + #inherit { color: green; } + } + @container not style(--inherit-no: inherit) { + #inherit-no { color: green; } + } + @container style(--unset: unset) { + #unset { color: green; } + } + @container not style(--unset-no: unset) { + #unset-no { color: green; } + } +</style> +<div id="defaulting"> + <div id="defaulting-container"> + <div id="initial"></div> + <div id="initial-implicit"></div> + <div id="initial-no"></div> + <div id="initial-no-implicit"></div> + <div id="inherit"></div> + <div id="inherit-no"></div> + <div id="unset"></div> + <div id="unset-no"></div> + </div> +</div> +<script> + test(() => { + assert_equals(getComputedStyle(document.querySelector("#initial")).color, green); + }, "Style query 'initial' matching"); + + test(() => { + assert_equals(getComputedStyle(document.querySelector("#initial-implicit")).color, green); + }, "Style query matching negated value-less query against initial value"); + + test(() => { + assert_equals(getComputedStyle(document.querySelector("#initial-no")).color, green); + }, "Style query 'initial' not matching"); + + test(() => { + assert_equals(getComputedStyle(document.querySelector("#initial-no-implicit")).color, green); + }, "Style query matching value-less query against non-initial value"); + + test(() => { + assert_equals(getComputedStyle(document.querySelector("#inherit")).color, green); + }, "Style query 'inherit' matching"); + + test(() => { + assert_equals(getComputedStyle(document.querySelector("#inherit-no")).color, green); + }, "Style query 'inherit' not matching"); + + test(() => { + assert_equals(getComputedStyle(document.querySelector("#unset")).color, green); + }, "Style query 'unset' matching"); + + test(() => { + assert_equals(getComputedStyle(document.querySelector("#unset-no")).color, green); + }, "Style query 'unset' not matching"); +</script> + +<style> + @property --reg-length { + syntax: "<length>"; + inherits: false; + initial-value: 10px; + } + + #registered { + container-type: inline-size; + width: 200px; + font-size: 20px; + } + + #reg-container-px { + --reg-length: 10px; + } + @container style(--reg-length: 10px) { + #reg-px { color: green; } + } + @container style(--reg-length: initial) { + #reg-px-initial { color: green; } + } + @container not style(--reg-length) { + #reg-px-initial-implicit { color: green; } + } + + #reg-container-font-relative { + --reg-length: 10px; + } + @container style(--reg-length: 0.5em) { + #reg-font-relative { color: green; } + } + + #reg-container-font-relative-2 { + --reg-length: 0.5em; + } + @container style(--reg-length: 10px) { + #reg-font-relative-2 { color: green; } + } + + #reg-container-container-relative { + width: 100px; + --reg-length: 100px; + } + @container style(--reg-length: 50cqi) { + #reg-container-relative { color: green; } + } + + #reg-container-initial { + --reg-length: 10px; + } + @container style(--reg-length: 10px) { + #reg-initial-value { color: green; } + } + @container style(--reg-length: initial) { + #reg-initial-keyword { color: green; } + } + @container not style(--reg-length) { + #reg-initial-implicit { color: green; } + } +</style> +<div id="registered"> + <div id="reg-container-px"> + <div id="reg-px"></div> + <div id="reg-px-initial"></div> + <div id="reg-px-initial-implicit"></div> + </div> + <div id="reg-container-font-relative"> + <div id="reg-font-relative"></div> + </div> + <div id="reg-container-font-relative-2"> + <div id="reg-font-relative-2"></div> + </div> + <div id="reg-container-container-relative"> + <div id="reg-container-relative"></div> + </div> + <div id="reg-container-initial"> + <div id="reg-initial-value"></div> + <div id="reg-initial-keyword"></div> + <div id="reg-initial-implicit"></div> + </div> +</div> +<script> + test(() => { + assert_equals(getComputedStyle(document.querySelector("#reg-px")).color, green); + }, "Match registered <length> custom property with px."); + + test(() => { + assert_equals(getComputedStyle(document.querySelector("#reg-px-initial")).color, green); + }, "Match registered <length> custom property with px via initial keyword."); + + test(() => { + assert_equals(getComputedStyle(document.querySelector("#reg-font-relative")).color, green); + }, "Match registered <length> custom property with em in query."); + + test(() => { + assert_equals(getComputedStyle(document.querySelector("#reg-font-relative-2")).color, green); + }, "Match registered <length> custom property with em in computed value."); + + test(() => { + assert_equals(getComputedStyle(document.querySelector("#reg-container-relative")).color, green); + }, "Match registered <length> custom property with cqi unit."); + + test(() => { + assert_equals(getComputedStyle(document.querySelector("#reg-initial-value")).color, green); + }, "Match registered <length> custom property with initial value."); + + test(() => { + assert_equals(getComputedStyle(document.querySelector("#reg-initial-keyword")).color, green); + }, "Match registered <length> custom property with initial value via initial keyword."); +</script> + +<style> + #original-text { + --number: 100.00; + --spaces: a b; + } + @container style(--number: 100.00) { + #original-text-number { + color: green; + } + } + @container style(--number: 100.0) { + #original-text-number { + color: red; + } + } + @container style(--number: 100) { + #original-text-number { + color: red; + } + } + @container style(--spaces: a b) { + #original-text-spaces { + color: green; + } + } + @container style(--number: a b) { + #original-text-spaces { + color: red; + } + } +</style> +<div id="original-text"> + <div id="original-text-number"></div> + <div id="original-text-spaces"></div> +</div> +<script> + test(() => { + assert_equals(getComputedStyle(document.querySelector("#original-text-number")).color, green); + }, "Should only match exact string for numbers in non-registered custom properties"); + + test(() => { + assert_equals(getComputedStyle(document.querySelector("#original-text-spaces")).color, green); + }, "Spaces should not collapse in non-registered custom properties"); +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/custom-property-style-query-change.html b/testing/web-platform/tests/css/css-contain/container-queries/custom-property-style-query-change.html new file mode 100644 index 0000000000..6669ede31d --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/custom-property-style-query-change.html @@ -0,0 +1,89 @@ +<!doctype html> +<title>CSS Container Queries Test: custom property style query changes</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#style-container"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/cq-testcommon.js"></script> +<style> + #container { container-name: my-container; } + #child, #grandchild { color: red; } + @container style(--target: child) { + #child { color: green; } + } + @container my-container style(--target: grandchild) { + #grandchild { color: green; } + } +</style> +<div id="container"> + <div id="child"></div> + <div> + <div id="grandchild"></div> + </div> +</div> +<script> + setup(() => assert_implements_container_queries()); + + const green = "rgb(0, 128, 0)"; + const red = "rgb(255, 0, 0)"; + + test(() => { + assert_equals(getComputedStyle(child).color, red); + assert_equals(getComputedStyle(grandchild).color, red); + }, "Initially no queries match."); + + test(() => { + container.style.setProperty("--target", "child"); + assert_equals(getComputedStyle(child).color, green); + assert_equals(getComputedStyle(grandchild).color, red); + }, "Target child"); + + test(() => { + container.style.setProperty("--target", "grandchild"); + assert_equals(getComputedStyle(child).color, red); + assert_equals(getComputedStyle(grandchild).color, green); + }, "Target grandchild"); +</script> + +<style> + @property --length { + syntax: "<length>"; + inherits: false; + initial-value: 0px; + } + + #reg_container { + container-name: my-reg-container; + font-size: 50px; + } + #reg_child, #reg_grandchild { color: red; } + @container style(--length: 100px) { + #reg_child { color: green; } + } + @container my-reg-container style(--length: 200px) { + #reg_grandchild { color: green; } + } +</style> +<div id="reg_container"> + <div id="reg_child"></div> + <div> + <div id="reg_grandchild"></div> + </div> +</div> +<script> + test(() => { + assert_equals(getComputedStyle(reg_child).color, red); + assert_equals(getComputedStyle(reg_grandchild).color, red); + }, "Initially no queries for registered property match."); + + test(() => { + reg_container.style.setProperty("--length", "2em"); + assert_equals(getComputedStyle(reg_child).color, green); + assert_equals(getComputedStyle(reg_grandchild).color, red); + }, "Registered property query child"); + + test(() => { + reg_container.style.setProperty("--length", "200px"); + assert_equals(getComputedStyle(reg_child).color, red); + assert_equals(getComputedStyle(reg_grandchild).color, green); + }, "Registered property query grandchild"); +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/deep-nested-inline-size-containers.html b/testing/web-platform/tests/css/css-contain/container-queries/deep-nested-inline-size-containers.html new file mode 100644 index 0000000000..00bc8b0a6b --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/deep-nested-inline-size-containers.html @@ -0,0 +1,38 @@ +<!doctype html> +<title>CSS Container Queries Test: Deeply nested inline-size container queries</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#size-container"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/cq-testcommon.js"></script> +<style id="test_style"> + .container { container-type: inline-size; } + #outer { width: 200px; } +</style> +<div id="outer" class="container"></div> +<script> + setup(() => { + assert_implements_container_queries(); + + // Create 50 nested inline-size containers where a child container is 1px + // narrower than its parent + let sheet = test_style.sheet; + let container = outer; + for (let width = 200; width > 150; --width) { + sheet.insertRule(` + @container (width = ${width}px) { + .container { max-width: ${width-1}px; } + } + `); + let child = document.createElement("div"); + child.className = "container"; + container.appendChild(child); + container = child; + } + }); + + test(() => { + let expected_width = 200; + for (let container of document.querySelectorAll(".container")) + assert_equals(container.offsetWidth, expected_width--); + }, "Test that all container widths match"); +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/dialog-backdrop-create.html b/testing/web-platform/tests/css/css-contain/container-queries/dialog-backdrop-create.html new file mode 100644 index 0000000000..f72bb69f68 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/dialog-backdrop-create.html @@ -0,0 +1,30 @@ +<!doctype html> +<title>CSS Container Queries Test: ::backdrop appearing conditionally on dialog container</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-queries"> +<link rel="match" href="top-layer-dialog-backdrop-ref.html"> +<style> + html { + /* Prevent multiple layout passes due to scrollbars */ + overflow: hidden; + background: red; + } + dialog { + container-type: size; + width: 100px; + height: 100px; + visibility: hidden; + } + dialog::backdrop { + display: none; + background-color: green; + } + @container (width > 1px) { + dialog::backdrop { + display: block; + } + } +</style> +<dialog id="dialog"></dialog> +<script> + dialog.showModal(); +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/dialog-backdrop-remove.html b/testing/web-platform/tests/css/css-contain/container-queries/dialog-backdrop-remove.html new file mode 100644 index 0000000000..47b4030492 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/dialog-backdrop-remove.html @@ -0,0 +1,30 @@ +<!doctype html> +<title>CSS Container Queries Test: ::backdrop disappearing conditionally on dialog container</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-queries"> +<link rel="match" href="top-layer-dialog-backdrop-ref.html"> +<style> + html { + /* Prevent multiple layout passes due to scrollbars */ + overflow: hidden; + background: green; + } + dialog { + container-type: size; + width: 100px; + height: 100px; + visibility: hidden; + } + dialog::backdrop { + display: block; + background-color: red; + } + @container (width > 1px) { + dialog::backdrop { + display: none; + } + } +</style> +<dialog id="dialog"></dialog> +<script> + dialog.showModal(); +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/display-contents-dynamic-style-queries.html b/testing/web-platform/tests/css/css-contain/container-queries/display-contents-dynamic-style-queries.html new file mode 100644 index 0000000000..782cf56655 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/display-contents-dynamic-style-queries.html @@ -0,0 +1,35 @@ +<!doctype html> +<title>CSS Container Queries Test: Invalidate style queries and display:contents</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#style-container"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/cq-testcommon.js"></script> +<style> + #container.contents { + --foo: bar; + display: contents; + } + #target { + color: red; + } + @container style(--foo: bar) { + #target { + color: green; + } + } +</style> +<div id="container"> + <div id="target">This should be green</div> +</div> +<script> + setup(() => assert_implements_container_queries()); + + test(() => { + assert_equals(getComputedStyle(target).color, "rgb(255, 0, 0)"); + }, "Initially the color is red"); + + test(() => { + container.className = "contents"; + assert_equals(getComputedStyle(target).color, "rgb(0, 128, 0)"); + }, "After display and --foo changes, style() query causes the color to be green"); +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/display-contents.html b/testing/web-platform/tests/css/css-contain/container-queries/display-contents.html new file mode 100644 index 0000000000..d96a46d06a --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/display-contents.html @@ -0,0 +1,93 @@ +<!doctype html> +<title>@container and display:contents</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#size-container"> +<link rel="help" href="https://drafts.csswg.org/css-contain-2/#containment-size"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/cq-testcommon.js"></script> +<script> + setup(() => assert_implements_container_queries()); +</script> +<style> + .container { + container-type: inline-size; + width: 30px; + height: 30px; + background: tomato; + } + .big { + width: 50px; + height: 50px; + background: skyblue; + } + .contents { + display: contents; + } + + @container (width: 30px) { + .target { --x:30; } + } + + @container (width: 50px) { + .target { --x:50; } + } + + main { + display: flex; + flex-wrap: wrap; + } + +</style> + +<main> + <!-- Container is display:contents --> + <div class="container contents"> + <div> + <div class="target" id=target1></div> + </div> + </div> + <script> + test(function() { + let s = getComputedStyle(target1); + assert_equals(s.getPropertyValue('--x'), ''); + }, 'getComputedStyle when container is display:contents'); + </script> + + <!-- Container becomes display:contents --> + <div id=container2 class="container"> + <div> + <div class="target" id=target2></div> + </div> + </div> + <script> + test(function() { + let s = getComputedStyle(target2); + assert_equals(s.getPropertyValue('--x'), '30'); + container2.classList.add('contents'); + assert_equals(s.getPropertyValue('--x'), ''); + container2.classList.remove('contents'); + assert_equals(s.getPropertyValue('--x'), '30'); + }, 'getComputedStyle when container becomes display:contents'); + </script> + + <!-- Intermediate container becomes display:contents --> + <div class="container"> + <div> + <div id=container3 class="container"> + <div> + <div class="target" id=target3></div> + </div> + </div> + </div> + </div> + <script> + test(function() { + let s = getComputedStyle(target3); + assert_equals(s.getPropertyValue('--x'), '30'); + container3.classList.add('contents'); + assert_equals(s.getPropertyValue('--x'), ''); + container3.classList.remove('contents'); + assert_equals(s.getPropertyValue('--x'), '30'); + }, 'getComputedStyle when intermediate container becomes display:contents'); + </script> +</main> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/display-in-container-ref.html b/testing/web-platform/tests/css/css-contain/container-queries/display-in-container-ref.html new file mode 100644 index 0000000000..fd8e9ef0c1 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/display-in-container-ref.html @@ -0,0 +1,47 @@ +<!doctype html> +<title>CSS Test Reference</title> +<style> + .container, .not_a_container { + width: auto; + height: 100px; + border: 1px solid black; + margin-bottom: 10px; + } + span { + border: 1px solid green; + margin: 2px; + } +</style> +<div style="width:150px"> + <div class=container> + <main> + <div style="display:flex"> + <span style="flex:1">Test1</span> + <span style="flex:1">Test2</span> + <span style="flex:1">Test3</span> + </div> + </main> + </div> +</div> +<div style="width:200px"> + <div class=container> + <main> + <div> + <span style="display:block">Test1</span> + <span style="display:block">Test2</span> + <span style="display:block">Test3</span> + </div> + </main> + </div> +</div> +<div style="width:150px"> + <div class=not_a_container> + <main> + <div> + <span>Test1</span> + <span>Test2</span> + <span>Test3</span> + </div> + </main> + </div> +</div> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/display-in-container.html b/testing/web-platform/tests/css/css-contain/container-queries/display-in-container.html new file mode 100644 index 0000000000..a2a4cd731c --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/display-in-container.html @@ -0,0 +1,69 @@ +<!doctype html> +<title>CSS Container Queries Test: @container queries affecting display type</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-queries"> +<link rel="match" href="display-in-container-ref.html"> +<style> + .container, .not_a_container { + width: auto; + height: 100px; + border: 1px solid black; + margin-bottom: 10px; + } + .container { + container-type: size; + } + span { + border: 1px solid green; + margin: 2px; + } + + /* Note: 150px - 2px, since .container has a 1px border */ + @container (min-width: 148px) { + div { display: flex; } + span { flex: 1; } + } + + /* Note: 200px - 2px, since .container has a 1px border */ + @container (min-width: 198px) { + div { display: revert; } + span { display: block; } + } + + /* Should not apply: */ + @container (min-width: 199px) { + * { color: red; background-color: red; } + } +</style> +<div style="width:150px"> + <div class=container> + <main> + <div> + <span>Test1</span> + <span>Test2</span> + <span>Test3</span> + </div> + </main> + </div> +</div> +<div style="width:200px"> + <div class=container> + <main> + <div> + <span>Test1</span> + <span>Test2</span> + <span>Test3</span> + </div> + </main> + </div> +</div> +<div style="width:150px"> + <div class=not_a_container> + <main> + <div> + <span>Test1</span> + <span>Test2</span> + <span>Test3</span> + </div> + </main> + </div> +</div> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/display-none.html b/testing/web-platform/tests/css/css-contain/container-queries/display-none.html new file mode 100644 index 0000000000..8d07ec09dd --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/display-none.html @@ -0,0 +1,393 @@ +<!doctype html> +<title>@container in display:none</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#size-container"> +<link rel="help" href="https://drafts.csswg.org/css-contain-2/#containment-size"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/cq-testcommon.js"></script> +<script> + setup(() => assert_implements_container_queries()); +</script> +<style> + .container { + container-type: size; + width: 30px; + height: 30px; + background: tomato; + } + .small { + width: 10px; + height: 10px; + } + .big { + width: 50px; + height: 50px; + background: skyblue; + } + .auto { + width: auto; + } + .none { + display: none; + } + .pseudo::before { + content: "foo"; + } + .pseudo_none::before { + content: "foo"; + display: none; + } + + @container (width: 30px) { + .target { --x:30; } + } + + @container (width: 50px) { + .target { --x:50; } + } + + main { + display: flex; + flex-wrap: wrap; + } + +</style> + +<main> + <!-- Target element is display:none --> + <div class="container"> + <div> + <div> + <div class="target none" id=target1></div> + </div> + </div> + </div> + <script> + test(function() { + let s = getComputedStyle(target1); + assert_equals(s.getPropertyValue('--x'), '30'); + }, 'getComputedStyle when element is display:none'); + </script> + + <!-- Parent is display:none --> + <div class="container"> + <div> + <div class="none"> + <div class="target" id=target2></div> + </div> + </div> + </div> + <script> + test(function() { + let s = getComputedStyle(target2); + assert_equals(s.getPropertyValue('--x'), '30'); + }, 'getComputedStyle when parent is display:none'); + </script> + + <!-- Ancestor is display:none --> + <div class="container"> + <div class="none"> + <div> + <div class="target" id=target3></div> + </div> + </div> + </div> + <script> + test(function() { + let s = getComputedStyle(target3); + assert_equals(s.getPropertyValue('--x'), '30'); + }, 'getComputedStyle when ancestor is display:none'); + </script> + + <!-- Container is display:none --> + <div class="container none"> + <div> + <div> + <div class="target" id=target4></div> + </div> + </div> + </div> + <script> + test(function() { + let s = getComputedStyle(target4); + assert_equals(s.getPropertyValue('--x'), ''); + }, 'getComputedStyle when container is display:none'); + </script> + + <!-- Target element is display:none in nested container --> + <div class="container big"> + <div> + <div> + <div class="container"> + <div> + <div> + <div class="target none" id=target5></div> + </div> + </div> + </div> + </div> + </div> + </div> + <script> + test(function() { + let s = getComputedStyle(target5); + assert_equals(s.getPropertyValue('--x'), '30'); + }, 'getComputedStyle when element in nested container is display:none'); + </script> + + <!-- Inner container is display:none --> + <div class="container big"> + <div> + <div> + <div class="container none"> + <div> + <div> + <div class="target" id=target6></div> + </div> + </div> + </div> + </div> + </div> + </div> + <script> + test(function() { + let s = getComputedStyle(target6); + assert_equals(s.getPropertyValue('--x'), ''); + }, 'getComputedStyle when inner container is display:none'); + </script> + + <!-- Intermediate ancestor is display:none --> + <div class="container big"> + <div class="none"> + <div> + <div class="container"> + <div> + <div> + <div class="target" id=target7></div> + </div> + </div> + </div> + </div> + </div> + </div> + <script> + test(function() { + let s = getComputedStyle(target7); + assert_equals(s.getPropertyValue('--x'), ''); + }, 'getComputedStyle when intermediate ancestor is display:none'); + </script> + + <!-- Outer container is display:none --> + <div class="container big none"> + <div> + <div> + <div class="container"> + <div> + <div> + <div class="target" id=target8></div> + </div> + </div> + </div> + </div> + </div> + </div> + <script> + test(function() { + let s = getComputedStyle(target8); + assert_equals(s.getPropertyValue('--x'), ''); + }, 'getComputedStyle when outer container is display:none'); + </script> + + <!-- Nothing is display:none initially, but target becomes display:none --> + <div class="container"> + <div> + <div> + <div class="target" id=target9></div> + </div> + </div> + </div> + <script> + test(function() { + let s = getComputedStyle(target9); + assert_equals(s.getPropertyValue('--x'), '30'); + target9.classList.add('none'); + assert_equals(s.getPropertyValue('--x'), '30'); + }, 'getComputedStyle when element becomes display:none'); + </script> + + <!-- Nothing is display:none initially, but parent becomes display:none --> + <div class="container"> + <div> + <div id=parent10> + <div class="target" id=target10></div> + </div> + </div> + </div> + <script> + test(function() { + let s = getComputedStyle(target10); + assert_equals(s.getPropertyValue('--x'), '30'); + parent10.classList.add('none'); + assert_equals(s.getPropertyValue('--x'), '30'); + }, 'getComputedStyle when parent becomes display:none'); + </script> + + <!-- Nothing is display:none initially, but ancestor becomes display:none --> + <div class="container"> + <div id=ancestor11> + <div> + <div class="target" id=target11></div> + </div> + </div> + </div> + <script> + test(function() { + let s = getComputedStyle(target11); + assert_equals(s.getPropertyValue('--x'), '30'); + ancestor11.classList.add('none'); + assert_equals(s.getPropertyValue('--x'), '30'); + }, 'getComputedStyle when ancestor becomes display:none'); + </script> + + <!-- Nothing is display:none initially, but container becomes display:none --> + <div class="container" id=container12> + <div> + <div> + <div class="target" id=target12></div> + </div> + </div> + </div> + <script> + test(function() { + let s = getComputedStyle(target12); + assert_equals(s.getPropertyValue('--x'), '30'); + container12.classList.add('none'); + assert_equals(s.getPropertyValue('--x'), ''); + }, 'getComputedStyle when container becomes display:none'); + </script> + + <!-- Intermediate container becomes display:none --> + <div class="container big"> + <div> + <div> + <div class="container" id=container13> + <div> + <div> + <div class="target" id=target13></div> + </div> + </div> + </div> + </div> + </div> + </div> + <script> + test(function() { + let s = getComputedStyle(target13); + assert_equals(s.getPropertyValue('--x'), '30'); + container13.classList.add('none'); + assert_equals(s.getPropertyValue('--x'), ''); + }, 'getComputedStyle when intermediate container becomes display:none'); + </script> + + <!-- Pseudo-element is display:none --> + <div class="container"> + <div> + <div> + <div class="target pseudo_none" id=target14></div> + </div> + </div> + </div> + <script> + test(function() { + let s = getComputedStyle(target14, '::before'); + assert_equals(s.getPropertyValue('content'), '"foo"'); + assert_equals(s.getPropertyValue('--x'), '30'); + }, 'getComputedStyle when ::before is display:none'); + </script> + + <!-- Pseudo-element with display:none originating element --> + <div class="container"> + <div> + <div> + <div class="target pseudo none" id=target15></div> + </div> + </div> + </div> + <script> + test(function() { + let s = getComputedStyle(target15, '::before'); + assert_equals(s.getPropertyValue('content'), '"foo"'); + assert_equals(s.getPropertyValue('--x'), '30'); + }, 'getComputedStyle when originating element is display:none'); + </script> + + <!-- Pseudo-element with display:none ancestor --> + <div class="container"> + <div class="none"> + <div> + <div class="target pseudo" id=target16></div> + </div> + </div> + </div> + <script> + test(function() { + let s = getComputedStyle(target16, '::before'); + assert_equals(s.getPropertyValue('content'), '"foo"'); + assert_equals(s.getPropertyValue('--x'), '30'); + }, 'getComputedStyle on ::before when ancestor element is display:none'); + </script> + + <!-- Pseudo-element with in display:none container --> + <div class="container none"> + <div> + <div> + <div class="target pseudo" id=target17></div> + </div> + </div> + </div> + <script> + test(function() { + let s = getComputedStyle(target17, '::before'); + assert_equals(s.getPropertyValue('content'), '"foo"'); + assert_equals(s.getPropertyValue('--x'), ''); + }, 'getComputedStyle on ::before when container is display:none'); + </script> + + <!-- Target in display:none with layout dirty outer element --> + <div class=small id="outer18"> + <div class="container auto"> + <div class="none"> + <div> + <div class="target" id=target18></div> + </div> + </div> + </div> + </div> + <script> + test(function() { + target18.offsetTop; + let s = getComputedStyle(target18); + assert_equals(s.getPropertyValue('--x'), ''); + + outer18.classList.remove('small'); + outer18.classList.add('big'); + assert_equals(s.getPropertyValue('--x'), '50'); + }, 'getComputedStyle when in display:none with layout dirty outer element'); + </script> + + <!-- Intermediate container has forced style --> + <div class="container"> + <div class="none"> + <div id="inner19" class="container"> + <div id="target19" class="target"></div> + </div> + </div> + </div> + <script> + test(function() { + getComputedStyle(inner19).getPropertyValue('--x'); + let s = getComputedStyle(target19); + assert_equals(s.getPropertyValue('--x'), ''); + }, 'getComputedStyle when display:none inner container has forced style'); + </script> +</main> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/fieldset-legend-change-ref.html b/testing/web-platform/tests/css/css-contain/container-queries/fieldset-legend-change-ref.html new file mode 100644 index 0000000000..b6e8dc6038 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/fieldset-legend-change-ref.html @@ -0,0 +1,4 @@ +<!doctype html> +<title>CSS Test Reference</title> +<p>Pass if the rendered legend below is "PASS"</p> +<fieldset style="width:400px"><legend>PASS</legend></fieldset> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/fieldset-legend-change.html b/testing/web-platform/tests/css/css-contain/container-queries/fieldset-legend-change.html new file mode 100644 index 0000000000..15b44a0e52 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/fieldset-legend-change.html @@ -0,0 +1,26 @@ +<!doctype html> +<title>CSS Container Queries Test: inline-size query changes rendered legend in fieldset</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#size-container"> +<link rel="match" href="fieldset-legend-change-ref.html"> +<p>Pass if the rendered legend below is "PASS"</p> +<style> + fieldset { + width: 200px; + container-type: inline-size; + } + .wide { width: 400px; } + + @container (min-width: 300px) { + #fail { + display: none; + } + } +</style> +<fieldset id="fieldset"> + <legend id="fail">FAIL</legend> + <legend>PASS</legend> +</fieldset> +<script> + fieldset.offsetTop; + fieldset.className = "wide"; +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/font-relative-calc-dynamic.html b/testing/web-platform/tests/css/css-contain/container-queries/font-relative-calc-dynamic.html new file mode 100644 index 0000000000..54f01d45a3 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/font-relative-calc-dynamic.html @@ -0,0 +1,35 @@ +<!doctype html> +<title>CSS Container Queries Test: font-relative calc - dynamic</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#size-container"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/cq-testcommon.js"></script> +<style> + body { font-size: 10px; } + body.larger { font-size: 20px; } + #container { + container-type: inline-size; + width: 100px; + color: red; + } + #intermediate { + font-size: 8px; + } + @container (width: calc(1em + 80px)) { + #target { color: green; } + } +</style> +<div id="container"> + <div id=intermediate> + <div id="target"></div> + </div> +</div> +<script> + setup(() => assert_implements_container_queries()); + + test(() => { + assert_equals(getComputedStyle(target).color, 'rgb(255, 0, 0)'); + document.body.className = 'larger'; + assert_equals(getComputedStyle(target).color, 'rgb(0, 128, 0)'); + }, 'font-relative calc() is responsive to container font-size changes'); +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/font-relative-units-dynamic.html b/testing/web-platform/tests/css/css-contain/container-queries/font-relative-units-dynamic.html new file mode 100644 index 0000000000..63a07c61db --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/font-relative-units-dynamic.html @@ -0,0 +1,280 @@ +<!doctype html> +<title>CSS Container Queries Test: font-relative units - dynamic</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#size-container"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/cq-testcommon.js"></script> +<script> + +setup(() => assert_implements_container_queries()); + +// Inflate a <template> subtree into #main, run the test function, +// then clean up. +function test_template(template_element, test_fn, description) { + test((t) => { + assert_equals(template_element.tagName, "TEMPLATE"); + t.add_cleanup(() => main.replaceChildren()); + main.append(template_element.content.cloneNode(true)); + test_fn(t); + }, description); +} + +const green = "rgb(0, 128, 0)"; +const red = "rgb(255, 0, 0)"; + +</script> + +<style> + main { + color: red; + } + #container { + container-type: inline-size; + width: 100px; + } + #container > div { + font-size: 16px; + } +</style> + +<main id=main> +</main> + +<template> + <style> + main { font-size: 10px; } + main.larger { font-size: 20px; } + @container (width: 5em) { + #test { color: green } + } + </style> + <div id="container"> + <div> + <div id="test"></div> + </div> + </div> +</template> +<script> +test_template(document.currentScript.previousElementSibling, (t) => { + t.add_cleanup(() => main.classList.remove("larger")); + assert_equals(getComputedStyle(main.querySelector("#test")).color, red); + main.classList.add("larger"); + assert_equals(getComputedStyle(main.querySelector("#test")).color, green); +}, 'em units respond to changes'); +</script> + +<template> + <style> + :root { font-size: 10px; } + :root.larger { font-size: 50px; } + @container (width: 2rem) { + #test { color: green } + } + </style> + <div id="container"> + <div> + <div id="test"></div> + </div> + </div> +</template> +<script> +test_template(document.currentScript.previousElementSibling, (t) => { + t.add_cleanup(() => document.documentElement.classList.remove("larger")); + assert_equals(getComputedStyle(main.querySelector("#test")).color, red); + document.documentElement.classList.add("larger"); + assert_equals(getComputedStyle(main.querySelector("#test")).color, green); +}, 'rem units respond to changes'); +</script> + +<template> + <style> + main { font-size: 10px; } + main.larger { font-size: 20px; } + @container (width <= 15ex) { + #test { color: green } + } + </style> + <div id="container"> + <div> + <div id="test"></div> + </div> + </div> +</template> +<script> +test_template(document.currentScript.previousElementSibling, (t) => { + t.add_cleanup(() => main.classList.remove("larger")); + assert_equals(getComputedStyle(main.querySelector("#test")).color, red); + main.classList.add("larger"); + assert_equals(getComputedStyle(main.querySelector("#test")).color, green); +}, 'ex units respond to changes'); +</script> + +<template> + <style> + :root { font-size: 10px; } + :root.larger { font-size: 20px; } + @container (width <= 12rex) { + #test { color: green } + } + </style> + <div id="container"> + <div> + <div id="test"></div> + </div> + </div> +</template> +<script> +test_template(document.currentScript.previousElementSibling, (t) => { + t.add_cleanup(() => document.documentElement.classList.remove("larger")); + assert_equals(getComputedStyle(main.querySelector("#test")).color, red); + document.documentElement.classList.add("larger"); + assert_equals(getComputedStyle(main.querySelector("#test")).color, green); +}, 'rex units respond to changes'); +</script> + +<template> + <style> + main { font-size: 10px; } + main.larger { font-size: 20px; } + @container (width <= 15ch) { + #test { color: green } + } + </style> + <div id="container"> + <div> + <div id="test"></div> + </div> + </div> +</template> +<script> +test_template(document.currentScript.previousElementSibling, (t) => { + t.add_cleanup(() => main.classList.remove("larger")); + assert_equals(getComputedStyle(main.querySelector("#test")).color, red); + main.classList.add("larger"); + assert_equals(getComputedStyle(main.querySelector("#test")).color, green); +}, 'ch units respond to changes'); +</script> + +<template> + <style> + :root { font-size: 10px; } + :root.larger { font-size: 20px; } + @container (width <= 15rch) { + #test { color: green } + } + </style> + <div id="container"> + <div> + <div id="test"></div> + </div> + </div> +</template> +<script> +test_template(document.currentScript.previousElementSibling, (t) => { + t.add_cleanup(() => document.documentElement.classList.remove("larger")); + assert_equals(getComputedStyle(main.querySelector("#test")).color, red); + document.documentElement.classList.add("larger"); + assert_equals(getComputedStyle(main.querySelector("#test")).color, green); +}, 'rch units respond to changes'); +</script> + +<template> + <style> + main { + font-size: 10px; + line-height: 5; + } + main.larger { font-size: 20px; } + @container (width <= 1lh) { + #test { color: green } + } + </style> + <div id="container"> + <div> + <div id="test"></div> + </div> + </div> +</template> +<script> +test_template(document.currentScript.previousElementSibling, (t) => { + t.add_cleanup(() => main.classList.remove("larger")); + assert_equals(getComputedStyle(main.querySelector("#test")).color, red); + main.classList.add("larger"); + assert_equals(getComputedStyle(main.querySelector("#test")).color, green); +}, 'lh units respond to changes'); +</script> + +<template> + <style> + :root { + font-size: 10px; + line-height: 5; + } + :root.larger { + font-size: 20px; + } + @container (width <= 1rlh) { + #test { color: green } + } + </style> + <div id="container"> + <div> + <div id="test"></div> + </div> + </div> +</template> +<script> +test_template(document.currentScript.previousElementSibling, (t) => { + t.add_cleanup(() => document.documentElement.classList.remove("larger")); + assert_equals(getComputedStyle(main.querySelector("#test")).color, red); + document.documentElement.classList.add("larger"); + assert_equals(getComputedStyle(main.querySelector("#test")).color, green); +}, 'rlh units respond to changes'); +</script> + +<template> + <style> + main { font-size: 10px; } + main.larger { font-size: 20px; } + @container (width <= 8ic) { + #test { color: green } + } + </style> + <div id="container"> + <div> + <div id="test"></div> + </div> + </div> +</template> +<script> +test_template(document.currentScript.previousElementSibling, (t) => { + t.add_cleanup(() => main.classList.remove("larger")); + assert_equals(getComputedStyle(main.querySelector("#test")).color, red); + main.classList.add("larger"); + assert_equals(getComputedStyle(main.querySelector("#test")).color, green); +}, 'ic units respond to changes'); +</script> + + +<template> + <style> + :root { font-size: 10px; } + :root.larger { font-size: 20px; } + @container (width <= 8ric) { + #test { color: green } + } + </style> + <div id="container"> + <div> + <div id="test"></div> + </div> + </div> +</template> +<script> +test_template(document.currentScript.previousElementSibling, (t) => { + t.add_cleanup(() => document.documentElement.classList.remove("larger")); + assert_equals(getComputedStyle(main.querySelector("#test")).color, red); + document.documentElement.classList.add("larger"); + assert_equals(getComputedStyle(main.querySelector("#test")).color, green); +}, 'ric units respond to changes'); +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/font-relative-units.html b/testing/web-platform/tests/css/css-contain/container-queries/font-relative-units.html new file mode 100644 index 0000000000..7f711ebf96 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/font-relative-units.html @@ -0,0 +1,100 @@ +<!doctype html> +<title>CSS Container Queries Test: font-relative units</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#size-container"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/cq-testcommon.js"></script> +<style> + :root { font-size: 10px; line-height: 10px; } + #em_container { + container-type: inline-size; + width: 100px; + font-size: 100px; + } + #ex_container { + container-type: inline-size; + font-size: 50px; + width: 10ex; + height: 50rex; + } + #ch_container { + container-type: inline-size; + font-size: 50px; + width: 10ch; + } + #ic_container { + container-type: inline-size; + font-size: 50px; + width: 10ic; + } + #lh_container { + container-type: inline-size; + line-height: 50px; + width: 10lh; + } + @container (width: 1em) { + #em_test { color: green } + } + @container (width: 10rem) { + #rem_test { color: green } + } + @container (width: 10ex) { + #ex_test { color: green } + } + @container (49rex <= width <= 100rex) { + #rex_test { color: green } + } + @container (width: 10ch) { + #ch_test { color: green } + } + @container (width: 50rch) { + #rch_test { color: green } + } + @container (width: 10ic) { + #ic_test { color: green } + } + @container (width: 50ric) { + #ric_test { color: green } + } + @container (width: 10lh) { + #lh_test { color: green } + } + @container (width: 50rlh) { + #rlh_test { color: green } + } +</style> +<div id="em_container"> + <div id="em_test"></div> + <div id="rem_test"></div> +</div> +<div id="ex_container"> + <div id="ex_test"></div> + <div id="rex_test"></div> +</div> +<div id="ch_container"> + <div id="ch_test"></div> + <div id="rch_test"></div> +</div> +<div id="ic_container"> + <div id="ic_test"></div> + <div id="ric_test"></div> +</div> +<div id="lh_container"> + <div id="lh_test"></div> + <div id="rlh_test"></div> +</div> +<script> + setup(() => assert_implements_container_queries()); + + const green = "rgb(0, 128, 0)"; + test(() => assert_equals(getComputedStyle(em_test).color, green), "em relative inline-size"); + test(() => assert_equals(getComputedStyle(rem_test).color, green), "rem relative inline-size"); + test(() => assert_equals(getComputedStyle(ex_test).color, green), "ex relative inline-size"); + test(() => assert_equals(getComputedStyle(rex_test).color, green), "rex relative inline-size"); + test(() => assert_equals(getComputedStyle(ch_test).color, green), "ch relative inline-size"); + test(() => assert_equals(getComputedStyle(rch_test).color, green), "rch relative inline-size"); + test(() => assert_equals(getComputedStyle(ic_test).color, green), "ic relative inline-size"); + test(() => assert_equals(getComputedStyle(ric_test).color, green), "ric relative inline-size"); + test(() => assert_equals(getComputedStyle(lh_test).color, green), "lh relative inline-size"); + test(() => assert_equals(getComputedStyle(rlh_test).color, green), "rlh relative inline-size"); +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/fragmented-container-001.html b/testing/web-platform/tests/css/css-contain/container-queries/fragmented-container-001.html new file mode 100644 index 0000000000..886f179054 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/fragmented-container-001.html @@ -0,0 +1,48 @@ +<!doctype html> +<title>CSS Container Queries Test: Query fragmented inline-size container</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#size-container"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/cq-testcommon.js"></script> +<style> + #multicol { + width: 400px; + column-count: 2; + column-fill: auto; + column-gap: 0; + height: 100px; + } + #float { + float: left; + width: 100px; + height: 50px; + } + #container { + container-type: inline-size; + display: flow-root; + height: 200px; + } + #first-child { + break-after: column; + } + @container (width = 100px) { + #first-child { color: green; } + #second-child { color: green; } + } +</style> +<div id="multicol"> + <div id="float"></div> + <div id="container"> + <div id="first-child"></div> + <div id="second-child"></div> + </div> +</div> +<script> + setup(() => assert_implements_container_queries()); + + test(() => { + const green = "rgb(0, 128, 0)"; + assert_equals(getComputedStyle(document.querySelector("#first-child")).color, green); + assert_equals(getComputedStyle(document.querySelector("#second-child")).color, green); + }, "Children of fragmented inline-size container should match inline-size of first fragment"); +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/get-animations.html b/testing/web-platform/tests/css/css-contain/container-queries/get-animations.html new file mode 100644 index 0000000000..dca41c6ada --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/get-animations.html @@ -0,0 +1,34 @@ +<!doctype html> +<title>getAnimations depending on container query</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#animated-containers"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/cq-testcommon.js"></script> +<style> + #container { + container-type: inline-size; + width: 100px; + } + #div { color: red; } + @keyframes test { + from { color: green; } + to { color: green; } + } + @container (min-width: 200px) { + #div { animation: test 1s linear forwards; } + } +</style> +<div id=container> + <div id=div>Green</div> +</div> +<script> + setup(() => assert_implements_container_queries()); + + test(() => { + assert_equals(getComputedStyle(div).color, 'rgb(255, 0, 0)'); + + container.style = 'width:300px'; + assert_equals(div.getAnimations().length, 1); + assert_equals(getComputedStyle(div).color, 'rgb(0, 128, 0)'); + }, 'Calling getAnimations updates layout of parent frame if needed'); +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/grid-container.html b/testing/web-platform/tests/css/css-contain/container-queries/grid-container.html new file mode 100644 index 0000000000..60278e09c6 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/grid-container.html @@ -0,0 +1,29 @@ +<!doctype html> +<title>CSS Container Queries Test: Grid container</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#size-container"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/cq-testcommon.js"></script> +<style> + #grid { + display: grid; + container-type: inline-size; + width: 400px; + grid-template-columns: 1fr 1fr; + } + @container (width = 400px) { + #grid div { color: green } + } +</style> +<div id="grid"> + <div id="item1"></div> + <div id="item2"></div> +</div> +<script> + setup(() => assert_implements_container_queries()); + + test(() => { + assert_equals(getComputedStyle(item1).color, "rgb(0, 128, 0)"); + assert_equals(getComputedStyle(item2).color, "rgb(0, 128, 0)"); + }, "Check that grid items can query grid container"); +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/grid-item-container.html b/testing/web-platform/tests/css/css-contain/container-queries/grid-item-container.html new file mode 100644 index 0000000000..f1c66efc26 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/grid-item-container.html @@ -0,0 +1,38 @@ +<!doctype html> +<title>CSS Container Queries Test: Grid item container</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#size-container"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/cq-testcommon.js"></script> +<style> + #grid { + width: 300px; + display: grid; + grid-template-columns: 2fr 1fr; + } + .item { + container-type: inline-size; + } + @container (width > 50px) { + .item div { color: lime; } + } + @container (width > 150px) { + .item div { color: green; } + } +</style> +<div id="grid"> + <div class="item"> + <div id="target1"></div> + </div> + <div class="item"> + <div id="target2"></div> + </div> +</div> +<script> + setup(() => assert_implements_container_queries()); + + test(() => { + assert_equals(getComputedStyle(target1).color, "rgb(0, 128, 0)", "First item container should be 200px wide"); + assert_equals(getComputedStyle(target2).color, "rgb(0, 255, 0)", "Second item container should be 100px wide"); + }, "Check that children can query grid item containers"); +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/idlharness.html b/testing/web-platform/tests/css/css-contain/container-queries/idlharness.html new file mode 100644 index 0000000000..ac1a677bb9 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/idlharness.html @@ -0,0 +1,29 @@ +<!doctype html> +<title>CSS Container Queries: CSSContainer Rule IDL tests</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/WebIDLParser.js"></script> +<script src="/resources/idlharness.js"></script> +<!-- used to provide objects --> +<style> + @container cont (width = 100px) { + @container (inline-size > 200em) { + #id { color: lime } + } + #id { color: green } + } +</style> +<script> + idl_test( + ['css-contain-3'], + ['css-conditional', 'cssom', 'dom'], + idl_array => { + idl_array.add_objects({ + CSSContainerRule: ['sheet.cssRules[0]', + 'sheet.cssRules[0].cssRules[0]'], + }); + self.sheet = document.styleSheets[0]; + } + ); +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/iframe-in-container-invalidation.html b/testing/web-platform/tests/css/css-contain/container-queries/iframe-in-container-invalidation.html new file mode 100644 index 0000000000..f43d1ce789 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/iframe-in-container-invalidation.html @@ -0,0 +1,58 @@ +<!DOCTYPE html> +<title>@container-dependent elements respond to size changes of an @container-dependent iframe</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#size-container"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/cq-testcommon.js"></script> +<style> + #container { + container-type: size; + width: 200px; + height: 200px; + } + iframe { + width: 200px; + height: 40px; + } + @container (width > 300px) { + iframe { width: 400px; } + } +</style> +<div id=container> + <iframe id=iframe srcdoc=" + <style> + div#container { + container-type: size; + height: 20px; + } + div#child { color: red; } + @container (width > 300px) { + div#child { color: green; } + } + </style> + <div id=container> + <div id=child>Test</div> + </div> + "></iframe> +</div> +<script> + setup(() => assert_implements_container_queries()); + + function waitForLoad(w) { + return new Promise(resolve => w.addEventListener('load', resolve)); + } + + promise_test(async () => { + await waitForLoad(window); + let inner_div = iframe.contentDocument.querySelector('div#child'); + assert_equals(getComputedStyle(inner_div).color, 'rgb(255, 0, 0)'); + + // Changing the size of the outer container changes the size of the iframe, + // which in turn should change the size of the inner container (inside that + // iframe). + container.style.width = '400px'; + container.style.setProperty('--x', 'x'); // crbug.com/1312940 + + assert_equals(getComputedStyle(inner_div).color, 'rgb(0, 128, 0)'); + }); +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/iframe-invalidation.html b/testing/web-platform/tests/css/css-contain/container-queries/iframe-invalidation.html new file mode 100644 index 0000000000..51f2be9cfa --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/iframe-invalidation.html @@ -0,0 +1,43 @@ +<!doctype html> +<title>@container-dependent elements respond to iframe size changes</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#size-container"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/cq-testcommon.js"></script> +<style> + iframe { + width: 200px; + height: 40px; + } +</style> +<iframe id=iframe srcdoc=" + <style> + div#container { + container-type: size; + height: 20px; + } + div#child { color: red; } + @container (min-width: 300px) { + div#child { color: green; } + } + </style> + <div id=container> + <div id=child>Test</div> + </div> +"></iframe> +<script> + setup(() => assert_implements_container_queries()); + + function waitForLoad(w) { + return new Promise(resolve => w.addEventListener('load', resolve)); + } + + promise_test(async () => { + await waitForLoad(window); + let inner_div = iframe.contentDocument.querySelector('div#child'); + assert_equals(getComputedStyle(inner_div).color, 'rgb(255, 0, 0)'); + + iframe.style = 'width:400px'; + assert_equals(getComputedStyle(inner_div).color, 'rgb(0, 128, 0)'); + }) +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/ineligible-containment.html b/testing/web-platform/tests/css/css-contain/container-queries/ineligible-containment.html new file mode 100644 index 0000000000..36ce68d864 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/ineligible-containment.html @@ -0,0 +1,51 @@ +<!doctype html> +<title>Containers ineligible for containment</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#size-container"> +<link rel="help" href="https://drafts.csswg.org/css-contain-2/#containment-size"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/cq-testcommon.js"></script> +<style> + #outer, #inner1, #inner2 { + width: 200px; + container-type: inline-size; + } + #inner1 { + display: table; + } + p { + color: green; + } + @container (min-width: 1px) { + p { color: red; } + } +</style> +<div id=outer> + <div id=inner1> + <p id=p1>Test1</p> + </div> + <div id=inner2> + <p id=p2>Test1</p> + </div> +</main> +<script> + setup(() => assert_implements_container_queries()); + + test(function(t) { + // #inner1 is the container, but it does not satisfy the containment + // requirements, hence the query should fail. + assert_equals(getComputedStyle(p1).color, 'rgb(0, 128, 0)'); + }, 'Container ineligible for containment'); + + test(function(t) { + t.add_cleanup(() => { inner2.style = ''; }); + + assert_equals(getComputedStyle(p2).color, 'rgb(255, 0, 0)'); + + inner2.style = 'display:table'; + + // #inner2 is still the container, but it no longer satisfies the + // containment requirements. + assert_equals(getComputedStyle(p2).color, 'rgb(0, 128, 0)'); + }, 'Changing containment eligibility invalidates style'); +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/inline-size-and-min-width.html b/testing/web-platform/tests/css/css-contain/container-queries/inline-size-and-min-width.html new file mode 100644 index 0000000000..8ddcbc614c --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/inline-size-and-min-width.html @@ -0,0 +1,26 @@ +<!doctype html> +<title>CSS Container Queries Test: query of inline-size container is affected by min-width property</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-queries"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/cq-testcommon.js"></script> +<style> + #container { + container-type: inline-size; + min-width: 200px; + width: fit-content; + } + @container (min-width: 200px) { + #child { color: green } + } +</style> +<div id="container"> + <div id="child">Green</div> +</div> +<script> + setup(() => assert_implements_container_queries()); + + test(() => { + assert_equals(getComputedStyle(child).color, "rgb(0, 128, 0)"); + }, "min-width of inline-size container affects container size"); +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/inline-size-bfc-floats-ref.html b/testing/web-platform/tests/css/css-contain/container-queries/inline-size-bfc-floats-ref.html new file mode 100644 index 0000000000..ecd72b7516 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/inline-size-bfc-floats-ref.html @@ -0,0 +1,9 @@ +<!doctype html> +<title>CSS Test Reference</title> +<p>You should see the text "no red" to the left of the third float and no red.</p> +<div style="width:400px"> + <div style="float:right;width:200px;height:150px;background:blue"></div> + <div style="float:left;width:250px;height:100px;background:blue"></div> + <div style="float:right;width:300px;height:100px;background:blue"></div> + <div style="height:200px;display:flow-root">No red</div> +</div> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/inline-size-bfc-floats.html b/testing/web-platform/tests/css/css-contain/container-queries/inline-size-bfc-floats.html new file mode 100644 index 0000000000..88b81c6759 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/inline-size-bfc-floats.html @@ -0,0 +1,47 @@ +<!doctype html> +<title>CSS Container Queries Test: inline-size constrained by floats - layout moving forwards</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#size-container"> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#containment-inline-size"> +<link rel="match" href="inline-size-bfc-floats-ref.html"> +<style> + .float { float: left; background-color: blue; } + .right { float: right; } + + #outer { width: 400px; } + #float1 { width: 200px; height: 150px; } + #float2 { width: 250px; height: 100px; } + #float3 { width: 300px; height: 100px; } + + #container { container-type: inline-size; } + + /* Initially, text + 200px of red content (#content1 + #content2) is too tall + to make #container fit by #float1 */ + .content { height: 100px; background-color: red; } + + /* Trying to fit #container beside #float2 causes the width to remove + #content1. text + 100px of red content (#content2) is too tall to fit + beside #float2. It would at this point fit beside #float1, but that would + cause the width to increase again, and the spec says layout always moves + forward. */ + @container (width < 200px) { + #content1 { display: none } + } + + /* Trying to fit #container beside #float3 causes the rest of the red content + (#content2) to disappear. */ + @container (width < 150px) { + #content2 { display: none } + } +</style> +<p>You should see the text "no red" to the left of the third float and no red.</p> +<div id="outer"> + <div id="float1" class="float right"></div> + <div id="float2" class="float left"></div> + <div id="float3" class="float right"></div> + + <div id="container"> + No red + <div id="content1" class="content"></div> + <div id="content2" class="content"></div> + </div> +</div> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/inline-size-containment-vertical-rl.html b/testing/web-platform/tests/css/css-contain/container-queries/inline-size-containment-vertical-rl.html new file mode 100644 index 0000000000..38c88f2df7 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/inline-size-containment-vertical-rl.html @@ -0,0 +1,38 @@ +<!doctype html> +<title>CSS Container Queries Test: query of inline-size container in vertical-rl</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#size-container"> +<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org"> +<style> + #ancestry { writing-mode: vertical-rl; } + #keg { container-type: inline-size; } + @container (max-height: 200px) { + #target { width: 400px; } + } + @container (min-height: 400px) { + #target { width: 20px; } + } +</style> +<div id="ancestry"> + <div id="keg"> + <div id="target"> + <div style="width:50px;"></div> + </div> + </div> +</div> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/cq-testcommon.js"></script> +<script> + setup(() => assert_implements_container_queries()); + + test(()=> { + ancestry.style.height = "100px"; + assert_equals(keg.offsetWidth, 400); + + ancestry.style.height = "300px"; + assert_equals(keg.offsetWidth, 50); + + ancestry.style.height = "500px"; + assert_equals(keg.offsetWidth, 20); + }, "inline-size containment only"); +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/inline-size-containment.html b/testing/web-platform/tests/css/css-contain/container-queries/inline-size-containment.html new file mode 100644 index 0000000000..d519322bd2 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/inline-size-containment.html @@ -0,0 +1,37 @@ +<!doctype html> +<title>CSS Container Queries Test: query of inline-size container is affected by min-width property</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#size-container"> +<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org"> +<style> + #keg { container-type: inline-size; } + @container (max-width: 200px) { + #target { height: 400px; } + } + @container (min-width: 400px) { + #target { height: 20px; } + } +</style> +<div id="ancestry"> + <div id="keg"> + <div id="target"> + <div style="height:50px;"></div> + </div> + </div> +</div> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/cq-testcommon.js"></script> +<script> + setup(() => assert_implements_container_queries()); + + test(()=> { + ancestry.style.width = "100px"; + assert_equals(keg.offsetHeight, 400); + + ancestry.style.width = "300px"; + assert_equals(keg.offsetHeight, 50); + + ancestry.style.width = "500px"; + assert_equals(keg.offsetHeight, 20); + }, "inline-size containment only"); +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/inner-first-line-non-matching-ref.html b/testing/web-platform/tests/css/css-contain/container-queries/inner-first-line-non-matching-ref.html new file mode 100644 index 0000000000..99e9c334bf --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/inner-first-line-non-matching-ref.html @@ -0,0 +1,3 @@ +<!doctype html> +<title>CSS Test Reference</title> +<div style="color:green">This text should be green.</div> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/inner-first-line-non-matching.html b/testing/web-platform/tests/css/css-contain/container-queries/inner-first-line-non-matching.html new file mode 100644 index 0000000000..5f39124e51 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/inner-first-line-non-matching.html @@ -0,0 +1,13 @@ +<!doctype html> +<title>CSS Container Queries Test: Non-matching ::first-line in @container</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-queries"> +<link rel="match" href="inner-first-line-non-matching-ref.html"> +<style> + #outer::first-line { color: green } + @container (width > 99999px) { + #inner::first-line { color: red } + } +</style> +<div id="outer"> + <div id="inner">This text should be green.</div> +</div> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/layout-dependent-focus.html b/testing/web-platform/tests/css/css-contain/container-queries/layout-dependent-focus.html new file mode 100644 index 0000000000..a16370ac56 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/layout-dependent-focus.html @@ -0,0 +1,39 @@ +<!doctype html> +<title>CSS Container Queries: Input losing focus as a result of a size query</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#size-container"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/cq-testcommon.js"></script> +<style> + #container { + container-type: inline-size; + width: 200px; + } + #container.narrow { + width: 100px; + } + @container (width = 100px) { + #inner.hide { visibility: hidden; } + } +</style> +<div id="outer"> + <div id="container"> + <input type="text" id="inner"> + </div> +</div> +<script> + setup(() => assert_implements_container_queries()); + + let hide_test = async_test("Verify that onblur is called on hidden input"); + onload = () => { + inner.addEventListener("blur", () => hide_test.done()); + inner.focus(); + inner.className = "hide"; + container.className = "narrow"; + requestAnimationFrame(() => { + requestAnimationFrame(() => { + hide_test.step(() => assert_unreached("Event listener for 'blur' not called")); + }); + }); + }; +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/multicol-container-001.html b/testing/web-platform/tests/css/css-contain/container-queries/multicol-container-001.html new file mode 100644 index 0000000000..3032170ac6 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/multicol-container-001.html @@ -0,0 +1,31 @@ +<!doctype html> +<title>CSS Container Queries Test: Query multicol container</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#size-container"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/cq-testcommon.js"></script> +<style> + #multicol { + container-type: inline-size; + width: 400px; + column-count: 2; + column-gap: 0; + } + @container (width = 400px) { + #first-child { color: green; } + #second-child { color: green; } + } +</style> +<div id="multicol"> + <div id="first-child">First</div> + <div id="second-child">Second</div> +</div> +<script> + setup(() => assert_implements_container_queries()); + + test(() => { + const green = "rgb(0, 128, 0)"; + assert_equals(getComputedStyle(document.querySelector("#first-child")).color, green); + assert_equals(getComputedStyle(document.querySelector("#second-child")).color, green); + }, "Children of multicol inline-size container should match inline-size of the container"); +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/multicol-inside-container.html b/testing/web-platform/tests/css/css-contain/container-queries/multicol-inside-container.html new file mode 100644 index 0000000000..9fc8393a51 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/multicol-inside-container.html @@ -0,0 +1,28 @@ +<!doctype html> +<title>CSS Container Queries Test: Multicol inside size container</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#size-container"> +<link rel="match" href="/css/reference/ref-filled-green-100px-square-only.html"> +<style> + #container { + container-type: size; + width: 200px; + height: 100px; + } + @container (width <= 200px) { + #multicol { + column-count: 2; + column-gap: 0; + } + } + #green { + display: inline-block; + width: 100%; + height: 100px; + background-color: green; + vertical-align: bottom; + } +</style> +<p>Test passes if there is a filled green square.</p> +<div id="container"> + <div id="multicol"><div id="green"></div></div> +</div> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/nested-query-containers.html b/testing/web-platform/tests/css/css-contain/container-queries/nested-query-containers.html new file mode 100644 index 0000000000..83cc3c2fec --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/nested-query-containers.html @@ -0,0 +1,125 @@ +<!DOCTYPE html> +<title>Nested query containers affecting each other</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#size-container"> +<link rel="help" href="https://drafts.csswg.org/css-contain-2/#containment-size"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/cq-testcommon.js"></script> +<style> + body > section { + contain: strict; + width: 500px; + } +</style> +<body> +<script> +promise_setup(() => { + assert_implements_container_queries(); + return new Promise(resolve => { + addEventListener("load", () => { + requestAnimationFrame(() => { + requestAnimationFrame(() => { + document.body.className = "run"; + resolve(); + }); + }); + }, {once: true}); + }); +}); + +function booleanTuples(n) { + const tuple = new Array(n); + function* recursion(i) { + if (i == n) { + yield tuple.slice(); + return; + } + tuple[i] = false; + yield* recursion(i + 1); + tuple[i] = true; + yield* recursion(i + 1); + } + return recursion(0); +} + +// The following display values evaluate container queries to unknown. +const testCases = [ + { + display: "inline", + expected: { + width: depth => depth % 2 ? 0 : 500 - depth, + height: depth => 0, + }, + }, + { + display: "contents", + expected: { + width: depth => depth % 2 ? 0 : 500 - depth, + height: depth => 0, + }, + }, + { + display: "table-cell", + expected: { + width: depth => depth % 2 ? 2 : 0, + height: depth => depth % 2 ? 2 : 0, + }, + }, + { + display: "table", + expected: { + width: depth => depth % 2 ? 4 : 0, + height: depth => depth % 2 ? 4 : 0, + }, + }, +]; + +let testNum = 1; +for (let testCase of testCases) { + for (let tuple of booleanTuples(3)) { + const section = document.createElement("section"); + const id = "test" + testNum; + section.id = id; + const style = document.createElement("style"); + style.textContent = ` + :where(body${tuple[0] ? ".run" : ""}) > #${id} { + container-type: size; + container-name: name; + } + :where(body${tuple[1] ? ".run" : ""}) > #${id} div { + container-type: size; + container-name: name; + border: solid; + border-width: 1px; + } + @container name (width >= 0) { + :where(body${tuple[2] ? ".run" : ""}) > #${id} div { + display: ${testCase.display}; + border-style: dotted; + } + } + `; + section.appendChild(style); + section.insertAdjacentHTML( + "beforeend", + "<div><div><div><div><div><div></div></div></div></div></div></div>" + ); + document.body.appendChild(section); + promise_test(async function() { + let div = section.querySelector("div"); + let depth = 1; + while (div) { + const cs = getComputedStyle(div); + assert_equals(cs.display, depth % 2 ? testCase.display : "block"); + assert_equals(cs.borderStyle, depth % 2 ? "dotted" : "solid", "borderStyle"); + assert_equals(div.clientWidth, testCase.expected.width(depth), "clientWidth"); + assert_equals(div.clientHeight, testCase.expected.height(depth), "clientHeight"); + div = div.firstElementChild; + depth += 1; + } + }, id + " - " + testCase.display + " - 0b" + tuple.map(Number).join("")); + testNum += 1; + } +} +</script> +</body> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/never-match-container.html b/testing/web-platform/tests/css/css-contain/container-queries/never-match-container.html new file mode 100644 index 0000000000..9d5ff6d227 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/never-match-container.html @@ -0,0 +1,44 @@ +<!doctype html> +<title>CSS Container Queries Test: @container querying size of elements without layout containment</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#size-container"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/cq-testcommon.js"></script> +<script> + setup(() => assert_implements_container_queries()); +</script> +<style> + #outer-container { + width: 100px; + container-type: inline-size; + } + #container-inline, #svg-container { + width: 100px; + container-type: inline-size; + } + @container (width >= 0px) { + #inner { color: red; } + #svg-inner { fill: red; } + } +</style> +<div id="outer-container"> + <span id="container-inline"> + <span id="inner">Not red</span> + </span> + <svg> + <g id="svg-container"> + <text x="0" y="20" id="svg-inner">Not red</text> + </g> + </svg> +</div> +<script> + const red = "rgb(255, 0, 0)"; + + test(() => { + assert_not_equals(getComputedStyle(inner).color, red); + }, "Size @container query against inline box never matches"); + + test(() => { + assert_not_equals(getComputedStyle(document.querySelector("#svg-inner")).fill, red); + }, "Size @container query against svg element never matches"); +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/orthogonal-wm-container-query.html b/testing/web-platform/tests/css/css-contain/container-queries/orthogonal-wm-container-query.html new file mode 100644 index 0000000000..1ad52bf499 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/orthogonal-wm-container-query.html @@ -0,0 +1,38 @@ +<!doctype html> +<title>CSS Container Queries Test: Orthogonal writing-mode change in @container</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#size-container"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/cq-testcommon.js"></script> +<link rel="stylesheet" href="/fonts/ahem.css"> +<style> + #container { + container-type: size; + width: 50vw; + height: 50vh; + } + #orthogonal { + font: 50px/1 Ahem; + } + @container (max-width: 100px) { + #orthogonal { + writing-mode: vertical-lr; + } + } +</style> +<div id="container"> + <div id="orthogonal">XX</div> +</div> +<script> + setup(() => assert_implements_container_queries()); + + test(() => { + assert_equals(orthogonal.offsetWidth, container.offsetWidth); + }, "Initial non-orthogonal width"); + + test(() => { + container.style.width = "100px"; + assert_equals(orthogonal.offsetWidth, 50); + assert_not_equals(orthogonal.offsetWidth, container.offsetWidth); + }, "Orthogonal width"); +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/percentage-padding-orthogonal.html b/testing/web-platform/tests/css/css-contain/container-queries/percentage-padding-orthogonal.html new file mode 100644 index 0000000000..0c419d18a9 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/percentage-padding-orthogonal.html @@ -0,0 +1,66 @@ +<!doctype html> +<title>CSS Container Queries Test: @container queries affecting height affecting percentage padding</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-queries"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/cq-testcommon.js"></script> +<style> + #vertical { + width: 500px; + writing-mode: vertical-lr; + } + + #padded { + width: 100%; + box-sizing: border-box; + padding-right: 100%; + background-color: orange; + } + + #horizontal { + writing-mode: horizontal-tb; + width: 100%; + } + + #container { + width: 100%; + container-type: inline-size; + background-color: green; + } + + #first, #second { height: 50px; } + + @container (width <= 400px) { + #second { display: none; } + } +</style> +<div id="vertical"> + <div id="padded"> + <div id="horizontal"> + <div id="container"> + <div id="first"></div> + <div id="second"></div> + </div> + </div> + </div> +</div> +<script> + setup(() => assert_implements_container_queries()); + + test(() => assert_equals(padded.offsetHeight, 100), + "#container height measured with 500px width. Both container children visible"); + test(() => assert_equals(container.offsetWidth, 400), + "#container width 400px after padding is applied."); + test(() => assert_equals(container.offsetHeight, 50), + "#container width 400px after padding is applied. #second is removed from the rendering"); + + // Reduce width by 1px to test that a re-layout is not stateful. + vertical.style.width = "499px"; + + test(() => assert_equals(padded.offsetHeight, 100), + "#container height measured with 499px width. Both container children visible"); + test(() => assert_equals(container.offsetWidth, 399), + "#container width 399px after padding is applied. #second is removed from the rendering"); + test(() => assert_equals(container.offsetHeight, 50), + "#container width 399x after padding is applied. #second is removed from the rendering"); +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/pseudo-elements-001.html b/testing/web-platform/tests/css/css-contain/container-queries/pseudo-elements-001.html new file mode 100644 index 0000000000..0baef0bfc2 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/pseudo-elements-001.html @@ -0,0 +1,59 @@ +<!DOCTYPE html> +<title>CSS Container Queries Test: Container for elements with pseudo elements</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#query-container"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/cq-testcommon.js"></script> +<style> + :root { + color: black; + } + + .container { + container-type: size; + width: 200px; + height: 40px; + } + + @container (min-width: 300px) { + #container1 div::before { content: "before"; } + #container1 div::after { content: "after"; } + #container2 li::marker { color: green; } + } +</style> +<main id=container1 class=container> + <div>test</div> +</main> +<main id=container2 class=container> + <ol> + <li>One</li> + </ol> +</main> +<script> + setup(() => assert_implements_container_queries()); + + test(function() { + let div = document.querySelector('#container1 > div'); + assert_equals(getComputedStyle(div, '::before').content, 'none'); + assert_equals(getComputedStyle(div, '::after').content, 'none'); + + container1.style.width = '300px'; + assert_equals(getComputedStyle(div, '::before').content, '"before"'); + assert_equals(getComputedStyle(div, '::after').content, '"after"'); + + container1.style = ''; + assert_equals(getComputedStyle(div, '::before').content, 'none'); + assert_equals(getComputedStyle(div, '::after').content, 'none'); + }, 'Pseudo-elements ::before and ::after respond to container size changes'); + + test(function() { + let li = document.querySelector('#container2 li'); + assert_equals(getComputedStyle(li, '::marker').color, 'rgb(0, 0, 0)'); + + container2.style.width = '300px'; + assert_equals(getComputedStyle(li, '::marker').color, 'rgb(0, 128, 0)'); + + container2.style = ''; + assert_equals(getComputedStyle(li, '::marker').color, 'rgb(0, 0, 0)'); + }, 'Pseudo-element ::marker responds to container size changes'); +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/pseudo-elements-002-ref.html b/testing/web-platform/tests/css/css-contain/container-queries/pseudo-elements-002-ref.html new file mode 100644 index 0000000000..da96a826cf --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/pseudo-elements-002-ref.html @@ -0,0 +1,6 @@ +<!DOCTYPE html> +<title>CSS Test Reference</title> +<div>PASS</div> +<div>PASS</div> +<div>PASS</div> +<div>PASS</div> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/pseudo-elements-002.html b/testing/web-platform/tests/css/css-contain/container-queries/pseudo-elements-002.html new file mode 100644 index 0000000000..a44c64c700 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/pseudo-elements-002.html @@ -0,0 +1,28 @@ +<!DOCTYPE html> +<title>CSS Container Queries Test: Container for ::before/::after pseudo elements</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-queries"> +<link rel="match" href="pseudo-elements-002-ref.html"> +<style> + .container { container-type: inline-size; } + + @container (max-width: 100px) { #c1::before { content: "PASS" } } + @container (min-width: 150px) { #c1::before { content: "FAIL" } } + + @container (max-width: 100px) { #c2::before { content: "PASS" } } + @container (min-width: 150px) { #c2::before { content: "FAIL" } } + + @container (max-width: 100px) { #c3::after { content: "PASS" } } + @container (min-width: 150px) { #c3::after { content: "FAIL" } } + + @container (max-width: 100px) { #c4::after { content: "PASS" } } + @container (min-width: 150px) { #c4::after { content: "FAIL" } } +</style> +<div id="c1" class="container" style="width:100px"></div> +<div id="c2" class="container" style="width:200px"></div> +<div id="c3" class="container" style="width:100px"></div> +<div id="c4" class="container" style="width:200px"></div> +<script> + document.body.offsetTop; + c2.style.width = "100px"; + c4.style.width = "100px"; +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/pseudo-elements-002b-ref.html b/testing/web-platform/tests/css/css-contain/container-queries/pseudo-elements-002b-ref.html new file mode 100644 index 0000000000..5783b77fec --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/pseudo-elements-002b-ref.html @@ -0,0 +1,12 @@ +<!DOCTYPE html> +<title>CSS Test Reference</title> +<div><span style="color:green">P</span>ASS if P is green.</div> +<div><span style="color:green">P</span>ASS if P is green.</div> +<div><span style="color:green">P</span>ASS if P is green.</div> +<div><span style="color:green">P</span>ASS if P is green.</div> +<div style="color:green">PASS if text is green.</div> +<div style="color:green">PASS if text is green.</div> +<div style="color:green">PASS if text is green.</div> +<div style="color:green">PASS if text is green.</div> +<div style="color:green">PASS if text is green.</div> +<div style="color:green">PASS if text is green.</div> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/pseudo-elements-002b.html b/testing/web-platform/tests/css/css-contain/container-queries/pseudo-elements-002b.html new file mode 100644 index 0000000000..e1874e035b --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/pseudo-elements-002b.html @@ -0,0 +1,58 @@ +<!DOCTYPE html> +<title>CSS Container Queries Test: Container for ::first-letter/::first-line pseudo elements</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-queries"> +<link rel="match" href="pseudo-elements-002b-ref.html"> +<style> + .container { container-type: inline-size; } + + @container (max-width: 300px) { #c5::first-letter { color: green } } + @container (max-width: 300px) { #c6::first-letter { color: green } } + + @container (min-width: 400px) { #c7::first-letter { color: green } } + @container (min-width: 400px) { #c8::first-letter { color: green } } + + @container (max-width: 300px) { #c9::first-line { color: green } } + @container (max-width: 300px) { #c10::first-line { color: green } } + + @container (min-width: 400px) { #c11::first-line { color: green } } + @container (min-width: 400px) { #c12::first-line { color: green } } + + #c13::first-line { color: red } + @container (min-width: 400px) { #c13::first-line { color: green } } + @container (min-width: 400px) { #c14::first-line { color: green } } +</style> +<div class="container" style="width:400px"> + <div id="c5" class="container" style="width:300px">PASS if P is green.</div> +</div> +<div class="container" style="width:400px"> + <div id="c6" class="container" style="width:400px">PASS if P is green.</div> +</div> +<div id="c7" class="container" style="width:400px"> + <div class="container" style="width:300px">PASS if P is green.</div> +</div> +<div id="c8" class="container" style="width:300px"> + <div class="container" style="width:300px">PASS if P is green.</div> +</div> +<div class="container" style="width:400px"> + <div id="c9" class="container" style="width:300px">PASS if text is green.</div> +</div> +<div class="container" style="width:400px"> + <div id="c10" class="container" style="width:400px">PASS if text is green.</div> +</div> +<div id="c11" class="container" style="width:400px"> + <div class="container" style="width:300px">PASS if text is green.</div> +</div> +<div id="c12" class="container" style="width:300px"> + <div class="container" style="width:300px">PASS if text is green.</div> +</div> +<div id="c13" class="container" style="width:300px">PASS if text is green.</div> +<div id="c14" class="container" style="width:300px">PASS if text is green.</div> +<script> + document.body.offsetTop; + c6.style.width = "300px"; + c8.style.width = "400px"; + c10.style.width = "300px"; + c12.style.width = "400px"; + c13.style.width = "400px"; + c14.style.width = "400px"; +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/pseudo-elements-003.html b/testing/web-platform/tests/css/css-contain/container-queries/pseudo-elements-003.html new file mode 100644 index 0000000000..2d7647f710 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/pseudo-elements-003.html @@ -0,0 +1,69 @@ +<!doctype html> +<title>@container: originating element container for pseudo elements</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-queries"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/cq-testcommon.js"></script> +<style> + .container { container-type: inline-size; } + #target { display: list-item; } + @container (max-width: 200px) { + #target::before { content: "PASS"; color: green; } + #target::after { color: green; } + #target::marker { color: green; } + #target::first-line { color: green; } + #target::first-letter { color: green; } + } + @container ((min-width: 300px) and (max-width: 350px)) { + #outer::first-line { color: green; } + #outer::first-letter { color: green; } + } + dialog::backdrop { background-color: lime; } + @container (max-width: 100px) { + dialog::backdrop { background-color: green; } + } +</style> +<div style="width: 400px" class="container"> + <div style="width: 300px" class="container"> + <div id="target" class="container" style="width: 200px">First-line</div> + <dialog id="dialog" class="container" style="width: 100px"></dialog> + </div> + <div style="width: 400px" class="container"> + <div id="outer" style="width: 300px" class="container"> + <div class="container" style="width: 200px">First-line</div> + </div> +</div> +<script> + setup(() => assert_implements_container_queries()); + + const green = "rgb(0, 128, 0)"; + const lime = "rgb(0, 255, 0)"; + + test(() => { + assert_equals(getComputedStyle(target, "::before").color, green); + }, "Originating element container for ::before"); + test(() => { + assert_equals(getComputedStyle(target, "::after").color, green); + }, "Originating element container for ::after"); + test(() => { + assert_equals(getComputedStyle(target, "::marker").color, green); + }, "Originating element container for ::marker"); + test(() => { + assert_equals(getComputedStyle(target, "::first-line").color, green); + }, "Originating element container for ::first-line"); + test(() => { + assert_equals(getComputedStyle(target, "::first-letter").color, green); + }, "Originating element container for ::first-letter"); + test(() => { + assert_equals(getComputedStyle(outer, "::first-line").color, green); + }, "Originating element container for outer ::first-line"); + test(() => { + assert_equals(getComputedStyle(outer, "::first-letter").color, green); + }, "Originating element container for outer ::first-letter"); + test((t) => { + t.add_cleanup(() => dialog.close()); + assert_equals(getComputedStyle(dialog, "::backdrop").backgroundColor, lime, "::backdrop not rendered"); + dialog.showModal(); + assert_equals(getComputedStyle(dialog, "::backdrop").backgroundColor, green, "::backdrop rendered"); + }, "Originating element container for ::backdrop"); +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/pseudo-elements-004.html b/testing/web-platform/tests/css/css-contain/container-queries/pseudo-elements-004.html new file mode 100644 index 0000000000..db199f2205 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/pseudo-elements-004.html @@ -0,0 +1,52 @@ +<!doctype html> +<title>@container: originating element container for pseudo elements</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-queries"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/cq-testcommon.js"></script> +<style> + #target { container-type: inline-size; } + #target::before, + #target::after, + #target::marker, + #target::first-line, + #target::first-letter, + #target::backdrop { + color: red; + } + @container (width >= 300px) { + #target::before, + #target::after, + #target::marker, + #target::first-line, + #target::first-letter, + #target::backdrop { + color: green; + } + } +</style> +<div id="outer" style="width: 200px"> + <div id="target"></div> +</div> +<script> + setup(() => assert_implements_container_queries()); + + const green = "rgb(0, 128, 0)"; + const red = "rgb(255, 0, 0)"; + + const pseudo_elements = ["::before", "::after", "::marker", "::first-line", "::first-letter", "::backdrop"]; + + pseudo_elements.forEach((pseudo_element) => { + test(() => { + assert_equals(getComputedStyle(target, pseudo_element).color, red); + }, `Initial color for ${pseudo_element}`); + }); + + outer.style.width = "300px"; + + pseudo_elements.forEach((pseudo_element) => { + test(() => { + assert_equals(getComputedStyle(target, pseudo_element).color, green); + }, `Color for ${pseudo_element} depending on container`); + }); +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/pseudo-elements-005.html b/testing/web-platform/tests/css/css-contain/container-queries/pseudo-elements-005.html new file mode 100644 index 0000000000..575b66d6f8 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/pseudo-elements-005.html @@ -0,0 +1,58 @@ +<!doctype html> +<title>CSS Container Queries Test: Style container for pseudo elements</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#query-container"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/cq-testcommon.js"></script> +<style> + #c1 { + --theme: green; + } + @container style(--theme: green) { + #c1::before { + content: ""; + color: green; + display: block; + height: 100px; + } + } +</style> +<div id="c1"></div> +<script> + setup(() => assert_implements_container_queries()); + + test(() => { + let style = getComputedStyle(c1, "::before"); + assert_equals(style.color, "rgb(0, 128, 0)"); + assert_equals(style.height, "100px"); + }, "::before pseudo element querying style() of originating element"); +</script> + +<style> + #c2 { + --theme: red; + } + #c2::before { color: red } + #c2.green { + --theme: green; + } + @container style(--theme: green) { + #c2::before { + content: ""; + color: green; + } + } +</style> +<div id="c2"></div> +<script> + test(() => { + let style = getComputedStyle(c2, "::before"); + assert_equals(style.color, "rgb(255, 0, 0)"); + }, "::before pseudo element not matching style()"); + + test(() => { + c2.className = "green"; + let style = getComputedStyle(c2, "::before"); + assert_equals(style.color, "rgb(0, 128, 0)"); + }, "::before pseudo element matching style() query after class change"); +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/pseudo-elements-006.html b/testing/web-platform/tests/css/css-contain/container-queries/pseudo-elements-006.html new file mode 100644 index 0000000000..65aee97f75 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/pseudo-elements-006.html @@ -0,0 +1,66 @@ +<!doctype html> +<title>@container: originating element container for pseudo elements</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-queries"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/cq-testcommon.js"></script> +<style> + .container { container-type: inline-size; } + #target { display: list-item; } + @container (max-width: 200px) { + #target::before { content: "PASS"; font-size: 10cqw; } + #target::after { font-size: 10cqw; } + #target::marker { font-size: 10cqw; } + #target::first-line { font-size: 10cqw; } + #target::first-letter { font-size: 10cqw; } + } + @container ((min-width: 300px) and (max-width: 350px)) { + #outer::first-line { font-size: 10cqw; } + #outer::first-letter { font-size: 10cqw; } + } + dialog::backdrop { font-size: 0px; } + @container (max-width: 100px) { + dialog::backdrop { font-size: 10cqw; } + } +</style> +<div style="width: 400px" class="container"> + <div style="width: 300px" class="container"> + <div id="target" class="container" style="width: 200px">First-line</div> + <dialog id="dialog" class="container" style="width: 100px"></dialog> + </div> + <div style="width: 400px" class="container"> + <div id="outer" style="width: 300px" class="container"> + <div class="container" style="width: 200px">First-line</div> + </div> +</div> +<script> + setup(() => assert_implements_container_queries()); + + test(() => { + assert_equals(getComputedStyle(target, "::before").fontSize, "20px"); + }, "Originating element container for ::before"); + test(() => { + assert_equals(getComputedStyle(target, "::after").fontSize, "20px"); + }, "Originating element container for ::after"); + test(() => { + assert_equals(getComputedStyle(target, "::marker").fontSize, "20px"); + }, "Originating element container for ::marker"); + test(() => { + assert_equals(getComputedStyle(target, "::first-line").fontSize, "20px"); + }, "Originating element container for ::first-line"); + test(() => { + assert_equals(getComputedStyle(target, "::first-letter").fontSize, "20px"); + }, "Originating element container for ::first-letter"); + test(() => { + assert_equals(getComputedStyle(outer, "::first-line").fontSize, "30px"); + }, "Originating element container for outer ::first-line"); + test(() => { + assert_equals(getComputedStyle(outer, "::first-letter").fontSize, "30px"); + }, "Originating element container for outer ::first-letter"); + test((t) => { + t.add_cleanup(() => dialog.close()); + assert_equals(getComputedStyle(dialog, "::backdrop").fontSize, "0px", "::backdrop not rendered"); + dialog.showModal(); + assert_equals(getComputedStyle(dialog, "::backdrop").fontSize, "10px", "::backdrop rendered"); + }, "Originating element container for ::backdrop"); +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/pseudo-elements-007.html b/testing/web-platform/tests/css/css-contain/container-queries/pseudo-elements-007.html new file mode 100644 index 0000000000..951f4226f4 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/pseudo-elements-007.html @@ -0,0 +1,49 @@ +<!doctype html> +<title>@container: originating element container for pseudo elements</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-queries"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/cq-testcommon.js"></script> +<style> + #target { container-type: inline-size; } + #target::before, + #target::after, + #target::marker, + #target::first-line, + #target::first-letter, + #target::backdrop { + font-size: 0px; + } + @container (width >= 300px) { + #target::before, + #target::after, + #target::marker, + #target::first-line, + #target::first-letter, + #target::backdrop { + font-size: 10cqw; + } + } +</style> +<div id="outer" style="width: 200px"> + <div id="target"></div> +</div> +<script> + setup(() => assert_implements_container_queries()); + + const pseudo_elements = ["::before", "::after", "::marker", "::first-line", "::first-letter", "::backdrop"]; + + pseudo_elements.forEach((pseudo_element) => { + test(() => { + assert_equals(getComputedStyle(target, pseudo_element).fontSize, "0px"); + }, `Initial font-size for ${pseudo_element}`); + }); + + outer.style.width = "300px"; + + pseudo_elements.forEach((pseudo_element) => { + test(() => { + assert_equals(getComputedStyle(target, pseudo_element).fontSize, "30px"); + }, `font-size for ${pseudo_element} depending on container`); + }); +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/pseudo-elements-008.html b/testing/web-platform/tests/css/css-contain/container-queries/pseudo-elements-008.html new file mode 100644 index 0000000000..1d722a46b6 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/pseudo-elements-008.html @@ -0,0 +1,59 @@ +<!doctype html> +<title>@container: originating element container for pseudo elements</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-queries"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/cq-testcommon.js"></script> +<style> + .container { container-type: inline-size; } + #target { display: list-item; } + #target::before { content: "PASS"; font-size: 10cqw; } + #target::after { font-size: 10cqw; } + #target::marker { font-size: 10cqw; } + #target::first-line { font-size: 10cqw; } + #target::first-letter { font-size: 10cqw; } + #outer::first-line { font-size: 10cqw; } + #outer::first-letter { font-size: 10cqw; } + dialog::backdrop { font-size: 10cqw; } +</style> +<div style="width: 400px" class="container"> + <div style="width: 300px" class="container"> + <div id="target" class="container" style="width: 200px">First-line</div> + <dialog id="dialog" class="container" style="width: 100px"></dialog> + </div> + <div style="width: 400px" class="container"> + <div id="outer" style="width: 300px" class="container"> + <div class="container" style="width: 200px">First-line</div> + </div> +</div> +<script> + setup(() => assert_implements_container_queries()); + + test(() => { + assert_equals(getComputedStyle(target, "::before").fontSize, "20px"); + }, "Originating element container for ::before"); + test(() => { + assert_equals(getComputedStyle(target, "::after").fontSize, "20px"); + }, "Originating element container for ::after"); + test(() => { + assert_equals(getComputedStyle(target, "::marker").fontSize, "20px"); + }, "Originating element container for ::marker"); + test(() => { + assert_equals(getComputedStyle(target, "::first-line").fontSize, "20px"); + }, "Originating element container for ::first-line"); + test(() => { + assert_equals(getComputedStyle(target, "::first-letter").fontSize, "20px"); + }, "Originating element container for ::first-letter"); + test(() => { + assert_equals(getComputedStyle(outer, "::first-line").fontSize, "30px"); + }, "Originating element container for outer ::first-line"); + test(() => { + assert_equals(getComputedStyle(outer, "::first-letter").fontSize, "30px"); + }, "Originating element container for outer ::first-letter"); + test((t) => { + t.add_cleanup(() => dialog.close()); + assert_equals(getComputedStyle(dialog, "::backdrop").fontSize, "30px", "::backdrop not rendered"); + dialog.showModal(); + assert_equals(getComputedStyle(dialog, "::backdrop").fontSize, "10px", "::backdrop rendered"); + }, "Originating element container for ::backdrop"); +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/query-content-box.html b/testing/web-platform/tests/css/css-contain/container-queries/query-content-box.html new file mode 100644 index 0000000000..5f6cc9fdbe --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/query-content-box.html @@ -0,0 +1,80 @@ +<!doctype html> +<title>CSS Container Queries Test: Size queries match content-box</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#size-container"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/cq-testcommon.js"></script> +<style> + .container { + container-type: size; + border: 10px solid black; + padding: 40px; + margin: 20px; + } + + #container1 { + box-sizing: content-box; + width: 100px; + height: 100px; + } + + #container2 { + box-sizing: border-box; + width: 200px; + height: 200px; + } + + #container3 { + box-sizing: content-box; + width: 100px; + height: 100px; + overflow: scroll; + } + + #container4 { + box-sizing: border-box; + width: 200px; + height: 200px; + overflow: scroll; + } + + @container ((width = 100px) and (height = 100px)) { + .target { + background-color: green; + height: 100%; + } + } +</style> +<div id="container1" class="container"> + <div class="target"></div> +</div> +<div id="container2" class="container"> + <div class="target"></div> +</div> +<div id="container3" class="container"> + <div class="target"></div> +</div> +<div id="container4" class="container"> + <div class="target"></div> +</div> +<script> + setup(() => assert_implements_container_queries()); + + const green = "rgb(0, 128, 0)"; + + test(() => { + assert_equals(getComputedStyle(document.querySelector("#container1 > .target")).backgroundColor, green); + }, "Size queries with content-box sizing"); + + test(() => { + assert_equals(getComputedStyle(document.querySelector("#container2 > .target")).backgroundColor, green); + }, "Size queries with border-box sizing"); + + test(() => { + assert_equals(getComputedStyle(document.querySelector("#container3 > .target")).backgroundColor, green); + }, "Size queries with content-box sizing and overflow:scroll"); + + test(() => { + assert_equals(getComputedStyle(document.querySelector("#container4 > .target")).backgroundColor, green); + }, "Size queries with border-box sizing and overflow:scroll"); +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/query-evaluation-style.html b/testing/web-platform/tests/css/css-contain/container-queries/query-evaluation-style.html new file mode 100644 index 0000000000..4262f8bb0c --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/query-evaluation-style.html @@ -0,0 +1,80 @@ +<!doctype html> +<title>Evaluation of style queries</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-rule"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/cq-testcommon.js"></script> +<style> + #container { + --applied: false; + --foo: bar; + } +</style> +<div id=container> + <div id=inner></div> +</div> +<script> + setup(() => assert_implements_container_queries()); + + function test_query(query, expected) { + test((t) => { + let style = document.createElement('style'); + t.add_cleanup(() => { style.remove(); }); + style.innerText = `@container ${query} { #inner { --applied:true; } }`; + let cs = getComputedStyle(inner); + assert_equals(cs.getPropertyValue('--applied'), 'false'); + document.head.append(style); + assert_equals(cs.getPropertyValue('--applied'), expected.toString()); + }, query); + }; + + // Note that the following assumes that elements are style containers by + // default [1], and that: + // + // - style(--foo: bar) is a query that returns 'true', and + // - style(--baz: qux) is a query that returns 'false'. + // + // [1] https://github.com/w3c/csswg-drafts/issues/7066 + + // Nesting in <style-query>: + test_query('style((--foo: bar))', true); + test_query('style((--baz: qux))', false); + test_query('style((unknown))', false); + test_query('unknown((--foo: bar))', false); + + // "not" in <style-query>: + test_query('style(not (--foo: bar))', false); + test_query('style(not (--baz: qux))', true); + test_query('style(not (unknown))', false); + + // "and" in <style-query>: + test_query('style((--foo: bar) and (--foo: bar))', true); + test_query('style((--foo: bar) and (--foo: bar) and (--foo: bar))', true); + test_query('style((--baz: qux) and (--baz: qux))', false); + test_query('style((--baz: qux) and (--foo: bar) and (--foo: bar))', false); + test_query('style((--foo: bar) and (--baz: qux) and (--foo: bar))', false); + test_query('style((--foo: bar) and (--foo: bar) and (--baz: qux))', false); + test_query('style((unknown) and (--foo: bar) and (--foo: bar))', false); + test_query('style((--foo: bar) and (unknown) and (--foo: bar))', false); + test_query('style((--foo: bar) and (--foo: bar) and (unknown))', false); + + // "or" in <style-query>: + test_query('style((--foo: bar) or (--foo: bar))', true); + test_query('style((--foo: bar) or (--foo: bar) or (--foo: bar))', true); + test_query('style((--baz: qux) or (--baz: qux))', false); + test_query('style((--baz: qux) or (--foo: bar) or (--foo: bar))', true); + test_query('style((--foo: bar) or (--baz: qux) or (--foo: bar))', true); + test_query('style((--foo: bar) or (--foo: bar) or (--baz: qux))', true); + test_query('style((unknown) or (--foo: bar) or (--foo: bar))', true); + test_query('style((--foo: bar) or (unknown) or (--foo: bar))', true); + test_query('style((--foo: bar) or (--foo: bar) or (unknown))', true); + test_query('style((unknown) or (--baz: qux) or (--foo: bar))', true); + + // Combinations, <style-query>: + test_query('style(not ((--foo: bar) and (--foo: bar)))', false); + test_query('style(not ((--foo: bar) and (--baz: qux)))', true); + test_query('style((--foo: bar) and (not ((--baz: qux) or (--foo: bar))))', false); + test_query('style((--baz: qux) or (not ((--baz: qux) and (--foo: bar))))', true); + test_query('style((--baz: qux) or ((--baz: qux) and (--foo: bar)))', false); + +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/query-evaluation.html b/testing/web-platform/tests/css/css-contain/container-queries/query-evaluation.html new file mode 100644 index 0000000000..5b301f2d1d --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/query-evaluation.html @@ -0,0 +1,87 @@ +<!doctype html> +<title>Evaluation of queries</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-rule"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/cq-testcommon.js"></script> +<style> + #container { + width: 1px; + height: 0px; + container-type: size; + --applied:false; + } +</style> +<div id=container> + <div id=inner></div> +</div> +<script> + setup(() => assert_implements_container_queries()); + + function test_query(query, expected) { + test((t) => { + let style = document.createElement('style'); + t.add_cleanup(() => { style.remove(); }); + style.innerText = `@container ${query} { #inner { --applied:true; } }`; + let cs = getComputedStyle(inner); + assert_equals(cs.getPropertyValue('--applied'), 'false'); + document.head.append(style); + assert_equals(cs.getPropertyValue('--applied'), expected.toString()); + }, query); + }; + + // We don't care about specific features in this file, only higher level + // evaluation like "and", "or", and so forth. The features "width", "height" + // and "unknown" are arbitrarily chosen to represent true, false, and + // unknown values, respectively. + + test_query('(width)', true); + test_query('(height)', false); + test_query('(unknown)', false); + test_query('unknown(width)', false); + + // Nesting in <container-query>: + test_query('((width))', true); + test_query('((height))', false); + test_query('((unknown))', false); + test_query('((((width))))', true); + test_query('((((height))))', false); + test_query('((((unknown))))', false); + + // "not" in <container-query>: + test_query('(not (width))', false); + test_query('(not (height))', true); + test_query('(not (unknown))', false); + test_query('(not unknown(width))', false); + + // "and" in <container-query>: + test_query('((width) and (width))', true); + test_query('((width) and (width) and (width))', true); + test_query('((height) and (height))', false); + test_query('((height) and (width) and (width))', false); + test_query('((width) and (height) and (width))', false); + test_query('((width) and (width) and (height))', false); + test_query('((unknown) and (width) and (width))', false); + test_query('((width) and (unknown) and (width))', false); + test_query('((width) and (width) and (unknown))', false); + + // "or" in <container-query>: + test_query('((width) or (width))', true); + test_query('((width) or (width) or (width))', true); + test_query('((height) or (height))', false); + test_query('((height) or (width) or (width))', true); + test_query('((width) or (height) or (width))', true); + test_query('((width) or (width) or (height))', true); + test_query('((unknown) or (width) or (width))', true); + test_query('((width) or (unknown) or (width))', true); + test_query('((width) or (width) or (unknown))', true); + test_query('((unknown) or (height) or (width))', true); + + // Combinations, <container-query>: + test_query('(not ((width) and (width)))', false); + test_query('(not ((width) and (height)))', true); + test_query('((width) and (not ((height) or (width))))', false); + test_query('((height) or (not ((height) and (width))))', true); + test_query('((height) or ((height) and (width)))', false); + +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/reattach-container-with-dirty-child.html b/testing/web-platform/tests/css/css-contain/container-queries/reattach-container-with-dirty-child.html new file mode 100644 index 0000000000..680d9caa84 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/reattach-container-with-dirty-child.html @@ -0,0 +1,37 @@ +<!doctype html> +<title>CSS Container Queries Test: @container changing display type while descendant styles change</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#size-container"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/cq-testcommon.js"></script> +<style> + #container { + container-type: inline-size; + } + @container (min-width: 200px) { + div { color: red } + } + @container (max-width: 150px) { + div { color: lime } + } +</style> +<div id="container"> + <div id="child"><span id="inner">XXX</span></div> +</div> +<script> + setup(() => assert_implements_container_queries()); + + test(() => { + container.offsetTop; + assert_equals(getComputedStyle(child).color, "rgb(255, 0, 0)"); + }, "Initially wider than 200px"); + + test(() => { + container.style.width = "100px"; + container.style.display = "inline-block"; + inner.style.color = "green"; + container.offsetTop; + assert_equals(getComputedStyle(child).color, "rgb(0, 255, 0)"); + assert_equals(getComputedStyle(inner).color, "rgb(0, 128, 0)"); + }, "Container query changed and inner.style applied"); +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/resize-while-content-visibility-hidden-ref.html b/testing/web-platform/tests/css/css-contain/container-queries/resize-while-content-visibility-hidden-ref.html new file mode 100644 index 0000000000..2a87df85b7 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/resize-while-content-visibility-hidden-ref.html @@ -0,0 +1,3 @@ +<!doctype html> +<title>CSS Test Reference</title> +<div style="width:200px;height:200px;background:green"></div> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/resize-while-content-visibility-hidden.html b/testing/web-platform/tests/css/css-contain/container-queries/resize-while-content-visibility-hidden.html new file mode 100644 index 0000000000..a3658f7f34 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/resize-while-content-visibility-hidden.html @@ -0,0 +1,53 @@ +<!doctype html> +<html class="reftest-wait"> +<title>CSS Container Queries Test: condition change while content-visibility: hidden</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-queries"> +<link rel="help" href="https://drafts.csswg.org/css-contain-2/#content-visibility"> +<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org"> +<link rel="match" href="resize-while-content-visibility-hidden-ref.html"> +<link rel="assert" content="Container query applies even if container is content-visibility: hidden"> + +<script src="/common/reftest-wait.js"></script> + +<style> +#container { + container-name: container; + container-type: size; + width: 300px; + height: 300px; +} + +#child { + width: 200px; + height: 200px; + background: red; +} + +#container.wide { width: 500px; } +.locked { content-visibility: hidden; } + +@container container (min-width: 400px) { #child { background: green; } } +</style> + +<div id=container> + <div id=child></div> +</div> + +<script> +async function runTest() { + await new Promise(requestAnimationFrame); + container.classList.add("locked"); + + await new Promise(requestAnimationFrame); + container.classList.add("wide"); + + await new Promise(requestAnimationFrame); + container.classList.remove("locked"); + + await new Promise(requestAnimationFrame); + takeScreenshot(); +} + +requestAnimationFrame(() => { requestAnimationFrame(() => runTest()) }); + +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/sibling-layout-dependency.html b/testing/web-platform/tests/css/css-contain/container-queries/sibling-layout-dependency.html new file mode 100644 index 0000000000..5e30a998d2 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/sibling-layout-dependency.html @@ -0,0 +1,134 @@ +<!doctype html> +<title>@container-dependent styles respond to layout changes</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#size-container"> +<link rel="help" href="https://drafts.csswg.org/css-contain-2/#containment-size"> +<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" /> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/cq-testcommon.js"></script> +<script> + setup(() => assert_implements_container_queries()); +</script> +<style> + + @container (width: 10px) { .affected { --x:10; } } + @container (width: 20px) { .affected { --x:20; } } + + .flex { + display: flex; + height: 30px; + width: 30px; + } + + .container { + container-type: size; + flex: 1; + background: tomato; + } + + .sibling { + background-color: skyblue; + } + .w10 { + width: 10px; + } + .ahem { font: 5px Ahem; } + + /* The following is just to make the results more human-readable. */ + main { + display: flex; + flex-wrap: wrap; + } + +</style> + +<main> + <!-- A sibling of the container gets a layout-affecting style change --> + <div class=flex> + <div class=container> + <div> + <div> + <div class=affected id=target1></div> + </div> + </div> + </div> + <div class="sibling w10" id=sibling1></div> + </div> + <script> + test(function() { + let cs = getComputedStyle(target1); + assert_equals(cs.getPropertyValue('--x'), '20'); + + sibling1.style.width = '20px'; + assert_equals(cs.getPropertyValue('--x'), '10'); + }, 'Sibling style mutation'); + </script> + + <!-- A sibling of the container gets a layout-affecting style change + affecting the parent of the gCS target --> + <div class=flex> + <div class=container> + <div> + <div class=affected id=parent2> + <div id=target2></div> + </div> + </div> + </div> + <div class="sibling w10" id=sibling2></div> + </div> + <script> + test(function() { + let cs = getComputedStyle(target2); + assert_equals(cs.getPropertyValue('--x'), '20'); + + sibling2.style.width = '20px'; + assert_equals(cs.getPropertyValue('--x'), '10'); + }, 'Sibling style mutation, parent is affected'); + </script> + +<!-- A sibling of the container gets a layout-affecting style change + affecting an ancestor of the gCS target --> + <div class=flex> + <div class=container> + <div class=affected id=ancestor3> + <div> + <div id=target3></div> + </div> + </div> + </div> + <div class="sibling w10" id=sibling3></div> + </div> + <script> + test(function() { + let cs = getComputedStyle(target3); + assert_equals(cs.getPropertyValue('--x'), '20'); + + sibling3.style.width = '20px'; + assert_equals(cs.getPropertyValue('--x'), '10'); + }, 'Sibling style mutation, ancestor is affected'); + </script> + + <!-- A sibling of the container needs layout via text mutation --> + <div class=flex> + <div class=container> + <div> + <div> + <div class=affected id=target4></div> + </div> + </div> + </div> + <div class="sibling ahem" id=sibling4>XX</div> + </div> + <script> + promise_test(async function() { + await document.fonts.ready; + + let cs = getComputedStyle(target4); + assert_equals(cs.getPropertyValue('--x'), '20'); + + sibling4.textContent = 'XXXX'; + assert_equals(cs.getPropertyValue('--x'), '10'); + }, 'Sibling text mutation'); + </script> + +</main> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/size-container-no-principal-box.html b/testing/web-platform/tests/css/css-contain/container-queries/size-container-no-principal-box.html new file mode 100644 index 0000000000..4bff0681ab --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/size-container-no-principal-box.html @@ -0,0 +1,63 @@ +<!doctype html> +<title>CSS Container Queries Test: size container types apply to elements without a principal box</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#size-container"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/cq-testcommon.js"></script> +<style> + #outer { + container-type: inline-size; + } + #inner_none { + display: none; + container-type: inline-size; + } + #inner_contents { + display: contents; + container-type: inline-size; + } + @container (min-width: 0) { + span { color: red; } + } + @container (min-width: 0) { + #ref { color: green; } + } + @container not (max-width: 0) { + span { background-color: red; } + } + @container not (max-width: 0) { + #ref { background-color: green; } + } +</style> +<div id="outer"> + <div id="ref"></div> + <div id="inner_none"><span></span></div> + <div id="inner_contents"><span></span></div> +</div> +<script> + setup(() => assert_implements_container_queries()); + + test(() => { + assert_equals(getComputedStyle(ref).color, "rgb(0, 128, 0)"); + }, "(min-width: 0) can match a container with a principal box"); + + test(() => { + assert_equals(getComputedStyle(inner_none.firstChild).color, "rgb(0, 0, 0)"); + }, "(min-width: 0) does not match a container without a principal box (display:none)"); + + test(() => { + assert_equals(getComputedStyle(inner_contents.firstChild).color, "rgb(0, 0, 0)"); + }, "(min-width: 0) does not match a container without a principal box (display:contents)"); + + test(() => { + assert_equals(getComputedStyle(ref).backgroundColor, "rgb(0, 128, 0)"); + }, "not (max-width: 0) can match a container with a principal box"); + + test(() => { + assert_equals(getComputedStyle(inner_none.firstChild).backgroundColor, "rgba(0, 0, 0, 0)"); + }, "not (max-width: 0) does not match a container without a principal box (display:none)"); + + test(() => { + assert_equals(getComputedStyle(inner_contents.firstChild).backgroundColor, "rgba(0, 0, 0, 0)"); + }, "not (max-width: 0) does not match a container without a principal box (display:contents)"); +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/size-container-with-quotes-ref.html b/testing/web-platform/tests/css/css-contain/container-queries/size-container-with-quotes-ref.html new file mode 100644 index 0000000000..e1822fa544 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/size-container-with-quotes-ref.html @@ -0,0 +1,3 @@ +<!DOCTYPE html> +<title>CSS Test Reference</title> +<q style="display:block">This text must be quoted.</q> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/size-container-with-quotes.html b/testing/web-platform/tests/css/css-contain/container-queries/size-container-with-quotes.html new file mode 100644 index 0000000000..b88f882cd0 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/size-container-with-quotes.html @@ -0,0 +1,11 @@ +<!DOCTYPE html> +<title>CSS Container Queries Test: <q> element as a size container must generate quotes</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#size-container"> +<link rel="match" href="size-container-with-quotes-ref.html"> +<style> + q { + container-type: inline-size; + display: block; + } +</style> +<q>This text must be quoted.</q> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/size-feature-evaluation.html b/testing/web-platform/tests/css/css-contain/container-queries/size-feature-evaluation.html new file mode 100644 index 0000000000..600a266fce --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/size-feature-evaluation.html @@ -0,0 +1,91 @@ +<!doctype html> +<title>Evaluation of size features</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#size-container"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/cq-testcommon.js"></script> + +<div id=container> + <div id=target> + Test + </div> +</div> + +<script> +setup(() => assert_implements_container_queries()); + +function test_evaluation(container_class, query, expected) { + test(function(t) { + let style_node = document.createElement('style'); + t.add_cleanup(() => { + container.classList.remove(container_class); + style_node.remove(); + }); + style_node.innerText = `@container ${query} { #target { --applied:true; } }`; + + assert_equals(getComputedStyle(target).getPropertyValue('--applied'), ''); + container.classList.add(container_class); + document.head.append(style_node); + assert_equals(getComputedStyle(target).getPropertyValue('--applied'), expected ? 'true' : ''); + }, `${query} (.${container_class})`); +} + +</script> + +<style> + .horizontal { + width: 100px; + height: 200px; + container-type: size; + } + + .vertical { + width: 100px; + height: 200px; + container-type: size; + writing-mode: vertical-rl; + } +</style> +<script> + + for (let cls of ['horizontal', 'vertical']) { + + let logical_width = (cls == 'horizontal') ? 'inline' : 'block'; + let logical_height = (cls == 'horizontal') ? 'block' : 'inline'; + + test_evaluation(cls, '(width < 100px)', false); + test_evaluation(cls, '(width >= 100px)', true); + test_evaluation(cls, '(min-width: 100px)', true); + test_evaluation(cls, '(min-width: 101px)', false); + test_evaluation(cls, '(max-width: 100px)', true); + test_evaluation(cls, '(max-width: 99px)', false); + + test_evaluation(cls, '(height < 200px)', false); + test_evaluation(cls, '(height >= 200px)', true); + test_evaluation(cls, '(min-height: 200px)', true); + test_evaluation(cls, '(min-height: 201px)', false); + test_evaluation(cls, '(max-height: 200px)', true); + test_evaluation(cls, '(max-height: 199px)', false); + + test_evaluation(cls, `(${logical_width}-size < 100px)`, false); + test_evaluation(cls, `(${logical_width}-size >= 100px)`, true); + test_evaluation(cls, `(min-${logical_width}-size: 100px)`, true); + test_evaluation(cls, `(min-${logical_width}-size: 101px)`, false); + test_evaluation(cls, `(max-${logical_width}-size: 100px)`, true); + test_evaluation(cls, `(max-${logical_width}-size: 99px)`, false); + + test_evaluation(cls, `(${logical_height}-size < 200px)`, false); + test_evaluation(cls, `(${logical_height}-size >= 200px)`, true); + test_evaluation(cls, `(min-${logical_height}-size: 200px)`, true); + test_evaluation(cls, `(min-${logical_height}-size: 201px)`, false); + test_evaluation(cls, `(max-${logical_height}-size: 200px)`, true); + test_evaluation(cls, `(max-${logical_height}-size: 199px)`, false); + + test_evaluation(cls, '(orientation: landscape)', false); + test_evaluation(cls, '(orientation: portrait)', true); + + test_evaluation(cls, '(aspect-ratio: 1/2)', true); + test_evaluation(cls, '(aspect-ratio: 2/1)', false); + } + +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/style-change-in-container.html b/testing/web-platform/tests/css/css-contain/container-queries/style-change-in-container.html new file mode 100644 index 0000000000..ed4baa7e8b --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/style-change-in-container.html @@ -0,0 +1,30 @@ +<!doctype html> +<title>CSS Container Queries Test: recompute style inside a @container</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-queries"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/cq-testcommon.js"></script> +<style> + #container { container-type: size; } + @container (min-width: 1px) { + #content { color: green; } + } +</style> +<div id="container"> + <div id="content"></div> +</div> +<script> + setup(() => assert_implements_container_queries()); + + let content = document.getElementById("content"); + + test(() => { + assert_equals(getComputedStyle(content).color, "rgb(0, 128, 0)"); + + // Dirty style of an element inside the container: + content.style.backgroundColor = "lime"; + + // The container query should still evaluate correctly: + assert_equals(getComputedStyle(content).color, 'rgb(0, 128, 0)'); + }, "Basic test for container query evaluation stability"); +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/style-container-for-shadow-dom.html b/testing/web-platform/tests/css/css-contain/container-queries/style-container-for-shadow-dom.html new file mode 100644 index 0000000000..b8bea09750 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/style-container-for-shadow-dom.html @@ -0,0 +1,265 @@ +<!doctype html> +<meta charset="utf-8"> +<title>CSS Container Queries Test: style query container for Shadow DOM</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#query-container"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/declarative-shadow-dom-polyfill.js"></script> +<script src="support/cq-testcommon.js"></script> + +<div id="inclusive-ancestor-across-root"> + <div style="--foo: bar"> + <template shadowrootmode="open"> + <style> + @container style(--foo: bar) { + #t1 { color: green; } + } + </style> + <div id="t1"></div> + </template> + </div> +</div> + +<div id="inclusive-ancestor-skip-slotting"> + <div style="--foo: bar"> + <template shadowrootmode="open"> + <div style="--foo: baz"> + <slot></slot> + </div> + </template> + <style> + @container style(--foo: bar) { + #t2 { color: green; } + } + </style> + <div id="t2"></div> + </div> +</div> + +<div id="inclusive-ancestor-slotted"> + <div style="--foo: baz"> + <template shadowrootmode="open"> + <style> + @container style(--foo: bar) { + ::slotted(#t3) { color: green; } + } + </style> + <slot style="--foo: bar"></slot> + </template> + <div id="t3"></div> + </div> +</div> + +<div id="inclusive-ancestor-host" style="--foo: bar"> + <div id="t4"> + <template shadowrootmode="open"> + <style> + @container style(--foo: bar) { + :host(#t4) { color: green; } + } + </style> + </template> + </div> +</div> + +<div id="inclusive-ancestor-part"> + <div style="--foo: bar"> + <template shadowrootmode="open"> + <div style="--foo: baz"> + <span id="t5" part="part"></span> + </div> + </template> + <style> + @container style(--foo: bar) { + #inclusive-ancestor-part > div::part(part) { color: green; } + } + </style> + </div> +</div> + +<div id="inclusive-ancestor-slotted-before"> + <div> + <template shadowrootmode="open"> + <style> + @container style(--foo: bar) { + ::slotted(#t6)::before { + content: "X"; + color: green; + } + } + </style> + <slot style="--foo: bar"></slot> + </template> + <div id="t6" style="--foo: baz"></div> + </div> +</div> + +<div id="inclusive-ancestor-host-before"> + <div id="t7" style="--foo: bar"> + <template shadowrootmode="open"> + <style> + @container style(--foo: bar) { + :host(#t7)::before { + content: "X"; + color: green; + } + } + </style> + </template> + </div> +</div> + +<div id="inclusive-ancestor-part-before"> + <style> + @container style(--foo: bar) { + #inclusive-ancestor-part-before > div::part(part)::before { + content: "X"; + color: green; + } + } + </style> + <div style="--foo: bar"> + <template shadowrootmode="open"> + <div style="--foo: baz"> + <span id="t8" part="part"></span> + </div> + </template> + </div> +</div> + +<div id="inclusive-ancestor-inner-part"> + <style> + @container style(--foo: bar) { + #inclusive-ancestor-inner-part > div::part(inner-part) { color: green; } + } + </style> + <div style="--foo: bar"> + <template shadowrootmode="open"> + <div exportparts="inner-part" style="-foo: baz"> + <template shadowrootmode="open"> + <div style="--foo: baz"> + <span id="t9" part="inner-part"></span> + </div> + </template> + </div> + </template> + </div> +</div> + +<div id="inclusive-ancestor-slot-fallback"> + <div><template shadowrootmode="open"> + <style> + @container style(--foo: bar) { + #t10 { color: green; } + } + </style> + <div> + <slot style="--foo: bar"><span id="t10"></span></slot> + </div> + </template></div> +</div> + +<div id="no-container-for-part"> + <div> + <template shadowrootmode="open"> + <style> + #t11 { color: green; } + </style> + <div style="--foo: bar"> + <span id="t11" part="part"></span> + </div> + </template> + <style> + @container style(--foo: bar) { + #no-container-for-part > div::part(part) { color: red; } + } + </style> + </div> +</div> + +<div id="inner-scope-host-part" style="--foo: bar"> + <div> + <template shadowrootmode="open"> + <style> + @container style(--foo: bar) { + :host::part(part) { color: green; } + } + </style> + <div style="--foo: baz"> + <span id="t12" part="part"></span> + </div> + </template> + </div> +</div> + +<script> + setup(() => { + assert_implements_container_queries(); + polyfill_declarative_shadow_dom(document); + }); + + const green = "rgb(0, 128, 0)"; + + test(() => { + const t1 = document.querySelector("#inclusive-ancestor-across-root > div").shadowRoot.querySelector("#t1"); + assert_equals(getComputedStyle(t1).color, green); + }, "Match container in outer tree"); + + test(() => { + const t2 = document.querySelector("#t2"); + assert_equals(getComputedStyle(t2).color, green); + }, "Match container in same tree, not walking flat tree ancestors"); + + test(() => { + const t3 = document.querySelector("#t3"); + assert_equals(getComputedStyle(t3).color, green); + }, "Match container in ::slotted selector's originating element tree"); + + test(() => { + const t4 = document.querySelector("#t4"); + assert_equals(getComputedStyle(t4).color, green); + }, "Match container in outer tree for :host"); + + test(() => { + const t5 = document.querySelector("#inclusive-ancestor-part > div").shadowRoot.querySelector("#t5"); + assert_equals(getComputedStyle(t5).color, green); + }, "Match container in ::part selector's originating element tree"); + + test(() => { + const t6 = document.querySelector("#t6"); + assert_equals(getComputedStyle(t6, "::before").color, green); + }, "Match container for ::before in ::slotted selector's originating element tree"); + + test(() => { + const t7 = document.querySelector("#t7"); + assert_equals(getComputedStyle(t7, "::before").color, green); + }, "Match container in outer tree for :host::before"); + + test(() => { + const t8 = document.querySelector("#inclusive-ancestor-part-before > div").shadowRoot.querySelector("#t8"); + assert_equals(getComputedStyle(t8, "::before").color, green); + }, "Match container for ::before in ::part selector's originating element tree"); + + test(() => { + const outerhost = document.querySelector("#inclusive-ancestor-inner-part > div"); + const innerhost = outerhost.shadowRoot.querySelector("div"); + const t9 = innerhost.shadowRoot.querySelector("#t9"); + assert_equals(getComputedStyle(t9).color, green); + }, "Match container for ::part selector's originating element tree for exportparts"); + + test(() => { + const t10 = document.querySelector("#inclusive-ancestor-slot-fallback > div").shadowRoot.querySelector("#t10"); + assert_equals(getComputedStyle(t10).color, green); + }, "Match container for slot light tree child fallback"); + + test(() => { + const t11 = document.querySelector("#no-container-for-part > div").shadowRoot.querySelector("#t11"); + assert_equals(getComputedStyle(t11).color, green); + }, "Should not match container inside shadow tree for ::part()"); + + test(() => { + const t12 = document.querySelector("#inner-scope-host-part > div").shadowRoot.querySelector("#t12"); + assert_equals(getComputedStyle(t12).color, green); + }, "A :host::part rule should match containers in the originating element tree"); + +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/style-not-sharing-float.html b/testing/web-platform/tests/css/css-contain/container-queries/style-not-sharing-float.html new file mode 100644 index 0000000000..7c76bb32bf --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/style-not-sharing-float.html @@ -0,0 +1,40 @@ +<!doctype html> +<title>CSS Container Queries Test: Check style is not sharing between cousins in the case of Container Queries</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#size-container"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/cq-testcommon.js"></script> +<style> + .float { + float: left; + width: 25px; + height: 25px; + } + .item { + container-type: inline-size; + height: 25px; + } + @container (width >= 50px) { + .item div { color: lime; } + } + @container (width >= 150px) { + .item div { color: green; } + } +</style> +<div style="width: 150px"> + <div class="float"></div> + <div class="item"> + <div id="target1"></div> + </div> + <div class="item"> + <div id="target2"></div> + </div> +</div> +<script> + setup(() => assert_implements_container_queries()); + + test(() => { + assert_equals(getComputedStyle(target1).color, "rgb(0, 255, 0)", "Second item container should be 100px wide"); + assert_equals(getComputedStyle(target2).color, "rgb(0, 128, 0)", "First item container should be 200px wide"); + }, "Check that style is not sharing in the case of Container Queries"); +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/support/cq-testcommon.js b/testing/web-platform/tests/css/css-contain/container-queries/support/cq-testcommon.js new file mode 100644 index 0000000000..2eaca1dd09 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/support/cq-testcommon.js @@ -0,0 +1,3 @@ +function assert_implements_container_queries() { + assert_implements(CSS.supports("container-type:size"), "Basic support for container queries required"); +} diff --git a/testing/web-platform/tests/css/css-contain/container-queries/support/test.vtt b/testing/web-platform/tests/css/css-contain/container-queries/support/test.vtt new file mode 100644 index 0000000000..ffd1d4ca44 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/support/test.vtt @@ -0,0 +1,4 @@ +WEBVTT + +00:00:00.000 --> 00:00:10.000 +Sub-<b>title</b> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/svg-foreignobject-child-container.html b/testing/web-platform/tests/css/css-contain/container-queries/svg-foreignobject-child-container.html new file mode 100644 index 0000000000..898fc22c2b --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/svg-foreignobject-child-container.html @@ -0,0 +1,38 @@ +<!doctype html> +<title>CSS Container Queries Test: size query container inside foreignObject</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#size-container"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/cq-testcommon.js"></script> +<style> + svg { + display: block; + width: 200px; + height: 200px; + container-type: size; + } + #container { + width: 100px; + height: 100px; + container-type: size; + } + @container (width = 100px) { + #inner { color: green; } + } +</style> +<svg> + <foreignObject> + <div id="container"> + <div id="inner">Green</div> + </div> + </foreignObject> +</svg> +<script> + setup(() => assert_implements_container_queries()); + + const green = "rgb(0, 128, 0)"; + + test(() => { + assert_equals(getComputedStyle(inner).color, green); + }, "#inner querying #container inside foreignObject"); +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/svg-foreignobject-no-size-container-ref.html b/testing/web-platform/tests/css/css-contain/container-queries/svg-foreignobject-no-size-container-ref.html new file mode 100644 index 0000000000..abf1af122b --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/svg-foreignobject-no-size-container-ref.html @@ -0,0 +1,4 @@ +<!doctype html> +<title>CSS Test Reference</title> +<p>You should see the word PASS below and no red.</p> +<svg><foreignObject style="width:100px;height:100px;"><div>PASS</div><foreignObject></svg> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/svg-foreignobject-no-size-container.html b/testing/web-platform/tests/css/css-contain/container-queries/svg-foreignobject-no-size-container.html new file mode 100644 index 0000000000..38fc493a16 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/svg-foreignobject-no-size-container.html @@ -0,0 +1,24 @@ +<!doctype html> +<title>CSS Container Queries Test: SVG <foreignObject> element not a size query container</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#size-container"> +<link rel="match" href="svg-foreignobject-no-size-container-ref.html"> +<style> + foreignObject { + display: block; + width: 100px; + height: 100px; + container-type: size; + } + @supports not (container-type: size) { + div { color: red; } + } + @container (width = 100px) { + div { color: red; } + } +</style> +<p>You should see the word PASS below and no red.</p> +<svg> + <foreignObject> + <div id="div">PASS</div> + </foreignObject> +</svg> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/svg-g-no-size-container-ref.html b/testing/web-platform/tests/css/css-contain/container-queries/svg-g-no-size-container-ref.html new file mode 100644 index 0000000000..4f30c39939 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/svg-g-no-size-container-ref.html @@ -0,0 +1,4 @@ +<!doctype html> +<title>CSS Test Reference</title> +<p>You should see the word PASS below and no red.</p> +<svg><text x="0" y="20" id="text">PASS</text></svg> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/svg-g-no-size-container.html b/testing/web-platform/tests/css/css-contain/container-queries/svg-g-no-size-container.html new file mode 100644 index 0000000000..ed9e853676 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/svg-g-no-size-container.html @@ -0,0 +1,23 @@ +<!doctype html> +<title>CSS Container Queries Test: SVG <g> element not a size query container</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#size-container"> +<link rel="match" href="svg-g-no-size-container-ref.html"> +<style> + g { + display: block; + width: 100px; + height: 100px; + container-type: size; + } + + @supports not (container-type: size) { + text { fill: red; } + } + @container (width = 100px) { + text { fill: red; } + } +</style> +<p>You should see the word PASS below and no red.</p> +<svg> + <g><text x="0" y="20" id="text">PASS</text></g> +</svg> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/svg-root-size-container.html b/testing/web-platform/tests/css/css-contain/container-queries/svg-root-size-container.html new file mode 100644 index 0000000000..70ce40c0bc --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/svg-root-size-container.html @@ -0,0 +1,36 @@ +<!doctype html> +<title>CSS Container Queries Test: SVG root as a size query container</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#size-container"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/cq-testcommon.js"></script> +<style> + svg { + display: block; + width: 100px; + height: 100px; + container-type: size; + } + @container (width = 100px) { + #div, #text { color: green; } + } +</style> +<svg> + <text id="text">Green</text> + <foreignObject> + <div id="div">Green</div> + </foreignObject> +</svg> +<script> + setup(() => assert_implements_container_queries()); + + const green = "rgb(0, 128, 0)"; + + test(() => { + assert_equals(getComputedStyle(text).color, green); + }, "SVG text querying SVG root size container"); + + test(() => { + assert_equals(getComputedStyle(div).color, green); + }, "div in foreignObject querying SVG root size container"); +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/table-inside-container-changing-display-ref.html b/testing/web-platform/tests/css/css-contain/container-queries/table-inside-container-changing-display-ref.html new file mode 100644 index 0000000000..c0355d2f50 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/table-inside-container-changing-display-ref.html @@ -0,0 +1,4 @@ +<!doctype html> +<title>CSS Test Reference</title> +<p>You should see the word PASS below.</p> +<table><td>PASS</td></table> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/table-inside-container-changing-display.html b/testing/web-platform/tests/css/css-contain/container-queries/table-inside-container-changing-display.html new file mode 100644 index 0000000000..33a4f4fe72 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/table-inside-container-changing-display.html @@ -0,0 +1,26 @@ +<!doctype html> +<title>CSS Container Queries Test: table inside @container changing display type</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-queries"> +<link rel="help" href="https://crbug.com/1284918"> +<link rel="match" href="table-inside-container-changing-display-ref.html"> +<style> + @supports not (container-type: inline-size) { + #container { display: none !important; } + } + #container { + width: 200px; + height: 200px; + container-type: inline-size; + } +</style> +<p>You should see the word PASS below.</p> +<div id="container"> + <div> + <table><td>PASS</td></table> + </div> +</div> +<script> + document.body.offsetTop; + document.querySelector("#container").style.display = "inline-block"; + document.querySelector("table").style.color = "currentColor"; +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/top-layer-dialog-backdrop-ref.html b/testing/web-platform/tests/css/css-contain/container-queries/top-layer-dialog-backdrop-ref.html new file mode 100644 index 0000000000..49c46974c9 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/top-layer-dialog-backdrop-ref.html @@ -0,0 +1,3 @@ +<!doctype html> +<html style="background:green"> +<title>CSS Test Reference</title> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/top-layer-dialog-backdrop.html b/testing/web-platform/tests/css/css-contain/container-queries/top-layer-dialog-backdrop.html new file mode 100644 index 0000000000..25635167a5 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/top-layer-dialog-backdrop.html @@ -0,0 +1,20 @@ +<!doctype html> +<title>CSS Container Queries Test: ::backdrop depending on @container</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-queries"> +<link rel="match" href="top-layer-dialog-backdrop-ref.html"> +<style> + html { background: green; } + #container { container-type: inline-size; } + @container (max-width: 200px) { + ::backdrop { display: none; } + #dialog { visibility: hidden; } + } +</style> +<div id="container"> + <dialog id="dialog"></dialog> +</div> +<script> + dialog.showModal(); + dialog.offsetTop; + container.style.width = "100px"; +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/top-layer-dialog-container.html b/testing/web-platform/tests/css/css-contain/container-queries/top-layer-dialog-container.html new file mode 100644 index 0000000000..5627a6cea0 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/top-layer-dialog-container.html @@ -0,0 +1,33 @@ +<!doctype html> +<title>CSS Container Queries Test: Top layer element as a @container</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-queries"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/cq-testcommon.js"></script> +<style> + #parent { width: 100px; } + #dialog { + container-type: inline-size; + width: auto; + border: none; + } + #child { color: red; } + @container (min-width: 200px) { + #child { color: green; } + } +</style> +<div id="parent"> + <dialog id="dialog"><span id="child"></span></dialog> +</div> +<script> + setup(() => assert_implements_container_queries()); + + test(() => { + assert_equals(getComputedStyle(child).color, "rgb(255, 0, 0)"); + }, "#dialog initially sized by #containing-block"); + + test(() => { + dialog.showModal(); + assert_equals(getComputedStyle(child).color, "rgb(0, 128, 0)"); + }, "#dialog sized by viewport"); +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/top-layer-dialog.html b/testing/web-platform/tests/css/css-contain/container-queries/top-layer-dialog.html new file mode 100644 index 0000000000..9d18b1862d --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/top-layer-dialog.html @@ -0,0 +1,45 @@ +<!doctype html> +<title>CSS Container Queries Test: @container with modal dialog child</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-queries"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/cq-testcommon.js"></script> +<style> + #container { + container-type: inline-size; + } + dialog { + color: red; + } + @container (max-width: 200px) { + dialog { color: green; } + } + @container (max-width: 100px) { + dialog { color: lime; } + } +</style> +<div id="container"> + <dialog id="dialog"></dialog> +</div> +<script> + setup(() => assert_implements_container_queries()); + + test(() => { + assert_equals(getComputedStyle(dialog).color, "rgb(255, 0, 0)"); + }, "#container initially wider than 200px"); + + test(() => { + container.style.width = "200px"; + assert_equals(getComputedStyle(dialog).color, "rgb(0, 128, 0)"); + }, "#container changed to 200px"); + + test(() => { + dialog.showModal(); + assert_equals(getComputedStyle(dialog).color, "rgb(0, 128, 0)"); + }, "Modal dialog still has parent as query container while in top layer"); + + test(() => { + container.style.width = "100px"; + assert_equals(getComputedStyle(dialog).color, "rgb(0, 255, 0)"); + }, "Container changes width while dialog is in top layer"); +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/top-layer-nested-dialog.html b/testing/web-platform/tests/css/css-contain/container-queries/top-layer-nested-dialog.html new file mode 100644 index 0000000000..1a6d573f24 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/top-layer-nested-dialog.html @@ -0,0 +1,45 @@ +<!doctype html> +<title>CSS Container Queries Test: Nested top layer elements and @container</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-queries"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/cq-testcommon.js"></script> +<style> + dialog { color: red; } + #container { width: 100px; } + #container, #outer { container-type: inline-size; } + @container (min-width: 200px) { + #outer { width: 400px; color: lime; } + } + @container (min-width: 400px) { + #inner { color: green; } + } +</style> +<div id="container"> + <dialog id="outer"> + <dialog id="inner"></dialog> + </dialog> +</div> +<script> + setup(() => assert_implements_container_queries()); + + test(() => { + assert_equals(getComputedStyle(outer).color, "rgb(255, 0, 0)"); + assert_equals(getComputedStyle(inner).color, "rgb(255, 0, 0)"); + }, "Dialogs initially not matching for container queries"); + + test(() => { + container.offsetTop; + outer.showModal(); + inner.showModal(); + assert_equals(getComputedStyle(outer).color, "rgb(255, 0, 0)"); + assert_equals(getComputedStyle(inner).color, "rgb(255, 0, 0)"); + }, "Dialogs still not matching after showModal"); + + test(() => { + container.offsetTop; + container.style.width = "200px"; + assert_equals(getComputedStyle(outer).color, "rgb(0, 255, 0)"); + assert_equals(getComputedStyle(inner).color, "rgb(0, 128, 0)"); + }, "@container queries start matching"); +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/transition-scrollbars.html b/testing/web-platform/tests/css/css-contain/container-queries/transition-scrollbars.html new file mode 100644 index 0000000000..60d82d26b4 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/transition-scrollbars.html @@ -0,0 +1,59 @@ +<!doctype html> +<title>Container Queries - Scrollbars do not cause transitions</title> +<link rel="help" href="https://drafts.csswg.org/css-transitions/#starting"> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#animated-containers"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/cq-testcommon.js"></script> +<style> + #scrollable { + overflow: auto; + width: 100px; + height: 100px; + } + #container { + container-type: inline-size; + } + #target { + background-color: black; + } + + /* Matches with or without a scrollbar: */ + @container (max-width: 100px) { + #target { + background-color: blue; + } + } + + /* Matches only when there's a scrollbar: */ + @container (max-width: 99px) { + #target { + background-color: green; + font-size: 10px; + transition: 2s steps(2, start) background-color; + } + } +</style> +<div id=scrollable> + <div id=container> + <div id=target> + Foo bar foo bar foo + Foo bar foo bar foo + Foo bar foo bar foo + Foo bar foo bar foo + Foo bar foo bar foo + </div> + </div> +</div> +<script> + setup(() => assert_implements_container_queries()); + + test(() => { + // Whether or not a scrollbar appeared is out of scope for this test. + // The only thing we care about is that no transition was triggered. + // Therefore we allow both 'green' and 'blue', but not any other values. + let has_scrollbar = target.offsetWidth < 100; + let expected = has_scrollbar ? 'rgb(0, 128, 0)' : 'rgb(0, 0, 255)'; + assert_equals(getComputedStyle(target).backgroundColor, expected); + }, 'Scrollbars do not cause a transition of background-color'); +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/transition-style-change-event-002.html b/testing/web-platform/tests/css/css-contain/container-queries/transition-style-change-event-002.html new file mode 100644 index 0000000000..dc9297004d --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/transition-style-change-event-002.html @@ -0,0 +1,45 @@ +<!doctype html> +<meta charset="utf-8"> +<title>Container Queries - Style Change Event for transitions</title> +<link rel="help" href="https://drafts.csswg.org/css-transitions/#starting"> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#animated-containers"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/cq-testcommon.js"></script> +<style> + .container { + container-type: inline-size; + } + #outer { + width: 100px; + color: green; + } + #target { + transition: color 100s step-end; + } + + @container (min-width: 200px) { + #inner { color: red; } + } + @container (min-width: 200px) { + #target { + /* This rule exists just to have a container query dependency between + target and #inner */ + background-color: orange; + } + } +</style> +<div id="outer" class="container"> + <div id="inner" class="container"> + <div id="target">Green</div> + </div> +</div> +<script> + setup(() => assert_implements_container_queries()); + + test(() => { + outer.offsetTop; + outer.style.width = "200px"; + assert_equals(getComputedStyle(target).color, "rgb(0, 128, 0)"); + }, "#inner color change to red triggers a step transition starting at green"); +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/transition-style-change-event.html b/testing/web-platform/tests/css/css-contain/container-queries/transition-style-change-event.html new file mode 100644 index 0000000000..4cc1772979 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/transition-style-change-event.html @@ -0,0 +1,58 @@ +<!doctype html> +<meta charset="utf-8"> +<title>Container Queries - Style Change Event for transitions</title> +<link rel="help" href="https://drafts.csswg.org/css-transitions/#starting"> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#animated-containers"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/cq-testcommon.js"></script> +<style> + .container { container-type: size } + #outer { + width: 100px; + color: green; + } + @container (min-width: 200px) { + #inner { color: red } + } + @container (min-width: 400px) { + #target { + color: green; + transition: color 1s step-start; + } + } +</style> +<div id="outer" class="container"> + <div id="inner" class="container"> + <div id="target">Green</div> + </div> +</div> +</div> +<script> + setup(() => assert_implements_container_queries()); + + const t = async_test(""); + const event_handler = t.step_func_done((e) => { + assert_unreached("Transition event incorrectly triggered: " + e.type); + }); + for (let event_name of ["transitionrun", + "transitionstart", + "transitionend", + "transitioncancel"]) { + target.addEventListener(event_name, event_handler); + } + + outer.offsetTop; + // #target is green. Making the #outer container 200px will turn #inner and + // #target red through inheritance. + outer.style.width = "200px"; + // Making #inner 400px will make #target green. + inner.style.width = "400px"; + // Both changes above should happen in one style change event and should not + // trigger any transition events. Run two rAFs to make sure any events have + // time to trigger. + requestAnimationFrame(() => requestAnimationFrame(t.step_func_done(() => { + assert_equals(getComputedStyle(inner).color, "rgb(255, 0, 0)", + "@container queries supported"); + }))); +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/unsupported-axis.html b/testing/web-platform/tests/css/css-contain/container-queries/unsupported-axis.html new file mode 100644 index 0000000000..308de2f424 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/unsupported-axis.html @@ -0,0 +1,228 @@ +<!doctype html> +<title>Query against unsupported axis</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#size-container"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/cq-testcommon.js"></script> +<script> + setup(() => assert_implements_container_queries()); +</script> + +<style> + #container { + width: 200px; + height: 100px; + container-type: inline-size; + } +</style> + +<div id=container> + <div id=target> + Test + </div> +</div> + + +<style> + @container (width > 0px) { + #target { --width:true; } + } +</style> +<script> + test(function(t) { + assert_equals(getComputedStyle(target).getPropertyValue('--width'), 'true'); + }, '(width > 0px)'); +</script> + + +<style> + @container (height > 0px) { + #target { --height:true; } + } +</style> +<script> + test(function(t) { + // container-type:inline-size does not support queries along the block + // axis. + assert_equals(getComputedStyle(target).getPropertyValue('--height'), ''); + }, '(height > 0px)'); +</script> + + +<style> + @container ((height > 0px) or (width > 0px)) { + #target { --height-or-width:true; } + } +</style> +<script> + test(function(t) { + // (height > 0px) requires container-type:size. + assert_equals(getComputedStyle(target).getPropertyValue('--height-or-width'), ''); + }, '((height > 0px) or (width > 0px))'); +</script> + + +<style> + @container ((width > 0px) or (height > 0px)) { + #target { --width-or-height:true; } + } +</style> +<script> + test(function(t) { + // (height > 0px) requires container-type:size. + assert_equals(getComputedStyle(target).getPropertyValue('--width-or-height'), ''); + }, '((width > 0px) or (height > 0px))'); +</script> + +<style> + @container ((orientation: landscape) or (width > 0px)) { + #target { --orientation-or-width:true; } + } +</style> +<script> + test(function(t) { + // (orientation: landscape) requires container-type:size. + assert_equals(getComputedStyle(target).getPropertyValue('--orientation-or-width'), ''); + }, '((orientation: landscape) or (width > 0px))'); +</script> + + +<style> + @container ((width > 0px) or (orientation: landscape)) { + #target { --width-or-orientation:true; } + } +</style> +<script> + test(function(t) { + // (orientation: landscape) requires container-type:size. + assert_equals(getComputedStyle(target).getPropertyValue('--width-or-orientation'), ''); + }, '((width > 0px) or (orientation: landscape))'); +</script> + + +<style> + @container ((height > 0px) or (orientation: landscape)) { + #target { --height-or-orientation:true; } + } +</style> +<script> + test(function(t) { + assert_equals(getComputedStyle(target).getPropertyValue('--height-or-orientation'), ''); + }, '((height > 0px) or (orientation: landscape))'); +</script> + + +<style> + @container ((height > 0px) or (orientation: landscape)) { + #target { --height-or-orientation2:true; } + } +</style> +<script> + test(function(t) { + // Adding full size containment via the 'contain' property does not + // make 'height' queryable. (Limited by container-type:inline-size). + t.add_cleanup(() => { target.style = ''; }); + target.style.contain = 'size'; + assert_equals(getComputedStyle(target).getPropertyValue('--height-or-orientation2'), ''); + }, '((height > 0px) or (orientation: landscape)), with contain:size'); +</script> + + +<style> + @container (inline-size > 0px) { + #target { --inline-size:true; } + } +</style> +<script> + test(function(t) { + assert_equals(getComputedStyle(target).getPropertyValue('--inline-size'), 'true'); + }, '(inline-size > 0px)'); +</script> + + +<style> + @container (block-size > 0px) { + #target { --block-size:true; } + } +</style> +<script> + test(function(t) { + // container-type:inline-size does not support queries along the block + // axis. + assert_equals(getComputedStyle(target).getPropertyValue('--block-size'), ''); + }, '(block-size > 0px)'); +</script> + + +<style> + @container (block-size > 0px) { + #target { --block-size2:true; } + } +</style> +<script> + test(function(t) { + // Changing the writing-mode does not affect the evaluation of block-size. + t.add_cleanup(() => { target.style = ''; }); + target.style.writingMode = 'vertical-rl'; + assert_equals(getComputedStyle(target).getPropertyValue('--block-size2'), ''); + }, '(block-size > 0px), with writing-mode:vertical-rl'); +</script> + + +<style> + @container not (width < 0px) { + #target { --not-width:true; } + } +</style> +<script> + test(function(t) { + assert_equals(getComputedStyle(target).getPropertyValue('--not-width'), 'true'); + }, 'not (width < 0px)'); +</script> + + +<style> + @container not (height < 0px) { + #target { --not-height:true; } + } +</style> +<script> + test(function(t) { + assert_equals(getComputedStyle(target).getPropertyValue('--not-height'), ''); + }, 'not (height < 0px)'); +</script> + + +<style> + @container not (inline-size < 0px) { + #target { --not-inline-size:true; } + } +</style> +<script> + test(function(t) { + assert_equals(getComputedStyle(target).getPropertyValue('--not-inline-size'), 'true'); + }, 'not (inline-size < 0px)'); +</script> + + +<style> + @container not (block-size < 0px) { + #target { --not-block-size:true; } + } +</style> +<script> + test(function(t) { + assert_equals(getComputedStyle(target).getPropertyValue('--not-block-size'), ''); + }, 'not (block-size < 0px)'); +</script> + +<style> + @container not (orientation) { + #target { --not-orientation:true; } + } +</style> +<script> + test(function(t) { + assert_equals(getComputedStyle(target).getPropertyValue('--not-orientation'), ''); + }, 'not (orientation)'); +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/viewport-units-dynamic.html b/testing/web-platform/tests/css/css-contain/container-queries/viewport-units-dynamic.html new file mode 100644 index 0000000000..2339533dee --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/viewport-units-dynamic.html @@ -0,0 +1,59 @@ +<!doctype html> +<title>CSS Container Queries Test: @container-dependent elements respond to viewport unit changes</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#size-container"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/cq-testcommon.js"></script> +<style> + iframe { + width: 100px; + height: 100px; + } +</style> +<iframe id="iframe" srcdoc=" + <style> + #vw, #vh { + container-type: inline-size; + width: 100px; + } + + @container (min-width: 50vw) { + #vw span { color: green } + } + @container (min-width: 100vw) { + #vw span { color: red } + } + @container (min-width: 50vh) { + #vh span { color: green } + } + @container (min-width: 100vh) { + #vh span { color: red } + } + </style> + <div id=vw><span>Green</span></div> + <div id=vh><span>Green</span></div> +"></iframe> +<script> + setup(() => assert_implements_container_queries()); + + function waitForLoad(w) { + return new Promise(resolve => w.addEventListener('load', resolve)); + } + + promise_test(async () => { + await waitForLoad(window); + const vw_child = iframe.contentDocument.querySelector("#vw > span"); + const vh_child = iframe.contentDocument.querySelector("#vh > span"); + + assert_equals(getComputedStyle(vw_child).color, "rgb(255, 0, 0)", "vw before resize"); + assert_equals(getComputedStyle(vh_child).color, "rgb(255, 0, 0)", "vh before resize"); + + iframe.style.width = "200px"; + assert_equals(getComputedStyle(vw_child).color, "rgb(0, 128, 0)", "vw after width resize"); + assert_equals(getComputedStyle(vh_child).color, "rgb(255, 0, 0)", "vh after width resize"); + + iframe.style.height = "200px"; + assert_equals(getComputedStyle(vw_child).color, "rgb(0, 128, 0)", "vw after height resize"); + assert_equals(getComputedStyle(vh_child).color, "rgb(0, 128, 0)", "vh after height resize"); + }); +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/viewport-units.html b/testing/web-platform/tests/css/css-contain/container-queries/viewport-units.html new file mode 100644 index 0000000000..9b8bb42c43 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/viewport-units.html @@ -0,0 +1,33 @@ +<!doctype html> +<title>CSS Container Queries Test: viewport units</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#size-container"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/cq-testcommon.js"></script> +<style> + #vw { container-type: inline-size; width: 10vw; } + #vh { container-type: inline-size; width: 10vh; } + + @container (min-width: 10vw) { + #vw span { color: green } + } + @container (min-width: 11vw) { + #vw span { color: red } + } + @container (min-width: 10vh) { + #vh span { color: green } + } + @container (min-width: 11vh) { + #vh span { color: red } + } +</style> +<div id="vw"><span>Green</span></div> +<div id="vh"><span>Green</span></div> +<script> + setup(() => assert_implements_container_queries()); + + const green = "rgb(0, 128, 0)"; + + test(() => assert_equals(getComputedStyle(vw.firstChild).color, green), "Match width with vw"); + test(() => assert_equals(getComputedStyle(vh.firstChild).color, green), "Match width with vh"); +</script> diff --git a/testing/web-platform/tests/css/css-contain/container-queries/whitespace-update-after-removal.html b/testing/web-platform/tests/css/css-contain/container-queries/whitespace-update-after-removal.html new file mode 100644 index 0000000000..a7df55efc6 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/container-queries/whitespace-update-after-removal.html @@ -0,0 +1,26 @@ +<!doctype html> +<title>CSS Container Queries Test: whitespace changes in container which changes evaluation</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-queries"> +<link rel="match" href="change-display-in-container-ref.html"> +<style> + #container { + container-type: size; + width: 400px; + height: 200px; + } + + @container (min-width: 400px) { + span { color: red; } + } +</style> +<p>You should see the word PASS below.</p> +<div id="container"><span id="fail">FAIL</span> <span>PASS</span></div> +<script> + if (CSS.supports("container-type:size")) { + container.offsetTop; + container.style.width = "200px"; + // The space text node between the two spans no longer takes up space when the + // first span is removed. + fail.remove(); + } +</script> |