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] ComputedStyleObserver to observe changes in elements' computed styles #8982

Open
trusktr opened this issue Jun 17, 2023 · 4 comments
Labels

Comments

@trusktr
Copy link

trusktr commented Jun 17, 2023

We need an API to observe computed style changes.

One example use case is to update canvas rendering based on changes in computed styles of an element (f.e. transform values to determine where to draw things in a canvas).

This would be generally useful for implementing things that CSS cannot do, or making early polyfills of new CSS features that haven't landed in browsers yet.

What could it look like? Taking a note from existing observers:

const callback = entries => {
  entries.forEach(entry => {
    console.log(`Property '${entry.property}' changed from '${entry.previousValue}' to '${entry.value}'`);
  });
}

let observer = new ComputedStyleObserver(callback);

observer.observe(someElement, ['background-color']);
observer.observe(otherElement, ['transform']);

// ... later
observer.unobserve(someElement)
// or unobserve all
observer.disconnect()

Some things like callback timing need to be ironed out. Maybe its timing would be aligned with animation frames like ResizeObserver.

Existing ideas and conversation:

The main take aways from these are:

  • simple implementations involve a non-ideal infinite polling loop with rAF
  • correct implementations are cumbersome and difficult to do correctly, easy to miss edge cases, or perhaps even impossible to fully realize
  • performance is not good

While we're making a new API, we can also see about avoiding the same problem that ResizeObserver has:

The problem is that rendering loops typically redraw in animation frame callbacks, but if CSS style change callbacks run after rAF, rendering can be delayed and incorrect and it isn't obvious why.

Maybe the initial set of callbacks for change entries should fire before rAF? Giving typical rendering setups a chance to usually be correct and only sometimes needing an additional next frame for cases when a frame changes style. I'm not totally sure what the solution should be, but it has been a pain debugging these sorts of issues.

@jimmyfrasche
Copy link

It would be quite useful to use this to reflect css state (combination of media/preference/container query and :hover/:focus etc) back into js by observing a custom property. Currently those either need to be tracked in parallel in the js (makes it hard to change anything) or handled entirely in js and have the js reflect the changes to css by adding and removing classes (annoying since it would be much easier to express in css)

@Loirooriol
Copy link
Contributor

I guess simple cases could be covered by the already approved #6205?

element.firstChild.matchContainer("style(property: value)")).addListener(listener)

But yeah not the best API if the element doesn't have children or for properties with a non-trivial value space.

@trusktr trusktr changed the title [cssom] ComputedStyleObserver to observe changes in elements' computed styles [cssom] ComputedStyleObserver to observe changes in elements' computed styles Dec 17, 2023
@trusktr
Copy link
Author

trusktr commented Dec 17, 2023

Here's a related issue describing a problem that would need to be solved for ComputedStyleObserver (and any other new observers) if it (they) ever become reality (f.e. BoundingClientRectObserver):

The more of these we add (which I think would be super useful) the more this problem will become pronounced.

Adding takeRecords and hasRecords to all *Observer APIs would help and would be useful.

Alternatively requestFinalFrame (or requestPaintFrame or some similar named API) would help solve the problem.

@PupilTong
Copy link

PupilTong commented May 17, 2024

+1 for this proposal.
Let me give some detail about why we need this.
Currently we're working on a cross-platform rendering infra(like react-native). Developers using CSS syntax to define layout of the DOMs.
However, we provided some non-standard CSS properties for developers, since it's will gain some performance improvement on iOS/Android.
The way we implement it on Web platform is that we transform the some-property:custom-value to --some-property:custom-value on compile-time, and use getComputedStyle() in attributeChangedCallback to get the value of the css variables, then use Javascript to do somethings.
As you can see, here we could only observe on style and class attribute change, which means our handler will be called frequently(it' expensive since we have to getComputedStyle every time);
It will be really helpful if there is a way to observe specified CSS properties.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

5 participants