'Defining a setter for individual style property

According to the current CSS specification CSSStyleDeclaration.setProperty() has a shorthand of writing directly to the style property. Like in the code below, both lines have the same functionality:

element.style.color = "#fff";
element.style.setProperty("color", "#fff");

Though there is an interesting and unclear situation to me here: I couldn't find the way to hook a custom setter for individual style properties, since these don't have an explicit setter. Changing the setProperty method only works for the direct call of the method element.style.setProperty() and not the shorthand (i.e. element.style.color).

Both seem to refer to CSSStyleDeclaration interface, but I can't find a way to define a setter for a specific style property (i.e. element.style.color).

MDN says the following:

While this property is considered read-only, it is possible to set an inline style by assigning a string directly to the style property. In this case the string is forwarded to CSSStyleDeclaration.cssText. Using style in this manner will completely overwrite all inline styles on the element.

According to this, changing a setter for cssText could possibly intercept the setter for specific style properties, but it only does for inline style definition itself (i.e. element.style = 'color:#fff;')

Is there a way to define a custom setter for individual style properties, such as element.style.color, or at least have a generic setter for any of them?



Solution 1:[1]

As you have explained, there are two ways to set a style property:

  1. e.style.property=
  2. e.style.setProperty(property,..)

Depending on implementation, these two ways can be handled either independently, or using each other. It is very unprobably, that setProperty calls the way 1. The way 1. can have a setter, which may or may not call the setProperty. The property may exist (have a property descriptor), or the way 1. may be handled another way (e.g. by catch the exception non-existent property.) This does mean, that you can define/redefine the property as an accessor, which's getter calls getPropertyValue, and which's setter calls setProperty. Then, you can inject any call of (even instance-defined) function.

Object.defineProperty(CSSStyleDeclaration.prototype, "color", {configurable:true, enumerable:true, get:function() {return this.getPropertyValue("color");}, set:function(c) {let tweakedC=tweakColor(c); this.setProperty("color", tweakedC); handleNewPropertyValue(c, tweakedC);}});

function handleNewPropertyValue(c, tweakedC) {...};

I have used this way in some version of Chrome, but I believe, that it will do in most implementations, except of those, where setProperty depends on existing the property per se (unprobably).

Tweaking the prototype to create a new instance property on first access is very easy, but it is another question.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Kokot