[csswg-drafts] [cssom-view] Spec for offsetTop/Left does not match implementations for `position:static` `<body>` element (#10549)

nicoburns has just created a new issue for https://github.com/w3c/csswg-drafts:

== [cssom-view] Spec for offsetTop/Left does not match implementations for `position:static` `<body>` element ==
## 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](https://www.w3.org/TR/cssom-view-1/#extensions-to-the-htmlelement-interface) 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](https://www.w3.org/TR/css3-positioning/#propdef-position) property is not [static](https://www.w3.org/TR/css3-positioning/#valdef-position-positionfake-maybe-placeholderstatic-fake-maybe-placeholder).
> 
> It is [the HTML body element](https://www.w3.org/TR/cssom-view-1/#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](https://www.w3.org/TR/cssom-view-1/#the-html-body-element) or does not have any associated [CSS layout box](https://www.w3.org/TR/cssom-view-1/#css-layout-box) return zero and terminate this algorithm.
> 
> If the [offsetParent](https://www.w3.org/TR/cssom-view-1/#dom-htmlelement-offsetparent) of the element is null return the y-coordinate of the top [border edge](https://www.w3.org/TR/cssom-view-1/#border-edge) of the first [CSS layout box](https://www.w3.org/TR/cssom-view-1/#css-layout-box) associated with the element, relative to the [initial containing block](https://www.w3.org/TR/css-display-3/#initial-containing-block) origin, ignoring any [transforms](https://www.w3.org/TR/cssom-view-1/#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](https://www.w3.org/TR/cssom-view-1/#padding-edge) of the first [CSS layout box](https://www.w3.org/TR/cssom-view-1/#css-layout-box) associated with the [offsetParent](https://www.w3.org/TR/cssom-view-1/#dom-htmlelement-offsetparent) of the element from the y-coordinate of the top [border edge](https://www.w3.org/TR/cssom-view-1/#border-edge) of the first [CSS layout box](https://www.w3.org/TR/cssom-view-1/#css-layout-box) associated with the element, relative to the [initial containing block](https://www.w3.org/TR/css-display-3/#initial-containing-block) origin, ignoring any [transforms](https://www.w3.org/TR/cssom-view-1/#transforms) that apply to the element and its ancestors.

## Test Case
```html
<!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 browsers are returning the offset 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](https://www.w3.org/TR/cssom-view-1/#extensions-to-the-htmlelement-interface) and the [css-flexbox spec](https://www.w3.org/TR/css-flexbox-1/) cannot pass those tests.

Either the spec or browser behaviour ought to be updated.

## 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?

Please view or discuss this issue at https://github.com/w3c/csswg-drafts/issues/10549 using your GitHub account


-- 
Sent via github-notify-ml as configured in https://github.com/w3c/github-notify-ml-config

Received on Wednesday, 10 July 2024 00:03:32 UTC