contain-layout-dynamic-001.html (7060B)
1 <!DOCTYPE html> 2 <meta charset="utf-8"> 3 <title>Dynamic change to layout containment</title> 4 <link rel="help" href="https://drafts.csswg.org/css-contain/#contain-property"> 5 <link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1765615"> 6 <link rel="stylesheet" type="text/css" href="/fonts/ahem.css" /> 7 <script src="/resources/testharness.js"></script> 8 <script src="/resources/testharnessreport.js"></script> 9 <meta name="assert" content="Verify layout containment is properly updated after dynamic change to the contain property."> 10 <style> 11 /* Selectors for contain */ 12 #none .wrapper { 13 contain: none; 14 } 15 #layout .wrapper { 16 contain: layout; 17 } 18 #none_to_layout .wrapper { 19 contain: none; 20 } 21 #layout_to_none .wrapper { 22 contain: layout; 23 } 24 25 /* Selectors for testing absolute/fixed positioned elements */ 26 #top_spacer { 27 height: 100px; 28 background: lightgray; 29 } 30 .absolute_pos { 31 position: absolute; 32 top: 42px; 33 } 34 .fixed_pos { 35 position: fixed; 36 top: 42px; 37 } 38 39 /* Selectors for testing baseline */ 40 .flex { 41 display: inline-flex; 42 align-items: baseline; 43 } 44 45 /* Selectors for testing IFC (floats) */ 46 .floatleft { 47 float: left; 48 } 49 .clearleft { 50 clear: left; 51 } 52 53 /* Selectors for testing IFC (margin collapsing) */ 54 .blockmargin { 55 margin: 25px 0; 56 } 57 .wrapper.blockmargin { 58 background: lightgray; 59 } 60 61 .rect { 62 background: black; 63 width: 50px; 64 height: 100px; 65 } 66 </style> 67 <body> 68 <div id="log"></div> 69 70 <div id="top_spacer"></div> 71 72 <div id="none"> 73 <div class="wrapper"> 74 <div class="absolute_pos"></div> 75 <div class="fixed_pos"></div> 76 </div> 77 <div class="flex"> 78 <div class="rect"></div> 79 <div class="wrapper rect">X</div> 80 </div> 81 <div> 82 <div class="floatleft rect"></div> 83 <div class="wrapper"> 84 <div class="clearleft rect"></div> 85 </div> 86 </div> 87 <div> 88 <div class="wrapper blockmargin"> 89 <div class="rect blockmargin"></div> 90 </div> 91 </div> 92 </div> 93 94 <div id="layout"> 95 <div class="wrapper"> 96 <div class="absolute_pos"></div> 97 <div class="fixed_pos"></div> 98 </div> 99 <div class="flex"> 100 <div class="rect"></div> 101 <div class="wrapper rect">X</div> 102 </div> 103 <div> 104 <div class="floatleft rect"></div> 105 <div class="wrapper"> 106 <div class="clearleft rect"></div> 107 </div> 108 </div> 109 <div> 110 <div class="wrapper blockmargin"> 111 <div class="rect blockmargin"></div> 112 </div> 113 </div> 114 </div> 115 116 <div id="none_to_layout"> 117 <div class="wrapper"> 118 <div class="absolute_pos"></div> 119 <div class="fixed_pos"></div> 120 </div> 121 <div class="flex"> 122 <div class="rect"></div> 123 <div class="wrapper rect">X</div> 124 </div> 125 <div> 126 <div class="floatleft rect"></div> 127 <div class="wrapper"> 128 <div class="clearleft rect"></div> 129 </div> 130 </div> 131 <div> 132 <div class="wrapper blockmargin"> 133 <div class="rect blockmargin"></div> 134 </div> 135 </div> 136 </div> 137 138 <div id="layout_to_none"> 139 <div class="wrapper"> 140 <div class="absolute_pos"></div> 141 <div class="fixed_pos"></div> 142 </div> 143 <div class="flex"> 144 <div class="rect"></div> 145 <div class="wrapper rect">X</div> 146 </div> 147 <div> 148 <div class="floatleft rect"></div> 149 <div class="wrapper"> 150 <div class="clearleft rect"></div> 151 </div> 152 </div> 153 <div> 154 <div class="wrapper blockmargin"> 155 <div class="rect blockmargin"></div> 156 </div> 157 </div> 158 </div> 159 160 <script> 161 function verifyLayoutContainment(id, applied) { 162 let container = document.getElementById(id); 163 let wrappers = container.getElementsByClassName("wrapper"); 164 165 // To verify the containment box establishes an absolute positioning 166 // containing block and a fixed positioning containing block, we test 167 // positions of absolutely/fixed positioned children (a bit below the 168 // containment box rather than a bit below the top of the viewport). 169 let containingBlockTop = wrappers[0].getBoundingClientRect().top; 170 let absTop = container.getElementsByClassName("absolute_pos")[0] 171 .getBoundingClientRect().top; 172 assert_equals(absTop > containingBlockTop, applied, "absolute positioning containing block"); 173 let fixedTop = container.getElementsByClassName("fixed_pos")[0] 174 .getBoundingClientRect().top; 175 assert_equals(fixedTop > containingBlockTop, applied, "fixed positioning containing block"); 176 177 // To verify the containment box suppresses baseline, we verify that 178 // the two items in the flex container are properly aligned. 179 let item1 = wrappers[1]; 180 let item2 = item1.previousElementSibling; 181 let aligned = Math.abs(item1.getBoundingClientRect().top - item2.getBoundingClientRect().top) <= 1; 182 assert_equals(aligned, applied, "vertical baseline suppressed"); 183 184 // To verify the containment box establishes an independent formatting 185 // context, we test position the clear: left div with respect to the 186 // float: left div. 187 let floatLeft = wrappers[2].previousElementSibling; 188 let clearLeft = wrappers[2].firstElementChild; 189 let clearNextToFloat = Math.abs(floatLeft.getBoundingClientRect().top - clearLeft.getBoundingClientRect().top) <= 1; 190 assert_equals(clearNextToFloat, applied, "independent formatting context (floats)"); 191 192 // In addition, we verify that the margin inside the containment box 193 // are not collapsed. 194 let IFCWithMargin = wrappers[3]; 195 let childWithMargin = IFCWithMargin.firstElementChild; 196 let marginCollapsed = Math.abs(IFCWithMargin.getBoundingClientRect().height - childWithMargin.getBoundingClientRect().height) <= 1; 197 assert_equals(!marginCollapsed, applied, "independent formatting context (margins collapsing)"); 198 } 199 200 function setContain(id, value) { 201 let container = document.getElementById(id); 202 Array.from(container.getElementsByClassName("wrapper")) 203 .forEach(element => element.style.contain = value); 204 } 205 206 promise_test(async () => { 207 await document.fonts.ready; 208 verifyLayoutContainment("none", /* applied=*/false); 209 }, "contain: none"); 210 211 promise_test(async () => { 212 await document.fonts.ready; 213 verifyLayoutContainment("layout", /* applied=*/true); 214 }, "contain: layout"); 215 216 promise_test(async () => { 217 await document.fonts.ready; 218 setContain("none_to_layout", "layout"); 219 verifyLayoutContainment("none_to_layout", /* applied=*/true) 220 }, "switching contain from none to layout"); 221 222 promise_test(async () => { 223 await document.fonts.ready; 224 setContain("layout_to_none", "none"); 225 verifyLayoutContainment("layout_to_none", /* applied=*/false); 226 }, "switching contain from layout to none"); 227 </script> 228 </body>