A partial archive of discourse.wicg.io as of Saturday February 24, 2024.

Observe current/computed style changes (StyleObserver)

noamr
2020-09-30

Not sure if this falls here or under APIs… This is related to A way to observe changes in CSS custom properties The idea is to have an observer, similar to Resize/Intersection/Mutation(Observer) that gets triggered when certain computed CSS properties of an elements are changed.

It’s very difficult to implement this with MutationObservers without a big performance penalty, while internally the browsers already track these changes.

simevidas
2020-10-02

Could you describe a use-case?

noamr
2020-10-03

Yes, the use case is describing new behaviors using custom CSS properties, and even using them to polyfill not-yet-supported standard properties.

leaverou
2020-10-13

Just came here to suggest the same thing.

Polyfills are indeed one use case. But IMO the main one is custom elements that need to propagate such changes to the appropriate child / shadow DOM node, or even rewrite them completely.

Examples:

  • Implementing a custom element that works like <fieldset>, where border isn’t applied to the whole element, but to the shadow DOM element wrapping the contents.
  • Similarly, a border on a tabs component wouldn’t be useful around the whole component, but should set the border of the tabs and the tab panels.
  • To direct where a background declaration should be applied. E.g. right now there are dialog/popup components, where setting the background sets the backdrop color instead of the dialog background because of how they were implemented.
  • To implement high-level custom properties that control multiple declarations, e.g. --tabs-placement: [top | right | bottom | left ], --size: [small | medium | large], --pill: [on | off ] which are currently typically implemented as attributes against TAG guidelines. I linked to Shoelace, but other component libraries are no different, Shoelace just has more linkable docs. :slight_smile: This is not something that can be solved with ::part().

Besides propagating declarations to the appropriate child, there is also the opposite: listening to style changes on the children and adjusting ancestors appropriately. E.g. imagine a <pie-chart> component that uses <pie-slice> children to define the different segments, where a shadow <canvas> or conic-gradient background on the parent was used to render the pie chart. This is not implementable without the ability to listen to background changes on <pie-slice> and redraw the chart. And unlike propagating to children, this is not something that can be hacked via inherit and display: contents.

If a generic observer would be too hard, perhaps there could be something specifically for custom elements and slotted elements, like attributeChangedCallback but for CSS properties.

Cross posted to Houdini

gmurray81
2023-05-23

IMO the most important scenario for this is canvas based web components. HTMLElements can generally interact well with CSS as long as they let CSS do its thing. But when you hit the boundary of a canvas, we need to turn the autonomic and declarative behaviors of the style system into imperative instructions to an immediate mode rendering system.

Trying to join these two systems manually either results in a lot of performance overhead, or a lot of compromises (needing to be manually told of a styling environment change). And avoiding performance overhead is generally why you chose to work with canvas in the first place rather than SVG.

jimmyfrasche
2023-05-23

It’s very easy to get CSS to respond to JS. Just change an attribute on the appropriate element and bam.

Being able to listen to a custom property change would let JS respond to CSS.

It’s easy to do a lot quickly in CSS, especially now with container queries, preference queries, and :has. But if your JS state needs to synchronize with that CSS state you’re out of luck and need to move everything into JS where it gets a lot wordier.

For a concrete example I’ve run into more than once: say you have a menu that’s a row of disclosure popups on big screens and a hamburger on small screens.

You can do almost all of this in CSS except for stuff like setting aria-expanded on the buttons. If you’re careful you can keep your JS mostly agnostic of the CSS state but you’re going to need to know about when the transition from/to small/large screen happens just to make sure everything gets reset and focus doesn’t get lost anywhere. That means moving the MQ into the JS to know when the changeover happens even though the JS doesn’t really care why this is happening or at what breakpoint.

It’s not clear how to update this to CQs and without custom MQs this means either duplicating the MQ in the CSS and JS, an additional build step to keep it synched, or putting it in JS and communicating the visual change by toggling a .hamburger class or somesuch.

It would be much cleaner, imo, if the JS could just listen to some custom prop and let the CSS control when that prop gets updated and why.