When a component flips classes at runtime, a container query can stop matching even when the DOM and sizes look fine. The root cause is often containment eligibility: the browser first finds an eligible container ancestor, then checks the axis or name your query uses. If the container’s container-type no longer supports the axis you ask for, there is simply no valid target and the query fails.
Implementation
- Decide which axis your queries use. Width-based checks use the inline axis; height-based checks use the block axis. Use container-type: size when you need both axes, or container-type: inline-size when you only ever need inline-axis queries.
- If you need to target a specific wrapper to avoid accidental matches, use container-name. Remember that naming preserves which container the browser will consider, but it does not add axis support.
- When refactoring or toggling classes, inspect the container ancestor at the exact moment of the change: is there still a qualifying container, does it have the expected name (if you rely on names), and does it support the axis you query?
Expected behavior
- With container-type: size, both inline (width) and block (height) queries can match the same container.
- With container-type: inline-size, inline-axis queries continue to work but block-axis queries will report no eligible container.
- Name-only queries can still resolve a named container regardless of axis, but axis-based checks still require the appropriate container-type.
Limitations
- This diagnosis demonstrates container eligibility logic. It does not replace checking your real page for selector specificity, layout overrides, or browser rendering differences.
- If a query fails because the container is too small, or because the element moved to a different ancestor chain, the correct fix is not always changing container-type.
The article includes a compact deterministic fixture that reproduces the toggle, shows the failing state, and demonstrates both repairs: keep an appropriate container-type for axis queries or use container naming for targeting problems. Use the fixture’s diagnostics to separate container discovery issues from axis-eligibility problems.
Working example
export function createElement({ tag = 'div', width = 0, height = 0 } = {}) {
return {
tag,
width,
height,
parent: null,
children: [],
containerType: 'normal',
containerName: undefined,
};
}
export function appendChild(parent, child) {
child.parent = parent;
parent.children.push(child);
}
export function setContainerType(el, type) {
el.containerType = type;
}
export function setContainerName(el, name) {
el.containerName = name;
}
export function toggleContainerType(el, nextType) {
setContainerType(el, nextType);
}
function compare(op, left, right) {
switch (op) {
case '>': return left > right;
case '>=': return left >= right;
case '<': return left < right;
case '<=': return left <= right;
default: throw new Error(`unsupported compare operator: ${op}`);
}
}
function queryAxis(query) {
if (query.kind === 'name-only') return null;
if (query.axis) return query.axis;
if (query.feature === 'width') return 'inline';
if (query.feature === 'height') return 'block';
return null;
}
export function findEligibleContainer(startEl, query) {
let node = startEl.parent;
const axis = queryAxis(query);
while (node) {
if (query.kind === 'name-only') {
if (node.containerName === query.name) return node;
} else if (axis) {
if (node.containerType === 'size') return node;
if (node.containerType === 'inline-size' && axis === 'inline') return node;
}
node = node.parent;
}
return null;
}
export function evaluateQuery(targetEl, query) {
const container = findEligibleContainer(targetEl, query);
if (!container) {
return { matched: false, reason: 'no-eligible-container', container: null };
}
if (query.kind === 'name-only') {
return { matched: true, container };
}
const axis = queryAxis(query);
const size = axis === 'inline' ? container.width : container.height;
return {
matched: compare(query.compare, size, query.value),
container,
containerValue: size,
};
}
Read the full article: https://chriseugenerodriguez.com/blog/why-do-container-queries-stop-matching-when-you-switch-container-type-dynamically
Top comments (0)