getComputedStyle-insets.js (9578B)
1 export const testEl = document.createElement("div"); 2 export const containerForInflow = document.createElement("div"); 3 export const containerForAbspos = document.createElement("div"); 4 export const containerForFixed = document.createElement("div"); 5 6 testEl.id = "test"; 7 containerForInflow.id = "container-for-inflow"; 8 containerForAbspos.id = "container-for-abspos"; 9 containerForFixed.id = "container-for-fixed"; 10 11 containerForInflow.appendChild(testEl); 12 containerForAbspos.appendChild(containerForInflow); 13 containerForFixed.appendChild(containerForAbspos); 14 document.body.appendChild(containerForFixed); 15 16 const stylesheet = document.createElement("style"); 17 stylesheet.textContent = ` 18 #container-for-inflow { 19 /* Content area: 100px tall, 200px wide */ 20 height: 100px; 21 width: 200px; 22 padding: 1px 2px; 23 border-width: 2px 4px; 24 margin: 4px 8px; 25 } 26 #container-for-abspos { 27 /* Padding area: 200px tall, 400px wide */ 28 height: 184px; 29 width: 368px; 30 padding: 8px 16px; 31 border-width: 16px 32px; 32 margin: 32px 64px; 33 position: relative; 34 } 35 #container-for-fixed { 36 /* Padding area: 300px tall, 600px wide */ 37 height: 172px; 38 width: 344px; 39 padding: 64px 128px; 40 border-width: 128px 256px; 41 margin: 256px 512px; 42 position: absolute; 43 transform: scale(1); 44 visibility: hidden; 45 } 46 [id ^= container] { 47 border-style: solid; 48 } 49 `; 50 document.head.prepend(stylesheet); 51 52 function runTestsWithWM(data, testWM, cbWM) { 53 const { 54 style, 55 containingBlockElement, 56 containingBlockArea, 57 preservesPercentages, 58 preservesAuto, 59 canStretchAutoSize, 60 staticPositionX, 61 staticPositionY, 62 } = data; 63 64 let cbHeight = containingBlockElement ? containingBlockElement.clientHeight : NaN; 65 let cbWidth = containingBlockElement ? containingBlockElement.clientWidth : NaN; 66 if (containingBlockElement && containingBlockArea == "content") { 67 const cs = getComputedStyle(containingBlockElement); 68 cbHeight -= parseFloat(cs.paddingTop) + parseFloat(cs.paddingBottom); 69 cbWidth -= parseFloat(cs.paddingLeft) + parseFloat(cs.paddingRight); 70 } 71 72 const staticPositionTop = cbWM.blockStart == "top" || cbWM.inlineStart == "top" 73 ? staticPositionY : cbHeight - staticPositionY; 74 const staticPositionLeft = cbWM.blockStart == "left" || cbWM.inlineStart == "left" 75 ? staticPositionX : cbWidth - staticPositionX; 76 const staticPositionBottom = cbWM.blockStart == "bottom" || cbWM.inlineStart == "bottom" 77 ? staticPositionY : cbHeight - staticPositionY; 78 const staticPositionRight = cbWM.blockStart == "right" || cbWM.inlineStart == "right" 79 ? staticPositionX : cbWidth - staticPositionX; 80 81 function serialize(declarations) { 82 return Object.entries(declarations).map(([p, v]) => `${p}: ${v}; `).join(""); 83 } 84 85 function wmName(wm) { 86 return Object.values(wm.style).join(" "); 87 } 88 89 function checkStyle(declarations, expected, msg) { 90 test(function() { 91 testEl.style.cssText = style + "; " + serialize(Object.assign({}, declarations, testWM.style)); 92 if (containingBlockElement) { 93 containingBlockElement.style.cssText = serialize(Object.assign({}, cbWM.style)); 94 } 95 const cs = getComputedStyle(testEl); 96 for (let [prop, value] of Object.entries(expected)) { 97 assert_equals(cs[prop], value, `'${prop}'`); 98 } 99 }, `${wmName(testWM)} inside ${wmName(cbWM)} - ${msg}`); 100 101 testEl.style.cssText = ""; 102 if (containingBlockElement) { 103 containingBlockElement.style.cssText = ""; 104 } 105 } 106 107 checkStyle({ 108 top: "1px", 109 left: "2px", 110 bottom: "3px", 111 right: "4px", 112 }, { 113 top: "1px", 114 left: "2px", 115 bottom: "3px", 116 right: "4px", 117 }, "Pixels resolve as-is"); 118 119 checkStyle({ 120 top: "1em", 121 left: "2em", 122 bottom: "3em", 123 right: "4em", 124 "font-size": "10px", 125 }, { 126 top: "10px", 127 left: "20px", 128 bottom: "30px", 129 right: "40px", 130 }, "Relative lengths are absolutized into pixels"); 131 132 if (preservesPercentages) { 133 checkStyle({ 134 top: "10%", 135 left: "25%", 136 bottom: "50%", 137 right: "75%", 138 }, { 139 top: "10%", 140 left: "25%", 141 bottom: "50%", 142 right: "75%", 143 }, "Percentages resolve as-is"); 144 } else { 145 checkStyle({ 146 top: "10%", 147 left: "25%", 148 bottom: "50%", 149 right: "75%", 150 }, { 151 top: cbHeight * 10 / 100 + "px", 152 left: cbWidth * 25 / 100 + "px", 153 bottom: cbHeight * 50 / 100 + "px", 154 right: cbWidth * 75 / 100 + "px", 155 }, "Percentages are absolutized into pixels"); 156 157 checkStyle({ 158 top: "calc(10% - 1px)", 159 left: "calc(25% - 2px)", 160 bottom: "calc(50% - 3px)", 161 right: "calc(75% - 4px)", 162 }, { 163 top: cbHeight * 10 / 100 - 1 + "px", 164 left: cbWidth * 25 / 100 - 2 + "px", 165 bottom: cbHeight * 50 / 100 - 3 + "px", 166 right: cbWidth * 75 / 100 - 4 + "px", 167 }, "calc() is absolutized into pixels"); 168 } 169 170 if (canStretchAutoSize) { 171 // Force overconstraintment by setting size or with insets that would result in 172 // negative size. Then the resolved value should be the computed one according to 173 // https://drafts.csswg.org/cssom/#resolved-value-special-case-property-like-top 174 175 checkStyle({ 176 top: "1px", 177 left: "2px", 178 bottom: "3px", 179 right: "4px", 180 height: "0px", 181 width: "0px", 182 }, { 183 top: "1px", 184 left: "2px", 185 bottom: "3px", 186 right: "4px", 187 }, "Pixels resolve as-is when overconstrained"); 188 189 checkStyle({ 190 top: "100%", 191 left: "100%", 192 bottom: "100%", 193 right: "100%", 194 }, { 195 top: cbHeight + "px", 196 left: cbWidth + "px", 197 bottom: cbHeight + "px", 198 right: cbWidth + "px", 199 }, "Percentages absolutize the computed value when overconstrained"); 200 } 201 202 if (preservesAuto) { 203 checkStyle({ 204 top: "auto", 205 left: "auto", 206 bottom: "3px", 207 right: "4px", 208 }, { 209 top: "auto", 210 left: "auto", 211 bottom: "3px", 212 right: "4px", 213 }, "If start side is 'auto' and end side is not, 'auto' resolves as-is"); 214 215 checkStyle({ 216 top: "1px", 217 left: "2px", 218 bottom: "auto", 219 right: "auto", 220 }, { 221 top: "1px", 222 left: "2px", 223 bottom: "auto", 224 right: "auto", 225 }, "If end side is 'auto' and start side is not, 'auto' resolves as-is"); 226 227 checkStyle({ 228 top: "auto", 229 left: "auto", 230 bottom: "auto", 231 right: "auto", 232 }, { 233 top: "auto", 234 left: "auto", 235 bottom: "auto", 236 right: "auto", 237 }, "If opposite sides are 'auto', they resolve as-is"); 238 } else if (canStretchAutoSize) { 239 checkStyle({ 240 top: "auto", 241 left: "auto", 242 bottom: "3px", 243 right: "4px", 244 }, { 245 top: cbHeight - 3 + "px", 246 left: cbWidth - 4 + "px", 247 bottom: "3px", 248 right: "4px", 249 }, "If start side is 'auto' and end side is not, 'auto' resolves to used value"); 250 251 checkStyle({ 252 top: "1px", 253 left: "2px", 254 bottom: "auto", 255 right: "auto", 256 }, { 257 top: "1px", 258 left: "2px", 259 bottom: cbHeight - 1 + "px", 260 right: cbWidth - 2 + "px", 261 }, "If end side is 'auto' and start side is not, 'auto' resolves to used value"); 262 263 checkStyle({ 264 top: "auto", 265 left: "auto", 266 bottom: "auto", 267 right: "auto", 268 }, { 269 top: staticPositionTop + "px", 270 left: staticPositionLeft + "px", 271 bottom: staticPositionBottom + "px", 272 right: staticPositionRight + "px", 273 }, "If opposite sides are 'auto', they resolve to used value"); 274 } else { 275 checkStyle({ 276 top: "auto", 277 left: "auto", 278 bottom: "3px", 279 right: "4px", 280 }, { 281 top: "-3px", 282 left: "-4px", 283 bottom: "3px", 284 right: "4px", 285 }, "If start side is 'auto' and end side is not, 'auto' resolves to used value"); 286 287 checkStyle({ 288 top: "1px", 289 left: "2px", 290 bottom: "auto", 291 right: "auto", 292 }, { 293 top: "1px", 294 left: "2px", 295 bottom: "-1px", 296 right: "-2px", 297 }, "If end side is 'auto' and start side is not, 'auto' resolves to used value"); 298 299 checkStyle({ 300 top: "auto", 301 left: "auto", 302 bottom: "auto", 303 right: "auto", 304 }, { 305 top: "0px", 306 left: "0px", 307 bottom: "0px", 308 right: "0px", 309 }, "If opposite sides are 'auto', they resolve to used value"); 310 } 311 } 312 313 const writingModes = [{ 314 style: { 315 "writing-mode": "horizontal-tb", 316 "direction": "ltr", 317 }, 318 blockStart: "top", 319 blockEnd: "bottom", 320 inlineStart: "left", 321 inlineEnd: "right", 322 }, { 323 style: { 324 "writing-mode": "horizontal-tb", 325 "direction": "rtl", 326 }, 327 blockStart: "top", 328 blockEnd: "bottom", 329 inlineStart: "right", 330 inlineEnd: "left", 331 }, { 332 style: { 333 "writing-mode": "vertical-lr", 334 "direction": "ltr", 335 }, 336 blockStart: "left", 337 blockEnd: "right", 338 inlineStart: "top", 339 inlineEnd: "bottom", 340 }, { 341 style: { 342 "writing-mode": "vertical-lr", 343 "direction": "rtl", 344 }, 345 blockStart: "left", 346 blockEnd: "right", 347 inlineStart: "bottom", 348 inlineEnd: "top", 349 }, { 350 style: { 351 "writing-mode": "vertical-rl", 352 "direction": "ltr", 353 }, 354 blockStart: "right", 355 blockEnd: "left", 356 inlineStart: "top", 357 inlineEnd: "bottom", 358 }, { 359 style: { 360 "writing-mode": "vertical-rl", 361 "direction": "rtl", 362 }, 363 blockStart: "right", 364 blockEnd: "left", 365 inlineStart: "bottom", 366 inlineEnd: "top", 367 }]; 368 369 export function runTests(data) { 370 for (let testWM of writingModes) { 371 for (let cbWM of writingModes) { 372 runTestsWithWM(data, testWM, cbWM); 373 } 374 } 375 }