Status: FAIL | Duration: 53ms | Subtests: 0/1 | Open test on wpt.live | wpt.fyi
/css/css-cascade/revert-rule-shadow.html
<!DOCTYPE html> <title>The revert-rule keyword: interaction with shadow DOM scopes</title> <link rel="author" title="Tim Nguyen" href="https://github.com/nt1m"> <link rel="help" href="https://drafts.csswg.org/css-cascade-5/#revert-rule-keyword"> <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> <!-- Test 1: revert-rule in document rule falls back to :host rule --> <div id="host1"></div> <script> host1.attachShadow({mode: 'open'}).innerHTML = ` <style> :host { color: green; } </style> `; </script> <style> #host1 { color: red; color: revert-rule; } </style> <script> test(() => { assert_true(CSS.supports('color:revert-rule')); assert_equals(getComputedStyle(host1).color, 'rgb(0, 128, 0)'); }, 'revert-rule in document rule falls back to :host rule'); </script> <!-- Test 2: revert-rule in document rule falls back to ::slotted rule --> <div id="host2"><div id="slotted2"></div></div> <script> host2.attachShadow({mode: 'open'}).innerHTML = ` <style> ::slotted(*) { color: green; } </style> <slot></slot> `; </script> <style> #slotted2 { color: red; color: revert-rule; } </style> <script> test(() => { assert_equals(getComputedStyle(slotted2).color, 'rgb(0, 128, 0)'); }, 'revert-rule in document rule falls back to ::slotted rule'); </script> <!-- Test 3: revert-rule in :host rule has no effect when a document rule wins --> <div id="host3"></div> <script> host3.attachShadow({mode: 'open'}).innerHTML = ` <style> :host { color: revert-rule; } </style> `; </script> <style> #host3 { color: green; } </style> <script> test(() => { assert_equals(getComputedStyle(host3).color, 'rgb(0, 128, 0)'); }, 'revert-rule in :host rule has no effect when a document rule already wins'); </script> <!-- Test 4: revert-rule in document rule with no fallback falls through to unset --> <div id="host4"></div> <script> host4.attachShadow({mode: 'open'}).innerHTML = `<slot></slot>`; </script> <style> #host4 { color: red; color: revert-rule; } </style> <script> test(() => { // No :host rule exists; color is inherited from the document body (rgb(0,0,0)). assert_equals(getComputedStyle(host4).color, 'rgb(0, 0, 0)'); }, 'revert-rule with no shadow fallback falls through to unset (inherited)'); </script> <!-- Test 5: revert-rule in document rule, multiple competing :host rules --> <div id="host5"></div> <script> host5.attachShadow({mode: 'open'}).innerHTML = ` <style> :host { color: green; } :host { color: red; } </style> `; </script> <style> #host5 { color: blue; color: revert-rule; } </style> <script> test(() => { assert_equals(getComputedStyle(host5).color, 'rgb(255, 0, 0)'); }, 'revert-rule in document rule falls back to the winning :host rule'); </script> <!-- Test 6: revert-rule in document rule, :host rule also reverts --> <div id="host6"></div> <script> host6.attachShadow({mode: 'open'}).innerHTML = ` <style> :host { color: green; } :host { color: revert-rule; } </style> `; </script> <style> #host6 { color: blue; color: revert-rule; } </style> <script> test(() => { // The document revert-rule falls back to the :host block. Within the :host // block, the second :host rule says revert-rule, which falls back to the // first :host rule's green. assert_equals(getComputedStyle(host6).color, 'rgb(0, 128, 0)'); }, 'revert-rule chain across document rule and :host rule'); </script> <!-- Test 7: revert-rule in ::part() rule falls back to earlier ::part() rule --> <div id="host7"></div> <script> { const shadow = host7.attachShadow({mode: 'open'}); shadow.innerHTML = `<span id="p7" part="mypart">text</span>`; } </script> <style> #host7::part(mypart) { color: green; } #host7::part(mypart) { color: revert-rule; } </style> <script> test(() => { const part = host7.shadowRoot.getElementById('p7'); assert_equals(getComputedStyle(part).color, 'rgb(0, 128, 0)'); }, 'revert-rule in ::part() rule falls back to earlier ::part() rule'); </script> <!-- Test 8: revert-rule in ::part() rule falls back to shadow-internal rule --> <div id="host8"></div> <script> { const shadow = host8.attachShadow({mode: 'open'}); shadow.innerHTML = ` <style>span { color: green; }</style> <span id="p8" part="mypart">text</span> `; } </script> <style> #host8::part(mypart) { color: revert-rule; } </style> <script> test(() => { // The ::part() rule reverts, falling back to the shadow-internal span rule (green). const part = host8.shadowRoot.getElementById('p8'); assert_equals(getComputedStyle(part).color, 'rgb(0, 128, 0)'); }, 'revert-rule in ::part() rule falls back to shadow-internal rule'); </script> <!-- Test 9: revert-rule in shadow-internal rule, ::part() rule wins --> <div id="host9"></div> <script> { const shadow = host9.attachShadow({mode: 'open'}); shadow.innerHTML = ` <style> span { color: blue; } span { color: revert-rule; } </style> <span id="p9" part="mypart">text</span> `; } </script> <style> #host9::part(mypart) { color: green; } </style> <script> test(() => { // The ::part() rule in the document wins. revert-rule inside the shadow // does not affect the winning ::part() declaration. const part = host9.shadowRoot.getElementById('p9'); assert_equals(getComputedStyle(part).color, 'rgb(0, 128, 0)'); }, 'revert-rule in shadow-internal rule has no effect when ::part() rule wins'); </script> <!-- Test 10: revert-rule chain across two ::part() rules --> <div id="host10"></div> <script> { const shadow = host10.attachShadow({mode: 'open'}); shadow.innerHTML = `<span id="p10" part="mypart">text</span>`; } </script> <style> #host10::part(mypart) { color: red; } #host10::part(mypart) { color: green; } #host10::part(mypart) { color: revert-rule; } </style> <script> test(() => { // Third rule reverts to what would exist without it → second rule (green). const part = host10.shadowRoot.getElementById('p10'); assert_equals(getComputedStyle(part).color, 'rgb(0, 128, 0)'); }, 'revert-rule in third ::part() rule falls back to second ::part() rule'); </script> <!-- Test 11: revert-rule in ::part() and :host on same host element --> <div id="host11"></div> <script> { const shadow = host11.attachShadow({mode: 'open'}); shadow.innerHTML = ` <style>:host { color: blue; }</style> <span id="p11" part="mypart">text</span> `; } </script> <style> #host11 { color: red; color: revert-rule; } #host11::part(mypart) { color: green; } </style> <script> test(() => { // Host color reverts to :host rule (blue). assert_equals(getComputedStyle(host11).color, 'rgb(0, 0, 255)'); // Part color is set by ::part() rule (green), independent of host revert. const part = host11.shadowRoot.getElementById('p11'); assert_equals(getComputedStyle(part).color, 'rgb(0, 128, 0)'); }, 'revert-rule on host and ::part() rule on part are independent'); </script> <!-- Test 12: revert-rule in ::part() rule falls back across selector specificity --> <div id="host12" class="host12cls"></div> <script> { const shadow = host12.attachShadow({mode: 'open'}); shadow.innerHTML = `<span id="p12" part="mypart">text</span>`; } </script> <style> #host12::part(mypart) { color: green; } #host12.host12cls::part(mypart) { color: revert-rule; } </style> <script> test(() => { // Higher specificity rule reverts, so falls back to the lower-specificity green. const part = host12.shadowRoot.getElementById('p12'); assert_equals(getComputedStyle(part).color, 'rgb(0, 128, 0)'); }, 'revert-rule in higher-specificity ::part() rule falls back to lower-specificity ::part() rule'); </script>