https://drafts.csswg.org/cssom/#dom-window-getcomputedstyle
The spec currently says that the list of declarations that a CSSStyleDeclaration
returned by getComputedStyle
includes only "supported CSS properties", which means that it doesn't include custom properties. I think it makes sense to expose these through computed style objects.
Gecko does this, both via item()
and getPropertyValue()
. For item()
(and the indexed getter) custom properties appear after all of the built-in properties, sorted by the order that they happen to cascade in (though that should probably become lexicographically sorted or something).
It seems to me that Blink exposes it via getPropertyValue()
but not via item()
.
And yeah, I guess we should probably make them lexicographical.
I agree that it makes sense to support custom properties in getComputedStyle
, and suspect that the text about "supported CSS properties" predates the introduction of CSS variables and custom properties.
@svgeesus the definition of "supported CSS properties" explicitly excludes custom properties.
https://drafts.csswg.org/css-variables-1/#apis makes claims that contradict what CSSOM requires.
I excluded custom properties in CSSOM proper because at the time the Custom Properties spec defined its own API for custom properties. It appears that has since been removed and the assumption is that the standard API should work for custom properties (in a case-sensitive manner).
So I guess we should make it work...
Hey folks, this is a pretty important feature for us here at Salesforce. Can we get this moving again?
@tabatkins
@stefsullrew This basically works in all browsers, right?
Or are you talking about the enumeration of the custom properties, which only works in Firefox? I can do the spec edits, given this is supported everywhere de facto.
The spec should definitely reflect what's currently supported in browsers — getPropertyValue()
and setProperty()
and so on. If there are any parts that still disagree, they need to be updated.
But I'd also be happy to have easier / more familiar ways to access the values. If you've got specific use cases, @stefsullrew, that would definitely help.
E.g, do you need support for el.style["--my-prop"]
getting and setting? Or as @emilio mentioned, the ability to list out all properties through enumeration?
Hey all, @stefsullrew asked me to reply on her behalf.
Essentially what we're looking for is having getComputedStyle
provide all the CSS custom properties that are declared on an element (or, in our case, a Web Component). Currently, Safari and Firefox support this while the latest Chrome does not. Here's a test case: https://codepen.io/acordova/pen/wOLzyP
If you view the above link in the supported browsers, you should see on the right-hand side a list of the component's declared custom properties with their values in an input. If you update the values in the input, it updates the component on the left-hand side. In Chrome, however, because it doesn't provide any properties that contain --
, the right-hand side is empty.
For this playground, we're assuming we _don't_ know the names of the properties contained within a component; getPropertyValue()
and setProperty()
absolutely work in all browsers, but it's seemingly only useful if you already know the name of the property, which in our case we wouldn't. Being able to grab the custom property names from getComputedStyle
would allow us to build a theming playground like this without manually having to update the property names for every component; in SLDS we currently have 84 components with 165 variants 😅.
If there's another way of accomplishing this, or if this is not the correct venue for this kind of change, or if anything needs further explanation, please do let me know. Thank you!
I support @alexiscordova's use case. These properties should be included, except if there is a strong reason not to (I don't see one stated in this thread so far).
Have you filed a bug on Chrome? That might be the easiest way to get this fixed, since all other browsers seem to agree on a behavior, so it looks like an interop issue for them at this point.
If you're all in agreement @emilio @AmeliaBR @zcorpan — and there's nothing more to do here, we're happy to file a bug on Chrome. Just let us know.
Cheers
I agree that use-case is reasonable, yeah. I think there'll be no pushback if I just add it to the spec, but I'll add it to the agenda first just to confirm next week.
Awesome, thanks everyone! I'll file the bug on Chrome now.
To confirm, the plan is that custom properties will be included in the iteration results of getComputedStyle
if the property has a value _other_ than the "empty initial value" for custom properties.
This seems to be what Firefox is doing. Including the properties in the iteration is consistent with how custom properties are treated in the style
object for inline styles. (Test case, focusing just on custom properties and not on custom elements: https://codepen.io/AmeliaBR/full/JVXEzq)
I'm assuming this means that the computed style should also include any custom property that has an initial value because of registerProperty
.
Firefox (and as far as I know, Safari) does _not_ currently support getting/setting custom properties using the named accessors (style["--my-var"]
), so I'm guessing that is not part of the proposed edits at this time: you'd still need to use getPropertyValue()
and setProperty()
for those.
Firefox (and as far as I know, Safari) does not currently support getting/setting custom properties using the named accessors (style["--my-var"]), so I'm guessing that is not part of the proposed edits at this time: you'd still need to use getPropertyValue() and setProperty() for those.
Yes, that's right. I'm not 100% sure how easy would be to make style["--my-var"] work, btw, would need to dig more into it.
There's lack of interop in how those properties are implemented (Firefox is the only one who follows the spec to the letter as far as I know), and IIRC they're defined in terms of WebIDL attributes, which means that the name would need to be known statically, which is obviously impossible in this case.
Also, another thing to check is what would be the iteration order. In Gecko we preserve the specified cascade order.
In WebKit it looks like it's just however the HashTable implementation ends up storing them...
That is a bit nasty.
I prefer what Gecko does, but Gecko doesn't have non-inherited custom properties yet, and if we had we'd want separate storage for them...
Alphabetic order would be better IMO, but then that makes the getter potentially expensive, because you need to sort your internal representation of the map...
So at this point I'm not sure what's better. I'd prefer to not leave the ordering of the properties unspecified. :-(
Ideas?
cc @andruud, in case he has ideas, since I know he's been looking into custom properties quite a bit.
FWIW in Edge we used to assign an ID to each custom property in the order in which we discovered them, so except if someone put special care about this (I doubt) there is no guarantee the order of any iteration of them would be stable across changes to your css. However, if you take this approach, sorting them later on can be reasonably cheap, you just need a list of all the properties that you maintain in sorted order relative to the property name, and their respective ID. Then when you want to iterate the custom properties, you iterate in the order of the sorted list.
and IIRC they're defined in terms of WebIDL attributes
The CSS-defined properties are, yes, but we can define a named getter/setter on the object to handle custom properties.
I'd prefer to not leave the ordering of the properties unspecified
@emilio Then _specify_ that the order is not defined. ;P
Otherwise, I think sorting the properties when setting up the iterator should be fine ... is performance _that_ critical for iteration?
@emilio Then specify that the order is not defined. ;P
Maybe :)
Otherwise, I think sorting the properties when setting up the iterator should be fine ... is performance that critical for iteration?
Well, you need to sort them every time the indexed getter gets called, potentially, since the computed style declaration is a live object. If you have a gazillion custom properties then it's bad.
Of course you can cache that somewhere or what not, but I personally would find it slightly annoying just for this purpose.
My mistake, I was looking at the code for for (let x of getComputedStyle(e))
...
For length
+ item
sorting would indeed be annoying.
The CSS Working Group just discussed should custom properties be exposed on computed style declarations?
, and agreed to the following:
RESOLVED: non-initial custom properties should be exposed on computed style objects, open a new issue about defining order
The full IRC log of that discussion
<dael> Topic: should custom properties be exposed on computed style declarations?
<dael> github: https://github.com/w3c/csswg-drafts/issues/1316
<dael> Rossen_: heycam added and then lively discussion. Who wants this?
<dael> TabAtkins: I can. I support it. If we allow interaction of custom prop via OM we should expose what's non-initial. Makes sense to make when you gCS from there. Technical questions on the API, but can be resolved by emilio as he feels fit.
<dael> TabAtkins: Should resolve non-initial custom prop should be exposed on computed style objects
<dael> Rossen_: Other opinions?
<emilio> There's an issue with ordering of properties
<dael> Rossen_: Objections to non-initial custom properties should be exposed on computed style objects
<emilio> Also, what happens with registered properties that have an initial value
<dael> Rossen_: emilio points out issue with ordering?
<dael> Rossen_: Does that change opinion?
<emilio> Basically, order in WebKit is just hash ordering, Gecko is cascade order. Defining alphabetic ordering or such may be problematic (need to sort every indexed operation and such)
<emilio> Leaving ordering undefined might be ok
<dael> TabAtkins: I think it's still useful. Need to figure out the answer. I'm confident emilio will put something good in the spec. What's the order you all use?
<dael> Rossen_: Gecko says cascade
<dael> Rossen_: Order undefined would be a lot of contridictory behavior
<dael> Rossen_: Resolve on adding and open issue on dealing with order?
<dael> TabAtkins: Okay
<emilio> Sgtm
<dael> Rossen_: Support overall behavior. Technical order issue should be sep.
<dael> Rossen_: Prop: non-initial custom prop should be exposed on computed style objects, open a new issue about defining order
<dael> RESOLVED: non-initial custom properties should be exposed on computed style objects, open a new issue about defining order
I think el.style['--my-prop']
should be supported if possible. It’s syntactically nicer and more consistent: we tend to use el.style.color
and not .getPropertyValue('color')
or .setProperty('color', 'red')
.
el.style['--scale'] = 3;
el.style['--scale']; // "3"
window.getComputedStyle(el)['--scale'];
// vs.
el.style.setProperty('--scale', 3);
el.style.getPropertyValue('--scale'); // "3"
window.getComputedStyle(el).getPropertyValue('--scale');
It's not clear from the last telcon discussion whether the resolution means to expose them only through getPropertyValue
but also through the named properties.
Since this is still open as a “Needs Edits”…
Those edits would be a good time to include more prominent notes to authors about how custom properties behave differently from recognized properties when it comes to getters/setters vs setProperty()
etc.
(See #4542 for an example of confusion, which was filed by @Pomax after trying to explain the behavior to someone else on StackOverflow)
Most helpful comment
I agree that use-case is reasonable, yeah. I think there'll be no pushback if I just add it to the spec, but I'll add it to the agenda first just to confirm next week.