| <!DOCTYPE html> | |
| <title>@scope - implicit scope root in constructed stylesheet adopted by a document</title> | |
| <link rel="help" href="https://drafts.csswg.org/css-cascade-6/#scope-limits"> | |
| <link rel="help" href="https://drafts.csswg.org/css-cascade-6/#scoped-rules"> | |
| <link rel="help" href="https://drafts.csswg.org/cssom/#extensions-to-the-document-or-shadow-root-interface"> | |
| <script src="/resources/testharness.js"></script> | |
| <script src="/resources/testharnessreport.js"></script> | |
| <div id="outer" class="b"> | |
| <div id="inner" class="a"></div> | |
| <div class="limit"> | |
| <div id="limited" class="a"></div> | |
| </div> | |
| </div> | |
| <script> | |
| function adopt(t, text) { | |
| const sheet = new CSSStyleSheet(); | |
| sheet.replaceSync(text); | |
| document.adoptedStyleSheets = [sheet]; | |
| t.add_cleanup(() => { document.adoptedStyleSheets = []; }); | |
| return sheet; | |
| } | |
| function createShadowRoot(t) { | |
| const host = document.createElement("div"); | |
| document.body.append(host); | |
| t.add_cleanup(() => host.remove()); | |
| const root = host.attachShadow({ mode: "open" }); | |
| root.innerHTML = `<div class="a"></div>`; | |
| return root; | |
| } | |
| const zIndex = element => getComputedStyle(element).zIndex; | |
| test(t => { | |
| adopt(t, `@scope { .a { z-index: 1; } }`); | |
| assert_equals(zIndex(inner), "1"); | |
| }, "Implicit @scope in a constructed stylesheet adopted by a document matches descendants"); | |
| test(t => { | |
| adopt(t, `@scope { html { z-index: 1; } }`); | |
| assert_equals(zIndex(document.documentElement), "1"); | |
| }, "Implicit @scope in a constructed stylesheet adopted by a document matches the root element"); | |
| test(t => { | |
| adopt(t, `@scope { :scope { z-index: 1; } }`); | |
| assert_equals(zIndex(document.documentElement), "auto"); | |
| assert_equals(zIndex(document.body), "auto"); | |
| }, ":scope in implicit @scope in a constructed stylesheet adopted by a document does not match any element"); | |
| test(t => { | |
| adopt(t, `@scope { z-index: 1; }`); | |
| assert_equals(zIndex(document.documentElement), "auto"); | |
| assert_equals(zIndex(document.body), "auto"); | |
| }, "Scoped declarations in implicit @scope in a constructed stylesheet adopted by a document do not match any element"); | |
| test(t => { | |
| adopt(t, `@scope { :scope .a { z-index: 1; } }`); | |
| assert_equals(zIndex(inner), "1"); | |
| }, "Explicit :scope with a descendant combinator in implicit @scope in a constructed stylesheet adopted by a document"); | |
| test(t => { | |
| adopt(t, `@scope { & .a { z-index: 1; } }`); | |
| assert_equals(zIndex(inner), "1"); | |
| }, "& with a descendant combinator in implicit @scope in a constructed stylesheet adopted by a document"); | |
| test(t => { | |
| adopt(t, `@scope { > html { z-index: 1; } > body { z-index: 1; } }`); | |
| assert_equals(zIndex(document.documentElement), "1"); | |
| assert_equals(zIndex(document.body), "auto"); | |
| }, "Child combinator in implicit @scope in a constructed stylesheet adopted by a document matches only the root element"); | |
| test(t => { | |
| adopt(t, `@scope to (.limit) { .a { z-index: 1; } }`); | |
| assert_equals(zIndex(inner), "1"); | |
| assert_equals(zIndex(limited), "auto"); | |
| }, "Implicit @scope with a scope end in a constructed stylesheet adopted by a document"); | |
| test(t => { | |
| adopt(t, ` | |
| @scope { .a { z-index: 1; } } | |
| .a { z-index: 2; } | |
| `); | |
| assert_equals(zIndex(inner), "1"); | |
| }, "Implicit @scope in a constructed stylesheet adopted by a document wins over unscoped rules by proximity"); | |
| test(t => { | |
| adopt(t, ` | |
| @scope (#outer) { .a { z-index: 2; } } | |
| @scope { .a { z-index: 1; } } | |
| `); | |
| assert_equals(zIndex(inner), "2"); | |
| }, "Implicit @scope in a constructed stylesheet adopted by a document loses to a closer scoping root by proximity"); | |
| test(t => { | |
| adopt(t, `@scope { @scope (.b) { .a { z-index: 1; } } }`); | |
| assert_equals(zIndex(inner), "1"); | |
| }, "Nested @scope inside implicit @scope in a constructed stylesheet adopted by a document"); | |
| test(t => { | |
| const root = createShadowRoot(t); | |
| adopt(t, `@scope { .a { z-index: 1; } }`); | |
| assert_equals(zIndex(inner), "1"); | |
| assert_equals(zIndex(root.querySelector(".a")), "auto"); | |
| }, "Implicit @scope in a constructed stylesheet adopted by a document does not match in shadow trees"); | |
| test(t => { | |
| const root = createShadowRoot(t); | |
| const sheet = adopt(t, `@scope { .a { z-index: 1; } }`); | |
| root.adoptedStyleSheets = [sheet]; | |
| assert_equals(zIndex(inner), "1"); | |
| assert_equals(zIndex(root.querySelector(".a")), "1"); | |
| }, "Implicit @scope in a constructed stylesheet adopted by both a document and a shadow root"); | |
| test(t => { | |
| adopt(t, `@scope { .a { z-index: 1; } }`); | |
| assert_equals(zIndex(inner), "1"); | |
| document.adoptedStyleSheets = []; | |
| assert_equals(zIndex(inner), "auto"); | |
| }, "Implicit @scope in a constructed stylesheet stops matching once the document no longer adopts it"); | |
| </script> |