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