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.

Scrollable overflow area will extend to include positioned element ↘
The scrollable overflow rectangle is extended to include the absolute positioned element at (200px, 200px). Scroll down to the bottom right corner to see the absolute positioned element.

 

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.

Scrollable overflow area will not include element positioned beyond the scroll origin ↖
Example showing that the scrollable overflow rectangle is not extended to include the absolute positioned box at (-200px, -200px).

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.

Overflow hidden will clip the absolute positioned element, so that it does not contribute to the scrollable overflow area of the scroll container.
Overflow
⚠ This demo requires support for the `:has()` relational pseudo-class.
An extra element with overflow: clip can be used to prevent a descendant element from extending the scrollable overflow rectangle. Use the radio-buttons to toggle between overflow: clip and overflow: visible to see the effect.

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.

Scrollable overflow
Overflow
⚠ This demo requires support for the `:has()` relational pseudo-class.
Scroll to the right to see how far the scrollable overflow area has been extended. With overflow: clip the scrollable overflow area is prevented from growing to include the background elements, but it removes the background elements from the 3d rendering context. Without overflow: clip the scrollable overflow area is extended to show all the background elements, something that is not desired.
Illustration: Created with the assistance of DALL·E 2

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..

Scrollable overflow
Scroll to the right to see how far the scrollable overflow area has been extended. The background elements are sizes so that they will not extend further than the main content when scrolled to the right. Unfortunately only Firefox seem to take the perspective transform into account when extending the scrollable overflow area.
Illustration: Created with the assistance of DALL·E 2

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.