demo · v130
shadow tree vs flat tree ancestry
The chromestatus motivation: "authors would expect queries to work on the box tree and not skip containers in shadow trees where elements in the ancestor chain were slotted in." Chrome 130 switches container-query ancestor lookup from the shadow-including tree to the flat tree, so a named container in the light DOM is now reachable from inside a shadow root that received slotted content from inside it.
500px
two trees, two answers
shadow-including tree (pre-Chrome 130)
.article-layout [container: article] └── #shadow-root (inline-banner) └── .slot-text @container article — no match └── <slot name="text"> └── <span> (slotted from light) .slot-text's ancestor chain in the shadow-including tree exits via #shadow-root. The query container .article-layout is reachable in DOM, but the ancestor walk passes through the shadow boundary and the named container is invisible.flat tree (Chrome 130+)
.article-layout [container: article] ├── .toolbar └── <inline-banner> └── .slot-text @container article — match └── <span> (slotted text — composed in) In the flat tree, slotted nodes are composed under the slot's host. .article-layout is a true flat-tree ancestor of .slot-text, so the named container query resolves and the styles apply.the code
// Light DOM
<div class="article-layout"> /* container-name: article; container-type: inline-size */
<inline-banner>
<span slot="text">...</span>
</inline-banner>
</div>
// Custom element shadow DOM
class InlineBanner extends HTMLElement {
connectedCallback() {
this.attachShadow({ mode: "open" }).innerHTML = `
<style>
.slot-text { padding: 1rem; background: var(--bg-paper); }
@container article (min-width: 600px) {
.slot-text { background: var(--accent-blue); color: var(--bg-paper); }
}
</style>
<div class="slot-text"><slot name="text"></slot></div>
`;
}
}
customElements.define("inline-banner", InlineBanner);
// Pre-Chrome 130: .slot-text's @container lookup walks shadow-including
// tree, hits the shadow root boundary, NEVER sees .article-layout.
// Styles inside the @container block are dead code.
// Chrome 130+: .slot-text's @container lookup walks the flat tree,
// finds .article-layout as a flat ancestor, queries match.