[csswg-drafts] [css-overflow][css-contain][css-sizing] `overflow: auto` incompatible with size containment and container queries (#7875)

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

== [css-overflow][css-contain][css-sizing] `overflow: auto` incompatible with size containment and container queries ==
## Context

Elements with `overflow: auto` only get a scrollbar when the contents overflow. Classic scrollbars take some space, so this affects sizing [this way](https://w3c.github.io/csswg-drafts/css-overflow-3/#scrollbar-layout): 

> When the box is intrinsically sized, this reserved space is added to the size of its contents. It is otherwise subtracted from space alotted to the [content area](https://w3c.github.io/csswg-drafts/css-box-4/#content-area). To the extent that the presence of scrollbars can affect sizing, UAs must start with the assumption that no scrollbars are needed, and recalculate sizes if it turns out they are.

[For example](https://software.hixie.ch/utilities/js/live-dom-viewer/?%3C!DOCTYPE%20html%3E%0A%3Cstyle%3E%0Adiv%20%7B%20overflow%3A%20auto%3B%20background%3A%20cyan%3B%20vertical-align%3A%20top%3B%20%7D%0Adiv%3A%3Abefore%20%7B%20content%3A%20%22%22%3B%20display%3A%20block%3B%20height%3A%20200px%3B%20width%3A%20200px%3B%20%7D%0A%3C%2Fstyle%3E%0A%3Cdiv%20style%3D%22display%3A%20inline-block%3B%20height%3A%20100px%3B%20width%3A%20100px%22%3E%3C%2Fdiv%3E%0A%3Cdiv%20style%3D%22display%3A%20inline-grid%3B%20grid-template%3A%20100px%20%2F%20100px%22%3E%3C%2Fdiv%3E):

```html
<style>
div { overflow: auto; background: cyan; vertical-align: top; }
div::before { content: ""; display: block; height: 200px; width: 200px; }
</style>
<div style="display: inline-block; height: 100px; width: 100px"></div>
<div style="display: inline-grid; grid-template: 100px / 100px"></div>
```
![](https://user-images.githubusercontent.com/7477678/195437734-71f00bf3-9ebc-4d02-a17c-443e078c0fe1.png)

Note that only Blink has this behavior, Gecko ([bug 764076](https://bugzilla.mozilla.org/show_bug.cgi?id=764076)) and WebKit don't: in the intrinsic case, the content area (without the scrollbar) is 100px tall indeed, but is less than 100px wide.

Tip: to force classical scrollbars if your UA uses overlay ones, in Firefox go to `about:config` and create a number pref `ui.useOverlayScrollbars` set to `0`. In Blink/WebKit add this CSS:
```css
::-webkit-scrollbar { background-color: #eff0f1; width: 12px; height: 12px; }
::-webkit-scrollbar-thumb { background: #898c8d; }
```

## Incompatibility with size containment

In short, with `overflow: auto` the contents can affect either the inner or the outer size of the element. This is a problem with size containment (when paired with layout containment), which should allow [this optimization](https://w3c.github.io/csswg-drafts/css-contain-2/#containment-size-opt):

> When the style or contents of a descendant of the [containment box](https://w3c.github.io/csswg-drafts/css-contain-2/#size-containment-box) is changed, calculating what part of the DOM tree is "dirtied" and might need to be re-laid out can stop at the containment box.

This is not true if the element is sized intrinsically: a change in the descendants may trigger or untrigger a scrollbar, affecting the outer size, and potentially the ancestors.

Blink and WebKit assume it's fine to apply the optimization... with clear wrong results. See [this testcase](https://software.hixie.ch/utilities/js/live-dom-viewer/?%3C!DOCTYPE%20html%3E%0A%3Cstyle%3E%0A.size%20%7B%20width%3A%20200px%3B%20height%3A%20200px%3B%7D%0A%3C%2Fstyle%3E%0A%3Cbutton%20onclick%3D%22document.getElementById(%27contents%27).classList.toggle(%27size%27)%22%3EChange%20contents%3C%2Fbutton%3E%0A%3Cbutton%20onclick%3D%22document.body.style.display%20%3D%20%27none%27%3B%20document.body.offsetLeft%3B%20document.body.style.display%20%3D%20%27%27%22%3EFull%20layout%3C%2Fbutton%3E%0A%3Cdiv%20style%3D%22width%3A%20max-content%3B%20border%3A%20solid%22%3E%0A%20%20%3Cdiv%20style%3D%22display%3A%20grid%3B%20grid-template%3A%20100px%20%2F%20100px%3B%20overflow%3A%20auto%3B%20contain%3A%20strict%22%3E%0A%20%20%20%20%3Cdiv%20id%3D%22contents%22%3E%3C%2Fdiv%3E%0A%20%20%3C%2Fdiv%3E%0A%3C%2Fdiv%3E%0A):

![](https://user-images.githubusercontent.com/7477678/195449007-00c3bb3c-6585-4993-b3f1-72df32c7ea15.gif)

The testcase above won't work in Firefox due to [bug 1488878](https://bugzilla.mozilla.org/show_bug.cgi?id=1488878), but the same problem can be seen with `contain-intrinsic-size`. [CSS Sizing](https://w3c.github.io/csswg-drafts/css-sizing-4/#cis-scrollbars) tries to define some interaction between `contain-intrinsic-size` and `overflow: auto`, but it has some problems (#7867, #7868) and I think the behavior should be the usual one, just with a custom intrinsic size. Here is the [testcase](https://software.hixie.ch/utilities/js/live-dom-viewer/?%3C!DOCTYPE%20html%3E%0A%3Cstyle%3E%0A.size%20%7B%20width%3A%20200px%3B%20height%3A%20200px%3B%7D%0A%3C%2Fstyle%3E%0A%3Cbutton%20onclick%3D%22document.getElementById(%27contents%27).classList.toggle(%27size%27)%22%3EChange%20contents%3C%2Fbutton%3E%0A%3Cbutton%20onclick%3D%22document.body.style.display%20%3D%20%27none%27%3B%20document.body.offsetLeft%3B%20document.body.style.display%20%3D%20%27%27%22%3EFull%20layout%3C%2Fbutton%3E%0A%3Cdiv%20style%3D%22width%3A%20max-content%3B%20border%3A%20solid%22%3E%0A%20%20%3Cdiv%20style%3D%22overflow%3A%20auto%3B%20contain%3A%20strict%3B%20contain-intrinsic-size%3A%20100px%20100px%22%3E%0A%20%20%20%20%3Cdiv%20id%3D%22contents%22%3E%3C%2Fdiv%3E%0A%20%20%3C%2Fdiv%3E%0A%3C%2Fdiv%3E%0A) with `contain-intrinsic-size`:

![](https://user-images.githubusercontent.com/7477678/195450622-cf2c620d-0899-4534-b8ce-629e894ede06.gif)

## Circularity with container queries

So far, we have seen that we shouldn't allow the contents of an element with size containment to affect its outer size. Could we maybe say that the scrollbar should shrink the inner size to preserve the outer size, even when sizing intrinsically? No, because that would create a circularity with container queries, because of https://w3c.github.io/csswg-drafts/css-contain-3/#width

> The [`width`](https://w3c.github.io/csswg-drafts/css-contain-3/#descdef-container-width) [container feature](https://w3c.github.io/csswg-drafts/css-contain-3/#container-feature) queries the [width](https://w3c.github.io/csswg-drafts/css-sizing-3/#width) of the [query container](https://w3c.github.io/csswg-drafts/css-contain-3/#query-container)’s [content box](https://w3c.github.io/csswg-drafts/css-box-4/#content-box).

I have checked how Blink handles the circularity. It turns out it queries the size of the content area plus the scrollbar. Oddly, this happens even with `overflow: scroll` or when sizing intrinsically with `overflow: auto`. [Testcase](https://software.hixie.ch/utilities/js/live-dom-viewer/?%3C!DOCTYPE%20html%3E%0A%3Cstyle%3E%0A.wrapper%20%7B%20display%3A%20inline-block%3B%20border%3A%20solid%3B%20vertical-align%3A%20top%3B%20%7D%0A.container%20%7B%20container-type%3A%20size%3B%20%7D%0A.contents%20%7B%20width%3A%2050px%3B%20height%3A%2050px%3B%20%7D%0A.size%20.contents%20%7B%20width%3A%20200px%3B%20height%3A%20200px%3B%7D%0A%40container%20(inline-size%20%3D%20100px)%20%7B%0A%20%20.contents%20%7B%20background%3A%20cyan%20%7D%0A%7D%0A%40container%20(inline-size%20%3E%20100px)%20%7B%0A%20%20.contents%20%7B%20background%3A%20magenta%20%7D%0A%7D%0A%3C%2Fstyle%3E%0A%3Cbutton%20onclick%3D%22document.body.classList.toggle(%27size%27)%22%3EChange%20contents%3C%2Fbutton%3E%0A%3Cbutton%20onclick%3D%22document.body.style.display%20%3D%20%27none%27%3B%20document.body.offsetLeft%3B%20document.body.style.display%20%3D%20%27%27%22%3EFull%20layout%3C%2Fbutton%3E%0A%3Cbr%3E%0A%3Cdiv%20class%3D%22wrapper%22%3E%0A%20%20%3Cdiv%20class%3D%22container%22%20style%3D%22overflow%3A%20scroll%3B%20width%3A%20100px%3B%20height%3A%20100px%22%3E%0A%20%20%20%20%3Cdiv%20class%3D%22contents%22%3E%3C%2Fdiv%3E%0A%20%20%3C%2Fdiv%3E%0A%3C%2Fdiv%3E%0A%3Cdiv%20class%3D%22wrapper%22%3E%0A%20%20%3Cdiv%20class%3D%22container%22%20style%3D%22overflow%3A%20scroll%3B%20contain-intrinsic-size%3A%20100px%22%3E%0A%20%20%20%20%3Cdiv%20class%3D%22contents%22%3E%3C%2Fdiv%3E%0A%20%20%3C%2Fdiv%3E%0A%3C%2Fdiv%3E%0A%3Cdiv%20class%3D%22wrapper%22%3E%0A%20%20%3Cdiv%20class%3D%22container%22%20style%3D%22overflow%3A%20auto%3B%20width%3A%20100px%3B%20height%3A%20100px%22%3E%0A%20%20%20%20%3Cdiv%20class%3D%22contents%22%3E%3C%2Fdiv%3E%0A%20%20%3C%2Fdiv%3E%0A%3C%2Fdiv%3E%0A%3Cdiv%20class%3D%22wrapper%22%3E%0A%20%20%3Cdiv%20class%3D%22container%22%20style%3D%22overflow%3A%20auto%3B%20contain-intrinsic-size%3A%20100px%22%3E%0A%20%20%20%20%3Cdiv%20class%3D%22contents%22%3E%3C%2Fdiv%3E%0A%20%20%3C%2Fdiv%3E%0A%3C%2Fdiv%3E%0A%0A)

![](https://user-images.githubusercontent.com/7477678/195456958-9a51f590-d797-4a0c-b95e-782da7a6bc76.gif)

 - 1st is extrinsic `overflow: scroll`. It matches `inline-size = 100px` despite the content area being narrower.
 -  2nd is intrinsic `overflow: scroll`. It matches `inline-size > 100px` despite the content area being 100px.
 -  3rd is extrinsic `overflow: auto`. It matches `inline-size = 100px` despite the content area being narrower when there is a scrollbar.
 -  4th is intrinsic `overflow: auto`. It matches `inline-size = 100px` when there is no scrollbar, and matches `inline-size > 100px` when there is a scrollbar despite the content area being 100px. Thus it would be circular, but due to the wrong optimization described above, the circularity is only apparent when forcing layout.

Well, I guess that does the trick to avoid circularities, but all of this seems very buggy and hacky.

## Possible solution

I'm leaning towards simply saying that size containment forces `overflow: auto` to behave as `overflow: scroll`.

Or maybe something like `scrollbar-gutter: stable` but without adding the gutter for `overflow: hidden`, and affecting both the inline and block axes.

CC @frivoal 

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


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

Received on Wednesday, 12 October 2022 22:26:56 UTC