has-sibling.html (5204B)
1 <!DOCTYPE html> 2 <meta charset="utf-8"> 3 <title>CSS Selector Invalidation: :has() with sibling combinator argument</title> 4 <link rel="author" title="Antti Koivisto" href="mailto:antti@apple.com"> 5 <script src="/resources/testharness.js"></script> 6 <script src="/resources/testharnessreport.js"></script> 7 <link rel="help" href="https://drafts.csswg.org/selectors/#relational"> 8 <style> 9 div, main { color: grey } 10 #subject:has(~ .test) { color: red } 11 #subject:has(+ .test) { color: green } 12 #subject:has(~ div .test) { color: blue } 13 #subject:has(~ div > .test) { color: purple } 14 #subject:has(+ div .test) { color: yellow } 15 #subject:has(+ div > .test) { color: pink } 16 </style> 17 18 <main id=main> 19 <div id=subject></div> 20 <div id=first_sibling> 21 <div id=first_sibling_child> 22 <div id=first_sibling_descendant></div> 23 </div> 24 </div> 25 <div id=second_sibling></div> 26 <div id=third_sibling> 27 <div id=third_sibling_child> 28 <div id=third_sibling_descendant></div> 29 </div> 30 </div> 31 </main> 32 <script> 33 34 const grey = 'rgb(128, 128, 128)'; 35 const red = 'rgb(255, 0, 0)'; 36 const green = 'rgb(0, 128, 0)'; 37 const blue = 'rgb(0, 0, 255)'; 38 const yellow = 'rgb(255, 255, 0)'; 39 const purple = 'rgb(128, 0, 128)'; 40 const pink = 'rgb(255, 192, 203)'; 41 42 function testColor(test_name, color) { 43 test(function() { 44 assert_equals(getComputedStyle(subject).color, color); 45 }, test_name); 46 } 47 48 function testClassChange(element, expectedColor) 49 { 50 element.classList.add('test'); 51 testColor(`add .test to ${element.id}`, expectedColor); 52 element.classList.remove('test'); 53 testColor(`remove .test from ${element.id}`, grey); 54 } 55 56 function testElementInsertionBefore(beforeElement, expectedColor) 57 { 58 const newElement = document.createElement('div'); 59 newElement.classList.add('test') 60 61 beforeElement.before(newElement); 62 testColor(`insert element div.test before ${beforeElement.id}`, expectedColor); 63 64 newElement.remove(); 65 testColor(`remove element div.test before ${beforeElement.id}`, grey); 66 } 67 68 function testElementInsertionAfter(afterElement, expectedColor) 69 { 70 const newElement = document.createElement('div'); 71 newElement.classList.add('test') 72 73 afterElement.after(newElement); 74 testColor(`insert element div.test after ${afterElement.id}`, expectedColor); 75 76 newElement.remove(); 77 testColor(`remove element div.test after ${afterElement.id}`, grey); 78 } 79 80 function testTreeInsertionBefore(beforeElement, expectedColor) 81 { 82 const newElement = document.createElement('div'); 83 const newChild = document.createElement('div'); 84 newChild.classList.add('test'); 85 newElement.appendChild(newChild); 86 87 beforeElement.before(newElement); 88 testColor(`insert tree div>div.test before ${beforeElement.id}`, expectedColor); 89 90 newElement.remove(); 91 testColor(`remove tree div>div.test before ${beforeElement.id}`, grey); 92 } 93 94 function testTreeInsertionAfter(afterElement, expectedColor) 95 { 96 const newElement = document.createElement('div'); 97 const newChild = document.createElement('div'); 98 newChild.classList.add('test'); 99 newElement.appendChild(newChild); 100 101 afterElement.after(newElement); 102 testColor(`insert tree div>div.test after ${afterElement.id}`, expectedColor); 103 104 newElement.remove(); 105 testColor(`remove tree div>div.test after ${afterElement.id}`, grey); 106 } 107 108 testColor('initial_color', grey); 109 110 testClassChange(first_sibling, green); 111 testClassChange(second_sibling, red); 112 testClassChange(third_sibling, red); 113 testClassChange(first_sibling_child, pink); 114 testClassChange(first_sibling_descendant, yellow); 115 testClassChange(third_sibling_child, purple); 116 testClassChange(third_sibling_descendant, blue); 117 118 testElementInsertionBefore(first_sibling, green); 119 testElementInsertionBefore(second_sibling, red); 120 testElementInsertionBefore(third_sibling, red); 121 testElementInsertionBefore(first_sibling_child, pink); 122 testElementInsertionBefore(first_sibling_descendant, yellow); 123 testElementInsertionBefore(third_sibling_child, purple); 124 testElementInsertionBefore(third_sibling_descendant, blue); 125 126 testElementInsertionAfter(first_sibling, red); 127 testElementInsertionAfter(second_sibling, red); 128 testElementInsertionAfter(third_sibling, red); 129 testElementInsertionAfter(first_sibling_child, pink); 130 testElementInsertionAfter(first_sibling_descendant, yellow); 131 testElementInsertionAfter(third_sibling_child, purple); 132 testElementInsertionAfter(third_sibling_descendant, blue); 133 134 testTreeInsertionBefore(first_sibling, pink); 135 testTreeInsertionBefore(second_sibling, purple); 136 testTreeInsertionBefore(third_sibling, purple); 137 testTreeInsertionBefore(first_sibling_child, yellow); 138 testTreeInsertionBefore(first_sibling_descendant, yellow); 139 testTreeInsertionBefore(third_sibling_child, blue); 140 testTreeInsertionBefore(third_sibling_descendant, blue); 141 142 testTreeInsertionAfter(first_sibling, purple); 143 testTreeInsertionAfter(second_sibling, purple); 144 testTreeInsertionAfter(third_sibling, purple); 145 testTreeInsertionAfter(first_sibling_child, yellow); 146 testTreeInsertionAfter(first_sibling_descendant, yellow); 147 testTreeInsertionAfter(third_sibling_child, blue); 148 testTreeInsertionAfter(third_sibling_descendant, blue); 149 </script>