Description
Context
This issue was discovered when trying to run unrelated WPT tests (css-flexbox tests) in Servo. It turns out that many of them depend on this non-standard behaviour. For example https://wpt.live/css/css-flexbox/align-content-horiz-001b.html
Specification
The spec says:
offsetParent
The offsetParent attribute must return the result of running these steps:
...
Return the nearest ancestor element of the element for which at least one of the following is true and terminate this algorithm if such an ancestor is found:
The computed value of the position property is not static.
It is the HTML body element.
...
offsetTop/offsetLeft
The offsetTop attribute must return the result of running these steps:
If the element is the HTML body element or does not have any associated CSS layout box return zero and terminate this algorithm.
If the offsetParent of the element is null return the y-coordinate of the top border edge of the first CSS layout box associated with the element, relative to the initial containing block origin, ignoring any transforms that apply to the element and its ancestors, and terminate this algorithm.
Return the result of subtracting the y-coordinate of the top padding edge of the first CSS layout box associated with the offsetParent of the element from the y-coordinate of the top border edge of the first CSS layout box associated with the element, relative to the initial containing block origin, ignoring any transforms that apply to the element and its ancestors.
Test Case
<!doctype html>
<html>
<body id="body" onload="recompute()">
<div id="target" style="height: 40px; width: 40px; background: red;"></div>
<div id="output" style="text-wrap: nowrap"></div>
<button onclick="recompute()">recompute</button>
<script type="text/javascript">
function recompute() {
let targetNode = document.getElementById("target");
let outputNode = document.getElementById("output");
outputNode.innerHTML = `
offsetParent: ${targetNode.offsetParent.id}<br />
offsetTop: ${targetNode.offsetTop}<br />
offsetLeft: ${targetNode.offsetLeft}<br />
`;
}
</script>
</body>
</html>
Per the spec, the offsetParent
for #target
ought to be the <body>
element. And therefore the offsetTop
and offsetLeft
both ought to be 0. However, actual browsers (tested Chrome 126.0.6478.127, Firefox 127.0.2, Safari 17.5) return 8 for both properties.
The actual observed behaviour seems to be that while browsers are correctly returning the <body>
element as the offsetParent
, they are actually computing the offsetLeft
/offsetTop
offsets relative to the border-edge of the <html>
element rather than the padding-edge of the <body>
element in this case.
(note that this is only the case if the <body>
is position: static
. If the <body>
is position: relative
then all browsers return 0 as per the spec).
Implications
This issue affects a number of of WPT tests and means that browsers that conform to both the offsetTop/offsetLeft spec and the css-flexbox spec cannot pass those tests.
Either the spec or browser behaviour ought to be updated.
In css-flexbox
, the following tests use data-offset-x
/data-offset-y
assertions and are potentially affected (but will only be affected if these are used with an offsetParent
that corresponds to the <body>
:
percentage-padding-001.html:1
inline-flex.html:3
column-reverse-gap.html:3
intrinsic-size/col-wrap-018.html:1
intrinsic-size/col-wrap-019.html:3
relayout-align-items.html:14
align-items-baseline-vert-rl-column-horz-flexbox-item.html:2
align-items-baseline-vert-rl-column-horz-table-item.html:2
flex-flow-013.html:32
align-items-baseline-vert-lr-column-horz-table-item.html:2
inline-flexbox-wrap-vertically-width-calculation.html:64
intrinsic-size/col-wrap-004.html:1
align-items-baseline-vert-lr-column-horz-flexbox-item.html:2
intrinsic-size/col-wrap-005.html:1
align-items-baseline-column-vert-rl-items.html:2
align-content-wrap-003.html:120
align-items-baseline-column-vert-lr-items.html:2
multiline-min-max.html:56
align-items-baseline-vert-lr-column-horz-items.html:2
align-content-wmvert-001.html:54
align-items-baseline-column-vert-lr-table-item.html:2
position-relative-percentage-top-001.html:1
flexbox_justifycontent-rtl-001.html:12
align-content-vert-001a.html:54
flex-factor-less-than-one.html:3
align-content-wrap-005.html:8
flexitem-no-margin-collapsing.html:2
align-items-baseline-column-vert-lr-flexbox-item.html:2
align-content-horiz-001a.html:54
percentage-heights-000.html:18
fieldset-as-container-justify-center.tentative.html:1
align-items-baseline-column-vert-rl-table-item.html:2
align-content-horiz-002.html:54
align-content-horiz-001b.html:54
flexbox_justifycontent-rtl-002.html:12
justify-content-007.html:1
abspos/position-absolute-001.html:2
abspos/flex-abspos-staticpos-justify-content-vertWM-001.html:24
align-content-vert-001b.html:54
align-items-baseline-vert-rl-column-horz-grid-item.html:2
abspos/flex-abspos-staticpos-align-self-rtl-004.html:24
abspos/position-absolute-012.html:2
abspos/flex-abspos-staticpos-justify-content-007.html:24
abspos/flex-abspos-staticpos-justify-content-002.html:24
abspos/flex-abspos-staticpos-align-self-vertWM-002.html:28
abspos/flex-abspos-staticpos-align-self-002.html:24
overflow-auto-003.html:1
abspos/position-absolute-002.html:39
abspos/flex-abspos-staticpos-justify-content-004.html:24
abspos/flex-abspos-staticpos-justify-content-008.html:24
abspos/flex-abspos-staticpos-justify-content-vertWM-002.html:24
abspos/flex-abspos-staticpos-align-self-003.html:24
align-content-wrap-001.html:13
abspos/flex-abspos-staticpos-align-self-001.html:24
abspos/flex-abspos-staticpos-align-self-vertWM-004.html:24
abspos/flex-abspos-staticpos-justify-content-rtl-002.html:24
abspos/flex-abspos-staticpos-justify-content-005.html:24
abspos/flex-abspos-staticpos-align-self-005.html:24
abspos/flex-abspos-staticpos-justify-content-rtl-001.html:24
abspos/position-absolute-015.html:1
abspos/flex-abspos-staticpos-align-self-rtl-001.html:24
abspos/flex-abspos-staticpos-align-self-006.html:24
justify-content-006.html:1
abspos/flex-abspos-staticpos-align-self-rtl-002.html:24
abspos/flex-abspos-staticpos-align-self-008.html:24
abspos/flex-abspos-staticpos-align-self-007.html:24
abspos/flex-abspos-staticpos-align-self-004.html:24
abspos/flex-abspos-staticpos-align-self-vertWM-003.html:24
abspos/flex-abspos-staticpos-align-content-001.html:24
abspos/position-absolute-003.html:16
abspos/flex-abspos-staticpos-justify-content-003.html:24
abspos/position-absolute-013.html:2
abspos/flex-abspos-staticpos-align-self-rtl-003.html:24
abspos/flex-abspos-staticpos-justify-content-001.html:24
abspos/flex-abspos-staticpos-align-self-vertWM-001.html:28
abspos/flex-abspos-staticpos-justify-content-006.html:24
box-sizing-001.html:2
align-self-014.html:2
flexbox_justifycontent-center-overflow.html:3
align-items-baseline-vert-lr-column-horz-grid-item.html:2
alignment/flex-align-baseline-overflow-001.html:12
alignment/flex-align-baseline-multicol-001.html:12
align-content-vert-002.html:54
alignment/flex-align-baseline-grid-001.html:12
alignment/flex-align-baseline-line-clamp-001.tentative.html:24
alignment/flex-align-baseline-002.html:6
alignment/flex-align-baseline-fieldset-002.html:4
alignment/flex-align-baseline-fieldset-003.html:4
alignment/flex-align-baseline-003.html:6
alignment/flex-align-baseline-004.html:6
alignment/flex-align-baseline-line-clamp-002.tentative.html:24
alignment/flex-align-baseline-flex-003.html:16
alignment/flex-align-baseline-007.html:3
alignment/flex-align-baseline-flex-001.html:48
alignment/flex-align-baseline-fieldset-001.html:4
alignment/flex-align-baseline-table-003.html:4
alignment/flex-align-baseline-line-clamp-003.tentative.html:24
alignment/flex-align-baseline-table-001.html:8
alignment/flex-align-baseline-grid-003.html:12
alignment/flex-align-baseline-005.html:3
alignment/flex-align-baseline-table-002.html:4
alignment/flex-align-baseline-flex-004.html:16
alignment/flex-align-baseline-006.html:3
alignment/flex-align-baseline-flex-002.html:48
alignment/flex-align-baseline-multicol-003.html:12
alignment/flex-align-baseline-overflow-003.html:12
align-items-baseline-column-vert-rl-flexbox-item.html:2
alignment/flex-align-baseline-001.html:6
alignment/flex-align-baseline-overflow-002.html:12
alignment/flex-align-baseline-multicol-002.html:12
alignment/flex-align-baseline-grid-002.html:12
flexbox-justify-content-wmvert-003.html:4
align-items-baseline-column-vert-lr-grid-item.html:2
align-items-baseline-vert-rl-column-horz-items.html:2
flexbox-justify-content-wmvert-002.html:4
align-items-baseline-column-vert-rl-grid-item.html:2
Questions
- Would PRs to update affected WPT tests to not depend on this behaviour (by adding
position:relative
to the<body>
and updating the expected offset values to match) be likely to be accepted?
Metadata
Metadata
Assignees
Type
Projects
Status