Why We Need a New Mechanism for Controlling Scrollable Overflow Contribution
CSS is designed to ensure that content is visible, accessible, and usable by default. When it comes to scroll containers, this means that all descendant boxes should be viewable unless they are explicitly hidden. To achieve this, the scrollbars in the container must allow the user to scroll around and see all the child elements.
However, there are cases such as decorative elements where we don’t necessarily want the entire element to be visible. In this post, we’ll discuss ways to prevent the scrollable area from being extended. We will also explore why we need a new way to control which elements will extend the scrollable area.
The scrollable overflow area
The rectangular area that the user can scroll around is called the scrollable overflow rectangle, and it should be the smallest rectangle that can contain all the descendant boxes while still aligning with the container’s axes. The combined area of all the descendant boxes is known as the scrollable overflow area.
As an example, lets take a scroll container that has a fixed size of 200px by 200px
.
It contains an element with dimensions of 50px by 50px
that is absolutely positioned at top: "200px; left:200px;
.
The scrollable overflow area will include the absolutely positioned child box,
and thus the scrollable overflow rectangle will have to be at least 250px by 250px
large.
The negative scrollable overflow region
An area that automatically extends to contain your content is great, but what if you want to fully or partially hide some content from visual readers?
One hack that was used historically was to place it beyond the top left corner. Browsers didn’t provide a scrolling mechanism to access this area. This meant that the content would be hidden from visible readers while remaining accessible to screen readers and search engines.
This corner is called the scroll origin, and as browsers now support different writing modes it will change position based on the writing mode. The area beyond this corner is called the negative scrollable overflow region, and due to web compatibility the scrollable area will not be extended into this region.
While the negative scrollable overflow region can be used to partially or fully hide content, it’s not very practical to use it for this purpose. However, knowing that this region exists can help you understand why content sometimes is hidden and why the scrollable area is not extended to make it visible.
I hope that we can extend the scrollable area into this region in the future, as this could be beneficial for some scroll snapping use cases.
Hiding or clipping overflow
If we add a decorative element along one of the edges of our scroll container,
the scrollable area will grow to show the entire element, something that we didn’t intend.
We can prevent this by using CSS’s aptly named overflow
property, which we’re already using to make the container scrollable.
We can clip the scrollable overflow area using overflow: hidden
or, even better, overflow: clip
.
The former allows scrolling by script, while the latter clips the overflow without creating a scroll container.
However, we can’t use these properties directly on our scrollable container because they would prevent scrolling.
Instead, we need to introduce a new element to contain the overflow.
Support for clip
is growing, but you should probably add a fallback to hidden
for older browsers.
While this is inconvenient, we can live with it.
But what if we could simply mark the decorative element as something that shouldn’t contribute to the scrollable overflow area?
This is the idea behind a proposed new CSS property, overflow-contribution: none
. Check out the proposal here.
When clipping breaks the content
While overflow: clip
can be a useful tool for preventing elements from contributing to the scrollable overflow area,
it has some limitations when it comes to 3D rendering contexts.
In a 3D rendering context, elements can be transformed in three dimensions, creating a sense of depth and perspective on the page.
However, when an element with overflow: clip
is inserted into a scroll container that creates a 3D rendering context,
it prevents the descendant elements from participating in that context.
The result can be seen in the example below, where you can toggle overflow: clip
on an element to see how it breaks the 3D rendering context.
This limitation occurs because overflow: clip
(and overflow: hidden
) are grouping property values that require the browser to create a flattened representation of the element before they can be applied.
This forces the used value of preserve-3d
to be flat
, effectively preventing the descendant elements from participating in the 3D rendering context.
As a result, overflow: clip
and overflow: hidden
cannot be used to prevent the elements from extending the scrollable overflow area in a 3D rendering context.
We have to explore other options to control the scrollable overflow region.
Are there any other solutions?
Currently, there are no known solutions to prevent 3D transformed elements from contributing to scrollable overflow. The only option is to size these elements to fit within the scrollable overflow area needed by the main content.
Unfortunately, only Firefox seem to take the perspective transform into account when calculating the size of the scrollable overflow area. In other browsers the scrollable overflow area are extended without taking perspective and the current scrollTop into account.
In the example below we have sized the content participating in the 3d rendering context so that it will not extend the scrollable overflow area when scrolled all the way to the right. As we mentioned above, only Firefox will calculate the scrollable overflow area correctly.
If you want browsers to handle perspective when calculating scrollable overflow, you should star these issues: 643213 1264086 1011442
Calculating the appropriate size of a z-translated element to fit within the main content is a topic for a future post..
Could there be a better solution?
For some content, there’s no need to extend the scrollable overflow area. If we could mark these elements, the browser could simply skip them when calculating the scrollable overflow area. This would save resources as well as solving our problem.
I have proposed to add a method to prevent elements from contributing to scrollable overflow, and the CSS Working Group has fortunately resolved to add such a feature.
One day in the future we might be able to mark elements using overflow-contribution: none
, contain: overflow-contribution
or something similar.
TL;DR
By default, the scrollable overflow area of a scroll container extends to include all descendant elements.
While we can use overflow: clip
and overflow: hidden
to somewhat control this area,
it might require adding extra elements
and cannot be used if descendant elements are participating in a 3d rendering context created by the scroll container.
To address this issue I have argued for the need to mark elements that should not contribute to the scrollable overflow area by setting a property like overflow-contribution: none
.
Fortunately, the CSSWG has resolved to add such a feature to CSS Overflow Module Level 4.