Tab Completion

I'm Tab Atkins Jr, and I wear many hats. I work for Google on the Chrome browser as a Web Standards Hacker. I'm also a member of the CSS Working Group, and am either a member or contributor to several other working groups in the W3C. You can contact me here.
Listing of All Posts

Feedback Requested: .specifiedStyle

Last updated:

The CSSWG has a question that it's not well-qualified to answer, because its members don't do enough web development to really understand the problem space well. So we'd like your feedback!

Here's the thing. For a long time, if you wanted access to the property values on an element, your only recourse was getComputedStyle(). This has always been kinda crappy, though - in particular, because the definition of "computed value" changed between CSS2 (when the function was first defined and implemented) and CSS2.1, the function now technically returns used values for a subset of 2.1 properties, and computed values for everything else. (This means that, for example, if you set width to a percentage, it'll show up as px in the getComputedStyle() results, but if you use a percentage in, say, flex-basis, it'll show up a percentage.)

(Quick primer on the basic differences between "computed" and "used" values. A CSS value goes through several stages as it transforms from its declared value (what's actually written in the style sheet) to its actual value (the final, absolute value actually used by the browser). The first stage is specified value, which handles the global keywords inherit and initial, and fills in the initial value of the property if you didn't specify anything in your stylesheet for that element. The second stage is computed value, which takes the specified value and resolves it into final form as much as it can, using only property data on the element and its parent. No layout information is used here, and we try to avoid depending on network loads or the property data of other elements. The third stage is used value, which finishes resolving the value into final form, using layout data, network data, and whatever else is necessary. Finally, there's an actual value, which is just the used value, but adjusted as necessary to accommodate the display device and other last-second limitations. For example, fractional pixel lengths might get rounded to integers so they map to an exact number of physical pixels.)

Recently, we added some new and better ways to access this kind of information on elements: the .specifiedStyle, .computedStyle, .usedStyle, and .defaultStyle attributes on Element. These work exactly like .style, except that rather than only exposing the property set by the style='' attribute, they expose all the properties, just like the getComputedStyle() method did.

Here's where we need your help. .computedStyle and .usedStyle seem pretty easy to justify. But .specifiedStyle is a little harder. What exactly would be helpful for you, the author?

As it's specified right now, .specifiedStyle will return a value for every property on the element. If you didn't give the element a value for that property in your stylesheets, it'll return the initial value for the property. If you set the property to initial or inherit, it'll substitute those with the values they represent.

On the other hand, would it be more useful to instead provide something slightly lower-level? Where initial and inherit are returned literally if specified, and you get back null or the empty string for properties that were not set on the element? I feel like being able to tell when a property hasn't been set on an element is potentially useful, as it lets you tell the difference between "set a value" and "inherited a value". I also suspect that any time you want something slightly more advanced/friendly, you'd be okay with going all the way to "computed value" or "used value".

Thoughts?

(a limited set of Markdown is supported)

I'd prefer the empty string for a property that is not explicitly specified. This is, because I could have specified "inherit" in my stylesheet, which might have the same outcome, but is still specified explicitly.

I've only taken a quick look at the spec, but I see it finally explicitly states how to work with shorthand properties (namely resolve respective longhand properties) - yay!

Have you also thought about giving CSS*Rule objects a bit more context? meta info like the following could help library authors wrangling the DOM (a lot):

  • is it a shorthand?
  • list of longhand properties
  • type ("<length>, <percentage>, <color>, …")
Reply?

(a limited set of Markdown is supported)

Without ability to get value of any (not only supported ones) property (it seems such ability is not provided currently in the CSSOM draft -- please correct me if I'm wrong), the specifiedStyle feature will probably be of pretty limited usefulness.

Reply?

(a limited set of Markdown is supported)

Re #2: Go read the Variables spec - custom properties are the intended way to let you add, well, custom properties. Just put a "var-" prefix in front, just like a vendor prefix.

Reply?

(a limited set of Markdown is supported)

Re #1: We want to expose a lot more info in CSSStyleDeclaration objects, allowing you to read or write values in particular units directly, etc. There was some effort to do this a few years ago by Anne van Kesteren, but he left the WG and no one's had the time to pick up the effort yet.

Reply?

(a limited set of Markdown is supported)

Re #1: Can you please file a bug or email www-style about the shorthand/longhand thing, and explain the use case? Thanks!

Reply?

(a limited set of Markdown is supported)

I think the specified value should read "inherit" or "initial" and not resolve to the actual unit, if that is what I specified. An empty string/null for properties that were not specified is the correct way to go, as well.

By the way, what about actualStyle?

Also, a way to map an element to its CSS cascade/chain would be handy in some situations (like the Google Chrome Developer Tools Computed Styles pane shows).

Reply?

(a limited set of Markdown is supported)

Re #3: I think Marat is talking about the fact that browsers discard properties they do not (yet) know/support. That's bad for when you want to write a polyfill for that property (e.g. CSS filter declarations). But isn't that also being tackled somewhere? I think something scrolled by in my Twitter feed.

Reply?

(a limited set of Markdown is supported)

My take would be ".specifiedStyle" that returns an empty string for properties not being set on a stylesheet, and do no interpret the value found in the stylesheet (even initial). The only use case I can see for ".specifiedStyle" is custom debug tools and polyfills, so any lost information may be critical to some usecase.

Reply?

(a limited set of Markdown is supported)

Re #7: Yup, I know what Marat was referring to, and offered him the correct response - we won't be supporting arbitrary properties (makes it hard for us to extend CSS), but using custom properties (var-*) lets you do whatever you want at the cost of a small prefix.

Reply?

(a limited set of Markdown is supported)

Re #6:

Also, a way to map an element to its CSS cascade/chain would be handy in some situations (like the Google Chrome Developer Tools Computed Styles pane shows).

You mean like a list of CSS rules that contributed to the cascade for the element, sorted by specificity?

I agree this would be useful. I'm pretty sure that WebKit/Blink expose a non-standard function for this already (presumably used by the devtools).

Reply?

(a limited set of Markdown is supported)

Re #6: Oh, and regarding .actualStyle, that's likely not going to happen. The conversions for actual style happen so late that it's really hard to plumb the data back to the rendering engine.

Reply?

(a limited set of Markdown is supported)

I'm with you Tab. I'd expect to get back initial and null, as you laid out.

Reply?

(a limited set of Markdown is supported)

I think I'd prefer to only see the properties that are actually specified (when enumerating), and to get back undefined where they're, well, undefined. That seems to be much more in keeping with the name specifiedStyle.

It looks as though specifiedStyle will only allow you access to the long-hand properties -- is that perhaps a bit confusing, given that the author may well have specified the properties in short-hand? I'm not suggesting that the behaviour is wrong, but that perhaps the name needs to change -- something like parsedStyle or cascadedStyle, perhaps. A different name would also have the advantage of making it clearer what you're getting back in the presence of media queries and variables -- I assume that with the latter, you'd get the substituted value, not the variable, after all.

Reply?

(a limited set of Markdown is supported)

Re #5: Mail to www-style didn't go through (have had issues with other lists as well, no clue why) - so I'll just post it here and leave the proxying to the list to you.


As a library author I want to identify longhand / shorthand properties. This is required so I can ignore margin in favor of margin-left et al. Right now this would be handy because we only have computedStyle, an returned values for shorthands vary across browsers. Even if there is a way to retrieve a proper value for a shorthand, this type information is still useful. I could use this in a rendering of the CSSOM (a la Dev Tools), ´prevent processing shorthands if there are (simpler to parse) longhands, etc.

As a polyfill author I want to know about unsupported properties. Tab made the argument that you could use custom var- properties for that, but that would require the CSS author to provide (unnecessary) duplicate definition. I wouldn't want this exposed as a regular property, rather accessible through a separate list from CSSStyleDeclaration. (We will always be "fixing" stuff for older browsers)

As a library/polyfill author I want to know the type(s) a CSS property accepts. This is static data. It allows me to control different parsing / serialisation modes when processing property values. A map like this probably already exists within implementations (for pretty much the same reason).

There are various serialized presentations of values. Colors (HSLa, RGBa, HEX, keywords) are a great example of how we have to parse strings in javascript-land simply so we can do some funky calculations on them. List-properties (such as animation-*, transition-*, box-shadow) require manual splitting. Way more "stupid string wrangling" than should really be necessary - considering engines already perform these tasks internally. I don't want to have to throw kilobytes of javascript at simple and repetitive problems like this. In a first step these complex value types should expose their components (RGBA: red, green, blue, alpha). In a second step these value objects could be enriched with utility functions such as lighten(<percentage>) for colors.

Reply?

(a limited set of Markdown is supported)

#15 - Mike Sherov:

IMO, .specifiedStyle would be MOST useful if it returned what the author specified (OR didn't).

By automatically converting "", "initial", and "inherit", you're destroying information. YAGNI or not, in 4 years, someone will find a use case where they need to know if someone explicitly said inherit or not. We'll have the same problem we currently have with getComputedStyle, and we'll need to come up with "yet another value type" for CSS properties: "truly specified value".

On the other hand, I can't find a good use case for the current behavior. Why return the initial style if not set? Wouldn't that be what a theoretical .initialStyle would be used for (or just a quick read of the spec dictate)? Wouldn't someone who needs to know what "", "initial", and "inherit" translate to just query .computedStyle?

Think of it this way... As a jquery contributor, I'd gladly promise to provide some functionality that turns "initial", "inherit", and "" into more useful values for consumers if they need it. But if the browser does that conversion for me, I can't promise jquery users I can do the opposite... determine if "initial" or "inherit" or "" was specified.

Reply?

(a limited set of Markdown is supported)

Re #3:

Go read the Variables spec - custom properties are the intended way to let you add, well, custom properties. Just put a "var-" prefix in front, just like a vendor prefix.

Tab, you are probably confusing a dirty workaround with a usable nonredundant solution. Variables have their own application and are not a solution here.

While the industry is moving from prefixes to preffing features off until they are stable enough (thus preventing declarations' duplication at all), you are insistently recommending to duplicate declarations again just because you think this is the only right way while practicing web developers do not.

Reply?

(a limited set of Markdown is supported)

It would definitely be handy to be able to get at both the style set by the author, say .setStyle, and the value set where no value was set in the CSS directly (whether inherited or assumed by default) say .specifiedStyle.

I don't see how either of those would interfere with .computedValue or .usedValue for the final, rendered result (or .usedStyle/computedStyle).

It may, at times be interesting to see the differences between computed and used styles: to see which way things are being rounded, as that becomes necessary.

Reply?

(a limited set of Markdown is supported)

Re #16: Totaly agree. We should make css full polyfillable. What about a style-mutation-observer?

Obsrvr = new styleMutationObserver(function(e){ e.target.MozBoxSizing = e.target.boxSizing }); Obsrvr.observe(document,{ subtree:true, styles:['box-sizing'] });

Reply?

(a limited set of Markdown is supported)