Source code
Revision control
Copy as Markdown
Other Tools
Test Info:
- This WPT test may be referenced by the following Test IDs:
- /css/CSS2/floats/float-dynamic-formatting-context.html - WPT Dashboard Interop Dashboard
<!doctype html>
<meta charset="utf-8">
<title>CSS Floats: a laid-out formatting context can become floated</title>
<link rel="author" href="mailto:102797145+mxmgorin@users.noreply.github.com" title="Maxim Gorin">
<meta name="assert" content="An element that has already been laid out in flow still generates a box after it is floated, whatever formatting context it establishes.">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<body>
<script>
// Each case is laid out in flow before being floated; the resulting box
// determines the incremental path, making these displays more interesting
// than a single div.
const DISPLAYS = ["block", "flex", "grid", "flow-root", "inline-flex"];
const FLOATS = ["left", "right"];
const CONTAINING_BLOCK_WIDTH = 300;
const ELEMENT_WIDTH = 50;
const ELEMENT_HEIGHT = 60;
const SIBLING_HEIGHT = 20;
function laidOutElement(t, tagName, display) {
const container = document.createElement("div");
container.style.width = `${CONTAINING_BLOCK_WIDTH}px`;
document.body.appendChild(container);
t.add_cleanup(() => container.remove());
const element = document.createElement(tagName);
element.style.display = display;
element.style.width = `${ELEMENT_WIDTH}px`;
element.style.height = `${ELEMENT_HEIGHT}px`;
container.appendChild(element);
// A float no longer contributes to the block box of this sibling, so the
// sibling reports whether the element is still in flow.
const sibling = document.createElement("div");
sibling.style.height = `${SIBLING_HEIGHT}px`;
container.appendChild(sibling);
// Forces layout, so the change below is incremental rather than part of the
// element's initial layout.
assert_equals(element.getBoundingClientRect().height, ELEMENT_HEIGHT,
"the element has a box while it is in flow");
assert_greater_than(sibling.getBoundingClientRect().top,
container.getBoundingClientRect().top,
"the in-flow element pushes its sibling down");
return { container, element, sibling };
}
function assertFloatedTo(container, element, sibling, float) {
const containerRect = container.getBoundingClientRect();
const expectedLeft = float === "right"
? containerRect.left + CONTAINING_BLOCK_WIDTH - ELEMENT_WIDTH
: containerRect.left;
const rect = element.getBoundingClientRect();
assert_equals(rect.left, expectedLeft, "left");
assert_equals(rect.width, ELEMENT_WIDTH, "width");
assert_equals(rect.height, ELEMENT_HEIGHT, "height");
assert_equals(sibling.getBoundingClientRect().top, containerRect.top,
"the sibling no longer follows the element in flow");
}
for (const float of FLOATS) {
for (const display of DISPLAYS) {
test(t => {
const { container, element, sibling } = laidOutElement(t, "div", display);
element.style.float = float;
assertFloatedTo(container, element, sibling, float);
}, `display: ${display} gets float set to ${float}`);
}
// A block-level replaced element is an independent formatting context too, and
// reaches the same path as the containers above.
test(t => {
const { container, element, sibling } = laidOutElement(t, "canvas", "block");
element.style.float = float;
assertFloatedTo(container, element, sibling, float);
}, `block-level canvas gets float set to ${float}`);
}
</script>