floats-wrap-bfc-with-margin-003.tentative.html (6377B)
1 <!DOCTYPE html> 2 <html class="reftest-wait"> 3 <meta charset="utf-8"> 4 <title>CSS Test: BFCs with large margin, placed next to a float</title> 5 <link rel="author" title="Daniel Holbert" href="mailto:dholbert@mozilla.com"> 6 <link rel="help" href="https://www.w3.org/TR/CSS21/visuren.html#floats"> 7 <link rel="help" href="https://www.w3.org/TR/CSS21/visudet.html#blockwidth"> 8 <link rel="match" href="floats-wrap-bfc-with-margin-003-ref.html"> 9 <!-- This test exercises the layout of an auto-width BFC with a large positive 10 margin on one side, positioned alongside a float. (Here, "large" = larger 11 than the space that's left when the float's width and the BFC's border 12 are subtracted away from the available space.) 13 14 The scenarios here break down into 3 cases, described below as A/B/C with 15 expected outcomes for each (with expectations based on the observed and 16 interoperably-implemented behavior of Gecko, WebKit, and Blink, aside 17 from some known bugs listed further down[1]): 18 19 (A) If the BFC's margin is on the same side as the float, then that margin 20 can simply overlap the float. In this case, nothing needs to overflow or 21 wrap, and there may even be some space remaining for the BFC's auto-width 22 content box (rendered as aqua). 23 24 (B) If the BFC's margin is on the "line-start" side and the float is on 25 the "line-end" side, then the BFC's margin pushes it into the float's 26 margin-box-area such that it impermissably "collides". So, the BFC 27 instead gets moved down below the float to avoid this collision. With 28 this moved-down placement, there may be space remaining for the BFC's 29 auto-width content-box -- precisely the same amount of space as in case A. 30 31 (C) If the BFC's margin is on the "line-end" side and the float is on the 32 "line-start" side, then the BFC is placed adjacent to the float, and its 33 large margin simply runs off the line-end edge of its containing 34 block. The BFC's content-box is 0 width (since there's no free space left 35 over). 36 37 Note: the expected-outcome in case B and C feels somewhat asymmetrical, 38 and in fact Gecko is the only engine that pushes the BFC down in case B. 39 But Blink/WebKit's alternative behavior for case B involves the BFC 40 overlapping the float, which clearly violates the spec, as discussed in 41 their bugs linked below. So I'm making the test expect Gecko's existing 42 and non-spec-violating behavior for case B, at this point. (I'm guessing 43 the asymmetry comes from how overflowing margins are handled at the 44 line-start vs. line-end edge, which makes some sense.) 45 46 Here's how this test's groups (black-bordered sections) map to these cases: 47 * This test's 1st, 4th, 5th, and 8th groups are "case A". 48 * This test's 3rd and 6th groups are in "case B". 49 * This test's 2nd and 7th groups are in "case C". 50 51 [1] Known bugs referenced above, which cause parts of this test to fail in 52 WebKit and Blink: 53 https://bugs.webkit.org/show_bug.cgi?id=240128 54 https://bugs.chromium.org/p/chromium/issues/detail?id=1322774 55 https://bugs.chromium.org/p/chromium/issues/detail?id=1323004 56 --> 57 <script> 58 const MARGIN_VALS = [15, 22, 28]; 59 const HORIZ_SIDES = ["left", "right"]; // Used for 'float:*' and 'margin-*'. 60 const DIRECTION_VALS = ["ltr", "rtl"]; 61 62 function newDivWithClassAndParent(className, parent) { 63 let elem = document.createElement("div"); 64 if (className) { 65 elem.classList.add(className); 66 } 67 parent.appendChild(elem); 68 return elem; 69 } 70 function generateGroup(directionVal, floatVal, marginPropSuffix) { 71 let group = newDivWithClassAndParent("group", document.body); 72 group.style.direction = directionVal; 73 const marginPropName = "margin-" + marginPropSuffix; 74 75 for (let v of MARGIN_VALS) { 76 let container = newDivWithClassAndParent("container", group); 77 let float = newDivWithClassAndParent("float", container); 78 float.style.cssFloat = floatVal; 79 80 let bfc = newDivWithClassAndParent("bfc", container); 81 bfc.style[marginPropName] = v + "px"; 82 } 83 } 84 function go() { 85 for (let directionVal of DIRECTION_VALS) { 86 for (let floatVal of HORIZ_SIDES) { 87 for (let marginPropSuffix of HORIZ_SIDES) { 88 generateGroup(directionVal, floatVal, marginPropSuffix); 89 } 90 } 91 } 92 // Note: the "reftest-wait" usage here isn't strictly necessary; it just 93 // helps ensure that we actually make it through all of the above JS and 94 // populate this document with the content that we want to render. 95 // (Specifically: if we e.g. throw a JS exception somewhere early in both 96 // the testcase and reference case, then the "reftest-wait" class will 97 // never be removed; and that will cause the test run to be classified 98 // as a failure, rather than a trivial "pass" with a visual comparison of 99 // two blank documents.) 100 document.documentElement.removeAttribute("class"); 101 } 102 </script> 103 <style> 104 .group { 105 width: 300px; 106 border: 1px solid black; 107 } 108 .container { 109 /* This is the container that holds our float+bfc. We make it an 110 inline-block so that we can test a bunch of these in a row. */ 111 display: inline-block; 112 vertical-align: top; 113 width: 30px; 114 height: 40px; 115 /* This border and margin are just cosmetic, to avoid overlap between 116 * adjacent containers within a row. */ 117 border: 1px solid gray; 118 margin-left: 30px; 119 } 120 121 .float { 122 /* We'll set the float property elsewhere (to 'right' or 'left'). */ 123 width: 7px; 124 height: 8px; 125 background: fuchsia; 126 border: 1px solid purple; 127 /* Each .float's margin-box (which the corresponding .bfc's border-box cannot 128 * overlap) is 14px wide: 129 * 7px content + 2px horizontal border + 5px horizontal margin 130 * Note that we're intentionally using a nonzero 'margin' here, to be sure 131 * the UA is using the float's margin-box (and not one of its other 132 * boxes) for this non-overlapping calculation. */ 133 margin: 1px 3px 1px 2px; 134 } 135 .bfc { 136 /* Each .bfc's border-box width is 2px (from the border) plus whatever we 137 * resolve 'width:auto' to, which is influenced by the particular choice of 138 * 'margin' values (and the available space). */ 139 display: flow-root; 140 background: aqua; 141 height: 15px; 142 border: 1px solid blue; 143 } 144 </style> 145 <body onload="go()"> 146 </body> 147 </html>