try-tactic-anchor.html (7816B)
1 <!DOCTYPE html> 2 <title>CSS Anchor Positioning: try-tactic, anchor()</title> 3 <link rel="help" href="https://drafts.csswg.org/css-anchor-position-1/#typedef-position-try-fallbacks-try-tactic"> 4 <script src="/resources/testharness.js"></script> 5 <script src="/resources/testharnessreport.js"></script> 6 <style> 7 :root { 8 --anchor-left:anchor(left); 9 } 10 #cb { 11 position: absolute; 12 width: 400px; 13 height: 400px; 14 border: 1px solid black; 15 } 16 #anchor { 17 position: absolute; 18 left: 150px; 19 top: 150px; 20 width: 60px; 21 height: 70px; 22 background-color: coral; 23 anchor-name: --a; 24 } 25 #target, #ref { 26 position: absolute; 27 left: 450px; /* force fallback */ 28 width: 40px; 29 height: 40px; 30 background-color: skyblue; 31 position-anchor: --a; 32 } 33 #ref { 34 background-color: seagreen; 35 } 36 </style> 37 <style id=style> 38 </style> 39 <div id=cb> 40 <div id=anchor></div> 41 <div id=target></div> 42 <div id=ref></div> 43 </div> 44 <script> 45 46 // Verify that a given try-tactic + untransformed declaration equals 47 // a reference element using `transformed` directly. 48 function test_anchor_flip(try_tactic, untransformed, transformed) { 49 test((t) => { 50 style.textContent = ` 51 @position-try --pf { 52 inset: auto; 53 ${untransformed} 54 } 55 #target { 56 position-try-fallbacks: --pf ${try_tactic}; 57 } 58 @position-try --ref { 59 inset: auto; 60 ${transformed} 61 } 62 #ref { 63 position-try-fallbacks: --ref; 64 } 65 `; 66 assert_equals(target.offsetLeft, ref.offsetLeft, 'offsetLeft'); 67 assert_equals(target.offsetTop, ref.offsetTop, 'offsetTop'); 68 }, `${try_tactic}, ${untransformed}, ${transformed}`); 69 } 70 71 // These are the possible transformations between 72 // anchor(left/right/top/bottom): 73 // 74 // ┌───┬────┬────┬────┬────┐ 75 // │ - │ L │ R │ T │ B │ 76 // │ L │ - │ LR │ LT │ LB │ 77 // │ R │ RL │ - │ RT │ RB │ 78 // │ T │ TL │ TR │ - │ TB │ 79 // │ B │ BL │ BR │ BT │ - │ 80 // └───┴────┴────┴────┴────┘ 81 82 // No flip, no transformation. 83 test_anchor_flip('', 'right:anchor(left)', 'right:anchor(left)'); 84 85 // flip-block does not affect left-right. 86 test_anchor_flip('flip-block', 'right:anchor(left)', 'right:anchor(left)'); 87 // flip-inline does not affect left-right. 88 test_anchor_flip('flip-inline', 'bottom:anchor(top)', 'bottom:anchor(top)'); 89 90 // Note that the letters represent the arguments to the anchor() functions, 91 // not the properties. For example, LR: anchor(left) => anchor(right). 92 93 // LR 94 test_anchor_flip('flip-inline', 'right:anchor(left)', 'left:anchor(right)'); 95 // RL 96 test_anchor_flip('flip-inline', 'left:anchor(right)', 'right:anchor(left)'); 97 98 // LT 99 test_anchor_flip('flip-start', 'right:anchor(left)', 'bottom:anchor(top)'); 100 // TL 101 test_anchor_flip('flip-start', 'bottom:anchor(top)', 'right:anchor(left)'); 102 103 // LB 104 test_anchor_flip('flip-inline flip-start', 'right:anchor(left)', 'top:anchor(bottom)'); 105 // BL 106 test_anchor_flip('flip-start flip-inline', 'top:anchor(bottom)', 'right:anchor(left)'); 107 108 // RT 109 test_anchor_flip('flip-start flip-block', 'left:anchor(right)', 'bottom:anchor(top)'); 110 // TR 111 test_anchor_flip('flip-block flip-start', 'bottom:anchor(top)', 'left:anchor(right)'); 112 113 // RB 114 test_anchor_flip('flip-start', 'left:anchor(right)', 'top:anchor(bottom)'); 115 // BR 116 test_anchor_flip('flip-start', 'top:anchor(bottom)', 'left:anchor(right)'); 117 118 // TB 119 test_anchor_flip('flip-block', 'bottom:anchor(top)', 'top:anchor(bottom)'); 120 // BT 121 test_anchor_flip('flip-block', 'top:anchor(bottom)', 'bottom:anchor(top)'); 122 123 // Logical versions. 124 // 125 // These tests duplicate the above, but replace the input logical anchor() 126 // functions. 127 128 // LR 129 test_anchor_flip('flip-inline', 'right:anchor(start)', 'left:anchor(right)'); 130 // RL 131 test_anchor_flip('flip-inline', 'left:anchor(end)', 'right:anchor(left)'); 132 133 // LT 134 test_anchor_flip('flip-start', 'right:anchor(start)', 'bottom:anchor(top)'); 135 // TL 136 test_anchor_flip('flip-start', 'bottom:anchor(start)', 'right:anchor(left)'); 137 138 // LB 139 test_anchor_flip('flip-inline flip-start', 'right:anchor(start)', 'top:anchor(bottom)'); 140 // BL 141 test_anchor_flip('flip-start flip-inline', 'top:anchor(end)', 'right:anchor(left)'); 142 143 // RT 144 test_anchor_flip('flip-start flip-block', 'left:anchor(end)', 'bottom:anchor(top)'); 145 // TR 146 test_anchor_flip('flip-block flip-start', 'bottom:anchor(start)', 'left:anchor(right)'); 147 148 // RB 149 test_anchor_flip('flip-start', 'left:anchor(end)', 'top:anchor(bottom)'); 150 // BR 151 test_anchor_flip('flip-start', 'top:anchor(end)', 'left:anchor(right)'); 152 153 // TB 154 test_anchor_flip('flip-block', 'bottom:anchor(start)', 'top:anchor(bottom)'); 155 // BT 156 test_anchor_flip('flip-block', 'top:anchor(end)', 'bottom:anchor(top)'); 157 158 // The same again, except with self-start/self-end. 159 160 // LR 161 test_anchor_flip('flip-inline', 'right:anchor(self-start)', 'left:anchor(right)'); 162 // RL 163 test_anchor_flip('flip-inline', 'left:anchor(self-end)', 'right:anchor(left)'); 164 165 // LT 166 test_anchor_flip('flip-start', 'right:anchor(self-start)', 'bottom:anchor(top)'); 167 // TL 168 test_anchor_flip('flip-start', 'bottom:anchor(self-start)', 'right:anchor(left)'); 169 170 // LB 171 test_anchor_flip('flip-inline flip-start', 'right:anchor(self-start)', 'top:anchor(bottom)'); 172 // BL 173 test_anchor_flip('flip-start flip-inline', 'top:anchor(self-end)', 'right:anchor(left)'); 174 175 // RT 176 test_anchor_flip('flip-start flip-block', 'left:anchor(self-end)', 'bottom:anchor(top)'); 177 // TR 178 test_anchor_flip('flip-block flip-start', 'bottom:anchor(self-start)', 'left:anchor(right)'); 179 180 // RB 181 test_anchor_flip('flip-start', 'left:anchor(self-end)', 'top:anchor(bottom)'); 182 // BR 183 test_anchor_flip('flip-start', 'top:anchor(self-end)', 'left:anchor(right)'); 184 185 // TB 186 test_anchor_flip('flip-block', 'bottom:anchor(self-start)', 'top:anchor(bottom)'); 187 // BT 188 test_anchor_flip('flip-block', 'top:anchor(self-end)', 'bottom:anchor(top)'); 189 190 191 function test_anchor_size_flip(try_tactic, flip_expected) { 192 test((t) => { 193 style.textContent = ` 194 @position-try --pf { 195 inset: auto; 196 width: calc(anchor-size(width) + 20px); 197 height: anchor-size(height); 198 } 199 #target { 200 position-try-fallbacks: --pf ${try_tactic}; 201 } 202 `; 203 204 let expected_width = anchor.offsetWidth + (flip_expected ? 0 : 20); 205 let expected_height = anchor.offsetHeight + (flip_expected ? 20 : 0); 206 207 assert_equals(target.offsetWidth, expected_width, 'offsetWidth'); 208 assert_equals(target.offsetHeight, expected_height, 'offsetHeight'); 209 }, try_tactic); 210 } 211 212 // No flip, no transformation. 213 test_anchor_size_flip('', /* expect_flip */ false); 214 215 // Note: only the cross-axis flips cause width/height to change. 216 // LR, TB (and their reverse versions) are in-axis, other combinations are 217 // cross-axis. 218 219 // In-axis: 220 221 // LR, RL 222 test_anchor_size_flip('flip-inline', /* expect_flip */ false); 223 // TB, BT 224 test_anchor_size_flip('flip-block', /* expect_flip */ false); 225 226 // Cross-axis: 227 228 // LT, TL, RB, BR 229 test_anchor_size_flip('flip-start', /* expect_flip */ true); 230 231 // LB, BL 232 test_anchor_size_flip('flip-inline flip-start', /* expect_flip */ true); 233 234 // RT, TR 235 test_anchor_size_flip('flip-start flip-block', /* expect_flip */ true); 236 237 238 test((t) => { 239 style.textContent = ` 240 @position-try --pf { 241 inset: auto; 242 right: var(--anchor-left); 243 } 244 #target { 245 position-try-fallbacks: --pf; 246 } 247 `; 248 // Initially positioned to the left of the anchor. 249 assert_equals(target.offsetLeft, 110, 'offsetLeft'); 250 251 // Now positioned to the right of the anchor. 252 style.textContent += ` 253 #target { 254 position-try-fallbacks: --pf flip-inline; 255 } 256 `; 257 assert_equals(target.offsetLeft, 210, 'offsetLeft'); 258 }, 'Can transform a value post-var-substitution'); 259 260 </script>