GoogleChromeLabs/container-query-polyfill

Support for non-trivial CSS Selectors

devknoll opened this issue · 2 comments

The polyfill can't currently handle each and every non-trivial CSS selector it might encounter. For example, consider the following rule:

#foo[data-bar] + div {
  container-type: inline-size;
}

Today, the polyfill is only guaranteed to correctly update this style when div is added, removed, or changed. It should also be updated when, for example, #foo is added, removed, or changed, or any siblings after #foo are added/removed/changed. The challenge, however, is that there's no simple way to detect when specific CSS property changes anywhere in the tree.

This is a performance trade-off. This issue could be resolved by revalidating the entire DOM after every mutation, but this would likely be prohibitively expensive in today's browsers for non-trivial documents. One promising optimization may be to instead keep track of just the selectors that change the properties we're interested in (e.g. #foo[data-bar] + div) and revalidate the delta of elements before and after the change.

Note: The CSS contain property doesn't help us here, as this relates to how CSS properties affect different parts of the tree, not the selectors that apply them. Here, the CSS properties affect the tree correctly, the polyfill is just unable to react to all of those changes.

Note: It's not sufficient to just invalidate the parent of a changed element, because you could write e.g. #foo:has(> #bar) + div. Invalidating all of the parents would be equivalent to invaliding the entire DOM.

Would the pattern of creating a MutationObserver per controller be a viable option for solving this? That pattern seemingly works well in the ShadowRootController but I am not sure if there are any potential limitations/performance concerns with that approach.

The problem is more that when e.g. #foo changes, we don't currently know that the sibling div could also be affected.

The approach of keeping track of the selectors that affect container or writing-mode properties is probably the way forward. In addition to helping removing this limitation, using it to filter the set of elements we compute the state for would improve performance quite a bit on lower-end devices.