Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[cssom] There should be a way to test CSSStyleRules against Elements #10470

Open
Kilian opened this issue Jun 19, 2024 · 8 comments
Open

[cssom] There should be a way to test CSSStyleRules against Elements #10470

Kilian opened this issue Jun 19, 2024 · 8 comments
Labels
cssom-1 Current Work

Comments

@Kilian
Copy link

Kilian commented Jun 19, 2024

To determine whether a given CSSStyleRule applies to a DOM element you can take its selectorText and use the element.matches() DOM API to check whether that selector applies to it. Doing so hasn't been sufficient for a long time:

  • It might be in a media query, or in a <style> or <link> element with a media attribute
  • It might be in a container query.
  • It might be inside a supports at-rule.
  • It might be nested, so its selectorText is incomplete on its own and potentially including &.
  • It might be inside a scope, either explicitly or implicitly, the selectortext potentially including :scope.

For media queries there is window.matchMedia(), for container queries there is going to be element.matchContainer(), for @supports there is CSS.supports(). This means you can at least get the information, but you will still need to walk the CSSOM to find conditionTexts to match against. (It seems that media and supports at-rules are getting a .matches property as discussed in #4240. This would be easier.)

For nesting and scoping however, you will need to walk the CSSOM and build up a complete, potentially very complex, selector to test against and, in the case of implicit scoping, also check the DOM and determine a selector to use for the common ancestor. This is far from ideal. For nesting this could potentially be solved with a resolved selectorText like discussed in #10246, but that wouldn't account for scoping.

All situations require you to loop over at least all ancestors in the CSSOM to get a full picture for a single CSSStyleRule, and potentially switching over to the DOM for attributes or common ancestors.

Proposal

The addition of a new API that explicitly tests if a given CSSStyleRule applies to a given Element with an optional pseudo-state (or class).

Applies here means that the content of the CSSStyleRule is used when determining the style of an element, regardless of whether the declarations inside the rule actually end up being used or are overwritten by style with higher specificity.

CSSStyleRule currently does not expose any functions so it makes sense to add a new method to the Element instead, possibly called matchRule(), that takes a CSSStyleRule and an optional second string argument indicating the pseudo state or element to match against, and returns a boolean value.

/* Match against the element itself */
Element.matchRule(CSSStyleRule);

/* Match against the element in hover state */
Element.matchRule(CSSStyleRule, ':hover');


/* Match against the element's first-letter */
Element.matchRule(CSSStyleRule, '::first-letter');

Alternatively, when matching for example a p against a CSSStyleRule with the selector div:hover p the matcher could not take that :hover pseudo-state into account and instead return an object that has a .matches boolean property (like window.matchMedia) as well as a conditional property that has an object property that could be shaped { element: Element, state: string }:

/* Match a CSSStyleRule with selectorText 'div:hover p' */
Element.matchRule(CSSStyleRule);
/* { 
        matches: true, 
        conditional: { 
            element: <div>,
            state: ':hover',
    }
*/

In addition it would be very useful if that function returned more information such as the resolved specificity or resolved/matched selectorText (for when the CSSStyleRule contains a selectorlist) and information on the conditionals (media, container, supports layer,) applied to the CSSStyleRule, though this is less important than the matching test itself.

I'm happy to do the work here in terms of spec writing (after consensus), if someone can nudge me in the right direction.

edit 20 june 24: expanded the proposal to include checking for pseudo classes and elements.

@bramus
Copy link
Contributor

bramus commented Jun 19, 2024

Seems like a valid request/use-case.

Not sure if it should become CSSStyleRule.matchesElement(Element) or Element.matchesRule(CSSStyleRule) though. There’s something to say for both.

@Kilian
Copy link
Author

Kilian commented Jun 19, 2024

I have no strong preference for either, but since CSSStyleRule has no functions and HTMLElement already has matches() and will get matchContainer(), I think it would be more consistent to have it there.

@lukewarlow
Copy link
Member

To be slightly pedantic, this new function should be on Element not HTMLElement (between the two). As is the case with matches().

@Kilian Kilian changed the title [cssom] There should be a way to test CSSStyleRules against HTMLElements [cssom] There should be a way to test CSSStyleRules against Elements Jun 19, 2024
@Kilian
Copy link
Author

Kilian commented Jun 19, 2024

Good callout, thanks. I've updated the proposal.

@hidde
Copy link
Member

hidde commented Jun 19, 2024

This seems like a useful addition!

@Kilian
Copy link
Author

Kilian commented Jun 20, 2024

I updated the proposal to handle pseudo classes and elements.

@jogibear9988
Copy link

I created a designer (https://github.com/node-projects/web-component-designer) where I use these APIs to show the matching CSS. For nesting (wich I do not support yet), I will have a solution to at least combine all the parent rules, but for scope this would be much complexer.
But as the CSSStyleSheet does not include Position information I need to parse the style myself, and so I'll need a API like "matchesScope(" wich I would hand over the scope definition.
sample:

  matchesScope("(.component) to (.content, .slot, .child-component)")

and this API should return true, if the element is inside of the scope.

But for sure, I also vote for the API for the Style Rule

@Kilian
Copy link
Author

Kilian commented Oct 7, 2024

The new CSSNestingDeclarations API and complexities around implicit &{} makes it even harder to resolve matching rules from selectors, so this is very much needed still.

@fantasai fantasai added the cssom-1 Current Work label Oct 15, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
cssom-1 Current Work
Projects
None yet
Development

No branches or pull requests

6 participants