1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136
|
<!DOCTYPE html>
<meta charset="utf-8" />
<title>CSS Selectors Invalidation: user-action pseudo classes in :has() argument</title>
<link rel="author" title="Byungwoo Lee" href="blee@igalia.com">
<link rel="help" href="https://drafts.csswg.org/selectors/#relational">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/resources/testdriver.js"></script>
<script src="/resources/testdriver-actions.js"></script>
<script src="/resources/testdriver-vendor.js"></script>
<style>
.ancestor:has(.descendant1:hover) { color: blue }
.ancestor:has(.descendant1:hover) .other-descendant { color: navy }
.ancestor:has(.descendant1:hover:active) { color: skyblue }
.ancestor:has(.descendant1:hover:active) .other-descendant { color: lightblue }
.ancestor:has(:focus) { color: green }
.ancestor:has(:focus) .other-descendant { color: darkgreen }
.ancestor:has(.descendant2:focus-visible) { color: yellowgreen }
.ancestor:has(.descendant2:focus-visible) .other-descendant { color: greenyellow }
.ancestor:has(.descendant3:focus-within) { color: lightgreen }
.ancestor:has(.descendant3:focus-within) .other-descendant { color: violet }
</style>
<div id=subject1 class=ancestor>
<div>
<div id=unhoverme>No :hover</div>
<div id=hoverme class=descendant1>Hover and click me</div>
<div id=focusme1 tabindex=1>Focus me</div>
<div id=focusme2 class=descendant2 tabindex=2>Focus me</div>
<div class=descendant3>
<div><div id=focusme3 tabindex=3>Focus me</div></div>
</div>
</div>
<div><div id=subject3 class=other-descendant>subject</div></div>
</div>
<div id=subject2 class=ancestor>
<div id=focusme4 tabindex=4>Focus me</div>
<div><div id=subject4 class=other-descendant>subject</div></div>
</div>
<script>
const tab_key = '\ue004';
promise_test(async () => {
assert_equals(getComputedStyle(subject1).color, "rgb(0, 0, 0)", "subject1 initially black");
assert_equals(getComputedStyle(subject2).color, "rgb(0, 0, 0)", "subject3 initially black");
await new test_driver
.Actions()
.pointerMove(0, 0, {origin: hoverme})
.send();
assert_equals(getComputedStyle(subject1).color, "rgb(0, 0, 255)",
"subject1 should be blue");
assert_equals(getComputedStyle(subject3).color, "rgb(0, 0, 128)",
"subject3 should be navy");
await new test_driver
.Actions()
.pointerMove(0, 0, {origin: unhoverme})
.send();
assert_equals(getComputedStyle(subject1).color, "rgb(0, 0, 0)",
"subject1 should be back to black");
assert_equals(getComputedStyle(subject3).color, "rgb(0, 0, 0)",
"subject3 should be back to black");
await new test_driver
.Actions()
.pointerMove(0, 0, {origin: hoverme})
.pointerDown()
.send();
assert_equals(getComputedStyle(subject1).color, "rgb(135, 206, 235)",
"subject1 should be skyblue");
assert_equals(getComputedStyle(subject3).color, "rgb(173, 216, 230)",
"subject3 should be lightblue");
// Clean up `pointerDown` from above. We want to test invalidation from
// `:hover:active` to `:hover`, but there's no guarantee that pointer
// state will stay the same between actions.
await new test_driver
.Actions()
.pointerUp()
.pointerMove(0, 0, {origin: unhoverme})
.send();
// Perform the entire activation chain again, then perform `pointerUp`.
await new test_driver
.Actions()
.pointerMove(0, 0, {origin: hoverme})
.pointerDown()
.pointerUp()
.send();
assert_equals(getComputedStyle(subject1).color, "rgb(0, 0, 255)",
"subject1 should be blue");
assert_equals(getComputedStyle(subject3).color, "rgb(0, 0, 128)",
"subject3 should be navy");
await new test_driver
.Actions()
.pointerMove(0, 0, {origin: focusme1})
.pointerDown()
.pointerUp()
.send();
assert_equals(getComputedStyle(subject1).color, "rgb(0, 128, 0)",
"subject1 should be green");
assert_equals(getComputedStyle(subject3).color, "rgb(0, 100, 0)",
"subject3 should be darkgreen");
await test_driver.send_keys(document.body, tab_key);
assert_equals(getComputedStyle(subject1).color, "rgb(154, 205, 50)",
"subject1 should be yellowgreen");
assert_equals(getComputedStyle(subject3).color, "rgb(173, 255, 47)",
"subject3 should be greenyellow");
await test_driver.send_keys(document.body, tab_key);
assert_equals(getComputedStyle(subject1).color, "rgb(144, 238, 144)",
"subject1 should be lightgreen");
assert_equals(getComputedStyle(subject3).color, "rgb(238, 130, 238)",
"subject3 should be violet");
focusme3.remove();
assert_equals(getComputedStyle(subject1).color, "rgb(0, 0, 0)",
"subject1 should be black");
assert_equals(getComputedStyle(subject3).color, "rgb(0, 0, 0)",
"subject3 should be black");
await test_driver.send_keys(document.body, tab_key);
assert_equals(getComputedStyle(subject2).color, "rgb(0, 128, 0)",
"subject2 should be green");
assert_equals(getComputedStyle(subject4).color, "rgb(0, 100, 0)",
"subject4 should be darkgreen");
focusme4.remove();
assert_equals(getComputedStyle(subject2).color, "rgb(0, 0, 0)",
"subject2 should be black");
assert_equals(getComputedStyle(subject4).color, "rgb(0, 0, 0)",
"subject4 should be black");
});
</script>
|