A way to observe changes in CSS custom properties


#1

I have custom elements that render with WebGL, and I’d like for them to be stylable with CSS. So what I’d like is to be able to observe changes to properties like --material, --material-color, etc.

Setting properties with CSSStyleDeclaration.setProperty(), is easy, and for normal elements that render with CSS, no observation is needed.

But because I refer with WebGL, I need to observe the properties so I can apply then to WebGL outside of CSS.

How can I do this?


Right now I believe the only way is to monkey-patch CSSStyleDeclaration.setProperty() so that anytime I detect that the property being set is one that I care about, I can then find all elements that match the selector, and do what I need (update the WebGL drawing).

I would also need to detect if the declaration is on an element vs in a style sheet, so I can update rendering for that element and not need to run a selector.

I would have to monkey-patch HTMLElement.style.

I will have to consider how users use !important.

I’ll have to extract number values and convert CSS unit values.

Etc…


It would be great if there were a built-in way to observe changes to rules of a stylesheet, or to rules of an element’s computed style.

Is there an API for this being planned anywhere?


#2

Monkey-patching setProperty would be a very poor choice, as property values can change merely by changing a CSS class. Currently, there’s no way to detect when a custom property’s value changes because it would be not very clear or too computationally intensive (i.e. it could trigger too many events).

A dirty trick would involve the transitionend property with a 1ms transition on any transition-able property using var(--custom-property), but that would only work on transition-able values too. And it would have a 1ms delay.

I think a well-targeted observer would be the optimal solution. I wonder if MutationObserver could be extended to support specific style properties…


#3

as property values can change merely by changing a CSS class.

True. In this case, MutationOberver on the class attribute can be used, but then the element has to be needlessly checked just to see if some property changed. It could also be possible to watch a style element’s textContent with a MutationOberver, and detect changes all at once (use the selector to find matching elements and trigger logic on them).

There’s lots of ways to do this, none of which are ideal.


#4

Another consideration is that the value of a custom property for an element could change without modifying the class name or style directly i.e. media queries


#5

Good observation. This thread will become a good list of all the things that we’d need a code path for.

Another consideration is that custom properties (the ones not made using CSS.registerProperty) are always inherited, so if we want the properties to affect only elements that the properties are targetting (and if CSS.registerProperty is not supported) we’ll have to write even more logic to handle that case.

It’s gonna get really messy, and introduce lots of surface area for edges cases and bugs.