animation-004.html (9110B)
1 <!doctype html> 2 <meta charset=utf-8> 3 <title>Animating CSS logical properties using CSS Transitions</title> 4 <link rel="help" href="https://drafts.csswg.org/css-logical/#box"> 5 <meta name="assert" content="The specified values of these properties are separate from the specified values of the parallel physical properties, but the flow-relative and physical properties share computed values."> 6 <script src="/resources/testharness.js"></script> 7 <script src="/resources/testharnessreport.js"></script> 8 <script src="../css-animations/support/testcommon.js"></script> 9 10 <div id="log"></div> 11 <div id="test"></div> 12 <script> 13 'use strict'; 14 15 const testEl = document.getElementById("test"); 16 17 function makeDeclaration(object = {}) { 18 return Object.entries(object).map(([prop, val]) => prop + ": " + val).join("; "); 19 } 20 21 /** 22 * Starts a CSS transition in testEl. By default, the transition will affect the properies 23 * specified in finalStyles, be linear, last 10 seconds and start halfway, but this can be 24 * overridden in baseStyles. 25 * 26 * @param t The testharness.js Test object. 27 * @param baseStyles A dictionary object with property names and values to set on the 28 * element before starting the transition. 29 * @param finalStyles A dictionary object with property names and values towards which 30 * the element will transition. 31 * @param [transitionStyles] An optional dictionary object to costumize the transition. 32 */ 33 function transition(t, baseStyles, finalStyles, transitionStyles = {}) { 34 // Clear styles from previous test. 35 testEl.style.cssText = ""; 36 testEl.className = ""; 37 getComputedStyle(testEl).height; 38 39 // Set base and final styles 40 addStyle(t, { 41 "#test": makeDeclaration(baseStyles), 42 "#test.transition": makeDeclaration(finalStyles), 43 }); 44 getComputedStyle(testEl).height; 45 46 // Set transition styles 47 const defaultTransition = { 48 "transition-property": Object.keys(finalStyles).join(", "), 49 "transition-timing-function": "linear", 50 "transition-duration": "10s", 51 "transition-delay": "-5s", 52 }; 53 addStyle(t, { 54 "#test": makeDeclaration(Object.assign(defaultTransition, transitionStyles)), 55 }); 56 57 // Start the transition 58 testEl.className = "transition"; 59 } 60 61 test(t => { 62 transition(t, { 63 "block-size": "0px", 64 }, { 65 "block-size": "100px", 66 }); 67 assert_equals(getComputedStyle(testEl).height, '50px'); 68 }, 'Logical properties can be transitioned'); 69 70 test(t => { 71 transition(t, { 72 "block-size": "0px", 73 "writing-mode": "vertical-rl", 74 }, { 75 "block-size": "100px", 76 }); 77 assert_equals(getComputedStyle(testEl).width, '50px'); 78 assert_equals(getComputedStyle(testEl).height, '0px'); 79 }, 'Logical properties in transitions respect the writing-mode'); 80 81 test(t => { 82 transition(t, { 83 "margin-inline-start": "0px", 84 "direction": "rtl", 85 }, { 86 "margin-inline-start": "100px", 87 }); 88 assert_equals(getComputedStyle(testEl).marginLeft, '0px'); 89 assert_equals(getComputedStyle(testEl).marginRight, '50px'); 90 }, 'Logical properties in transitions respect the direction'); 91 92 test(t => { 93 transition(t, { 94 "block-size": "0px", 95 "height": "200px", 96 }, { 97 "block-size": "100px", 98 "height": "300px", 99 }); 100 assert_equals(getComputedStyle(testEl).height, '250px'); 101 }, 'Declaration order is respected within declaration blocks'); 102 103 test(t => { 104 transition(t, {}, { 105 "margin-top": "200px", 106 "margin-block-start": "100px" 107 }, { 108 "transition-timing-function": "step-start", 109 }); 110 assert_equals(getComputedStyle(testEl).marginTop, '100px'); 111 }, 'Logical properties are able to override physical properties in declaration blocks'); 112 113 test(t => { 114 transition(t, {}, { 115 "margin-inline": "200px", 116 "margin-inline-start": "0px", 117 "margin-inline-start": "100px", 118 }, { 119 "transition-timing-function": "step-start", 120 }); 121 assert_equals(getComputedStyle(testEl).marginLeft, '100px'); 122 }, 'Declaration order is respected amongst logical properties within declaration blocks'); 123 124 test(t => { 125 transition(t, { 126 "block-size": "200px", 127 }, { 128 "height": "300px", 129 }); 130 assert_equals(getComputedStyle(testEl).height, '250px'); 131 }, 'Physical properties and logical properties can be mixed'); 132 133 test(t => { 134 transition(t, { 135 "height": "100px", 136 "block-size": "200px", 137 }, { 138 "block-size": "100px", 139 "height": "300px", 140 }); 141 assert_equals(getComputedStyle(testEl).height, '250px'); 142 }, 'Declaration order is respected on each keyframe individually'); 143 144 test(t => { 145 transition(t, { 146 "width": "0px", 147 "height": "0px", 148 "block-size": "0px", 149 }, { 150 "block-size": "100px", 151 }); 152 assert_equals(getComputedStyle(testEl).width, '0px'); 153 assert_equals(getComputedStyle(testEl).height, '50px'); 154 155 testEl.style.writingMode = 'vertical-rl'; 156 assert_equals(getComputedStyle(testEl).width, '50px'); 157 assert_equals(getComputedStyle(testEl).height, '0px'); 158 }, 'Transitions update when the writing-mode is changed'); 159 160 promise_test(async t => { 161 transition(t, { 162 "width": "0px", 163 "height": "0px", 164 "block-size": "0px", 165 }, { 166 "block-size": "100px", 167 }, { 168 "transition-delay": "-9.9s", 169 }); 170 const watcher = new EventWatcher(t, testEl, [ 'transitionend' ]); 171 await watcher.wait_for('transitionend'); 172 173 assert_equals(getComputedStyle(testEl).width, '0px'); 174 assert_equals(getComputedStyle(testEl).height, '100px'); 175 176 testEl.style.transition = 'none'; 177 testEl.style.writingMode = 'vertical-rl'; 178 assert_equals(getComputedStyle(testEl).width, '100px'); 179 assert_equals(getComputedStyle(testEl).height, '0px'); 180 }, 'Filling transitions update when the writing-mode is changed'); 181 182 test(t => { 183 transition(t, { 184 "width": "0px", 185 "height": "0px", 186 }, { 187 "block-size": "100px", 188 "height": "200px", 189 }); 190 191 // Initially we are interpolating the height from 0 to 200px 192 assert_equals(getComputedStyle(testEl).width, '0px'); 193 assert_equals(getComputedStyle(testEl).height, '100px'); 194 195 // But once we change the writing-mode, we will be interpolating *both* 196 // the height (from 0px to 200px) *and* the width (from 0px to 100px). 197 testEl.style.writingMode = 'vertical-rl'; 198 assert_equals(getComputedStyle(testEl).width, '50px'); 199 assert_equals(getComputedStyle(testEl).height, '100px'); 200 }, 'The number of interpolating properties can be increased when the' 201 + ' writing-mode is changed'); 202 203 test(t => { 204 transition(t, { 205 "width": "100px", 206 "height": "100px", 207 }, { 208 "width": "500px", 209 "block-size": "200px", 210 }); 211 212 // Initially we are interpolating the width (100px -> 500px) and the height 213 // (100px -> 200px). 214 assert_equals(getComputedStyle(testEl).width, '300px'); 215 assert_equals(getComputedStyle(testEl).height, '150px'); 216 217 // Once we change the writing-mode, we will be interpolating *only* the 218 // width (300px -> 200px). 219 testEl.style.writingMode = 'vertical-rl'; 220 assert_equals(getComputedStyle(testEl).width, '250px'); 221 assert_equals(getComputedStyle(testEl).height, '100px'); 222 }, 'The number of interpolating properties can be decreased when the' 223 + ' writing-mode is changed'); 224 225 test(t => { 226 addStyle(t, { ':root': '--writingMode: horizontal-tb' }); 227 transition(t, { 228 "width": "0px", 229 "height": "0px", 230 "writing-mode": "var(--writingMode)", 231 "block-size": "0px", 232 }, { 233 "block-size": "100px" 234 }); 235 assert_equals(getComputedStyle(testEl).width, '0px'); 236 assert_equals(getComputedStyle(testEl).height, '50px'); 237 238 testEl.style.setProperty('--writingMode', 'vertical-rl'); 239 assert_equals(getComputedStyle(testEl).width, '50px'); 240 assert_equals(getComputedStyle(testEl).height, '0px'); 241 }, 'Transitions update when the writing-mode is changed through a CSS variable'); 242 243 test(t => { 244 transition(t, { 245 "margin-inline-start": "0px", 246 }, { 247 "margin-inline-start": "100px", 248 }); 249 assert_equals(getComputedStyle(testEl).marginLeft, '50px'); 250 assert_equals(getComputedStyle(testEl).marginRight, '0px'); 251 252 testEl.style.direction = 'rtl'; 253 assert_equals(getComputedStyle(testEl).marginLeft, '0px'); 254 assert_equals(getComputedStyle(testEl).marginRight, '50px'); 255 }, 'Transitions update when the direction is changed'); 256 257 test(t => { 258 transition(t, { 259 "margin-inline-start": "100px", 260 }, { 261 "margin-left": "200px", 262 }); 263 assert_equals(getComputedStyle(testEl).marginLeft, '150px'); 264 assert_equals(getComputedStyle(testEl).marginRight, '0px'); 265 266 testEl.style.direction = 'rtl'; 267 assert_equals(getComputedStyle(testEl).marginLeft, '150px'); 268 assert_equals(getComputedStyle(testEl).marginRight, '100px'); 269 }, 'Transitions from logical to physical update when the direction is changed'); 270 271 test(t => { 272 transition(t, { 273 "margin-left": "200px", 274 }, { 275 "margin-inline-start": "100px", 276 }); 277 assert_equals(getComputedStyle(testEl).marginLeft, '150px'); 278 assert_equals(getComputedStyle(testEl).marginRight, '0px'); 279 280 testEl.style.direction = 'rtl'; 281 assert_equals(getComputedStyle(testEl).marginLeft, '200px'); 282 assert_equals(getComputedStyle(testEl).marginRight, '50px'); 283 }, 'Transitions from physical to logical update when the direction is changed'); 284 </script>