Resolving Issues from Unexpected Changes to `container-type: inline-size` in Chrome 129
Chrome 129 introduced a change in the behavior of container queries affecting elements with container-type: inline-size
. This change, while small, has the potential to break your web app's layout. I'm going to go over what changed, how it behaved before, and how it behaves starting with Chrome 129.
What Changed?
Prior to Chrome 129, container-type: inline-size
implicitly:
- Created a containing block for absolutely positioned elements
- Established a new stacking context
To illustrate this, consider the following:
<!DOCTYPE html>
<html lang="en">
<head>
<style>
.container {
container-type: inline-size;
width: 300px;
height: 300px;
border: 2px solid black;
padding: 1rem;
margin: 2rem;
contain: layout;
}
.child,
.sibling {
position: absolute;
display: flex;
justify-content: center;
align-items: center;
color: white;
}
.child {
width: 200px;
height: 200px;
}
.child-1 {
background-color: rgba(255, 0, 0, 0.7);
top: 100px;
left: 100px;
z-index: 2;
}
.child-2 {
background-color: rgba(0, 255, 0, 0.7);
top: 30px;
left: 0;
z-index: 1;
}
.sibling {
width: 150px;
height: 150px;
background-color: rgba(0, 0, 255, 0.7);
top: 165px;
left: 50px;
z-index: 1;
}
</style>
</head>
<body>
<div class="container">
<div class="child child-1">Child 1 (z-index: 2)</div>
<div class="child child-2">Child 2 (z-index: 1)</div>
</div>
<div class="sibling">Sibling (z-index: 1)</div>
</body>
</html>
Before Chrome 129, the above code rendered as follows:
The children of the black-outlined .container
div are absolutely positioned. child-2
(the green div) is positioned left: 0
, however it aligns with the left-side boundaries of the parent .container
div. This is because in Chrome 128 and older, container-type: inline-size
implicitly created a containing block for absolutely positioned children.
Additionally, the container-type: inline-size
element is implicitly creating a new stacking context, resulting in green being on the bottom, red in the middle, and blue on top.
However, as of Chrome 129, the same HTML and CSS renders like so,
No containing block is created for the .container
element's children, and therefore the absolutely positioned elements are positioned relative to the web page rather than relative to their container. This results in the green square entirely escaping the container
and touching the left side of the web page.
Additionally, since no new stacking context was created, the order in which the children and siblings stack has changed. The green square is still on the bottom, but now the blue square is in the middle, and the red square is on top.
Why the Change?
According to the Chromium team on the official Chromium bug tracker this was an intentional change to fix what is considered by the team to be a design mistake in original specification.
The specification itself has yet to be updated, but the team made the change in the browser behavior prior to any change having been made in the specification due to agreement within the working-group.
As of the time of writing this article (October 3rd, 2024), all other major browsers (Firefox, Safari) still follow the pre-Chrome 129 behavior.
Mitigating the Changes
If you just want to restore things to how they were pre-Chrome 129 (and in the meantime maintain consistency across browsers until Firefox and Safari update to follow Chrome's implementation), you can simply add contain: layout;
to the element which has container-type: inline-size;
.
If you want to add the containing block behavior but not create a new stacking context, you could alternatively add position: relative
to the container-type: inline-size;
element, which will create a containing block for child elements but not create a new stacking context. However, this will result in different behavior in different browsers until the point that other browsers update to follow Chrome's lead.
Try It Yourself
Below is a CodePen that you can play with that demonstrates what I am talking about above. If you remove contain: layout
from the .container
style, and if you're using Chrome 129 or later, the layout will show as it does in the second image I provided above. However, if you view the CodePen in Firefox 131 (latest as of writing), it should display the same regardless of whether contain: layout
is set or not.
I wasn't able to find mention of this change in the release notes for Chrome 129, and as was already mentioned this change was made ahead of any specification change, so it really caught us off guard and significantly broke the layout on one of our web apps. I hope that this information can help anyone else having the same problems.
This article was originally published on dev.to.