Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[cssom] Serialization of CSS declaration block returned from getComputedStyle #1033

Open
upsuper opened this Issue Feb 14, 2017 · 17 comments

Comments

Projects
None yet
8 participants
@upsuper
Copy link
Member

upsuper commented Feb 14, 2017

How should CSS declaration block returned from getComputedStyle be serialized? It contains all longhand properties.

Currently, Gecko and Edge return empty string for it, while WebKit and Blink (probably inherit from WebKit) seem to return serialization of all longhand properties (i.e. not trying to generate shorthands). Apparently none follows the spec.

Following the same algorithm for cssText of declaration block from getComputedStyle is complicated, and probably isn't worth. So I suggest that the spec should either follow Gecko and Edge to return empty string, or follow WebKit and Blink to just return all longhand properties.

I would prefer we just make it return empty string... But there is a webcompat issue reported to Firefox for lack of its support: webcompat/web-bugs#3822. This is a Google website though, so maybe we can just ask Google to fix it and ignore this issue...

@upsuper upsuper added the cssom-1 label Feb 14, 2017

@mrego

This comment has been minimized.

Copy link
Member

mrego commented Feb 14, 2017

We've similar issues in CSS Grid Layout spec.
This was an old mail to www-style: https://lists.w3.org/Archives/Public/www-style/2015Jul/0242.html

A very basic example:

myGrid.style.grid = "100px / 50px";
console.log("style: " + myGrid.style.grid);
console.log("computedStyle: " + getComputedStyle(myGrid).grid);

The output right now in Chrome is:

style:
computedStyle: 100px / 50px / none / row / auto / auto / 0px / 0px

And in Firefox:

style: 100px / 50px;
computedStyle:
@upsuper

This comment has been minimized.

Copy link
Member Author

upsuper commented Feb 14, 2017

I don't think that's something related. IIRC in general we don't serialize new shorthands in computed style, only longhands are serialized there. There are several shorthands get serialized in computed style just for backward compatibility.

@mrego

This comment has been minimized.

Copy link
Member

mrego commented Feb 14, 2017

Oops, ok I messed it up, I thought you were talking about shorthands.

@FremyCompany

This comment has been minimized.

Copy link
Contributor

FremyCompany commented Feb 14, 2017

(Adding myself to the thread; but could you clarify what you think Chrome doesn't do per standards here? I have the impression their behavior is correct in that case at first glance)

(Just to clarify, talking about the initial issue, not the shorthands-in-gCS one)

@upsuper

This comment has been minimized.

Copy link
Member Author

upsuper commented Feb 14, 2017

could you clarify what you think Chrome doesn't do per standards here? I have the impression their behavior is correct in that case at first glance

In the spec, the serialize a CSS declaration block algorithm tries to construct shorthands whenever possible. In case of declaration block from getComputedStyle, since all longhands are available, most of shorthands would be constructible. However, Chrome doesn't seem to construct any shorthand in that case.

@tabatkins

This comment has been minimized.

Copy link
Member

tabatkins commented Feb 22, 2017

On the call today WG resolved to accept Firefox's and Edge's behavior, and make the object serialize to the empty string.

I'll file a bug on Chrome to fix this, and start evangelizing at Drive to fix the webcompat bug.

@tabatkins tabatkins added Needs Edits and removed Agenda+ labels Feb 22, 2017

@FremyCompany

This comment has been minimized.

Copy link
Contributor

FremyCompany commented Feb 22, 2017

Thanks Tab!

@zcorpan

This comment has been minimized.

Copy link
Member

zcorpan commented Mar 6, 2017

@upsuper

There are several shorthands get serialized in computed style just for backward compatibility.

Which are these?

@upsuper

This comment has been minimized.

Copy link
Member Author

upsuper commented Mar 6, 2017

Mainly the shorthands which are previously longhands, e.g. background-position, text-decoration, overflow, and mask.

@zcorpan

This comment has been minimized.

Copy link
Member

zcorpan commented Mar 15, 2017

Given the following case, it seems browsers all have some logic to try to serialize as shorthands when possible. It's unclear to me why we want to avoid doing that for getComputedStyle specifically?

http://software.hixie.ch/utilities/js/live-dom-viewer/saved/4948

<!DOCTYPE html>
<p style="border:1em solid">
<p style="border:1em solid; border-right-width: 1px">
<p style="border:1em solid; border-right-width: 1px !important">
<script>
for (var p of document.querySelectorAll('p'))
  p.style.color = 'purple';
</script>

(check the value of the style attributes after the script has run.)

@emilio

This comment has been minimized.

Copy link
Collaborator

emilio commented Apr 27, 2018

@tabatkins Could you link it to the Chrome bug if you can find it please? I think this resolution makes sense, but Chrome hasn't updated its behavior yet :/.

I'll file a WebKit bug pointing to that bug as well.

@carlosame

This comment has been minimized.

Copy link

carlosame commented May 2, 2018

Like @zcorpan , I do not see for which reason computed styles cannot have a meaningful serialization. A computed style is still a style, after all.

I'm the developer of a CSS tool (a CSSOM library) that happens to behave like Chrome (although there is an optional method that builds the shorthands), and see no reason to change to returning an empty string (what's more, I have users depending on the current behaviour).

@upsuper

This comment has been minimized.

Copy link
Member Author

upsuper commented May 3, 2018

@zcorpan @carlosame

From the implementation side, computed style and specified style are usually stored in different forms in browsers, and when browsers are asked to serialize a computed value, they serialize it from its internal form directly (rather than, say, convert to specified value then serialize the latter), however, shorthand serialization algorithms are usually written to handle declaration block of specified values.

It means that to serialize declaration block from gCS per spec, browsers would need extra work either to implement all shorthand serialization algorithms on computed value as well, or create a declaration block containing every property in their specified value form, and then use the algorithm of specified declaration block to serialize them.

Doing such conversion is not impossible, though. Actually, at least in Gecko, we have such mechanism for animation and transition, because our cascading is based on specified value, but interpolation happens on computed value, so we need to "uncompute" value to cascade animation and transition correctly.

However, many properties are required to serialize differently for gCS, and the "uncompute" mechanism may not exactly match that requirement, so reusing it can potentially further complicate things.

From the use case side, I'd argue that getting a serialization of a declaration block containing every property with shorthand serialized properly is hardly the ideal way for anything.

If you just want to persist and restore all values, you should just iterate all properties in that block, that would almost certainly be faster than relying on browser to generate the serialization of the huge declaration block, then parsing this huge serialization again, as can be seen in the discussion of webcompat/web-bugs#3822.

Also, shorthand serialization are usually for human readability, but would anyone want to read a declaration block serialization containing hundreds of properties?

Given that this needs probably non-trivial extra work on implementations, while it doesn't seem to be very useful, we should probably just make it as simple as possible so that implementations can be interoperable on the behavior.

@carlosame

This comment has been minimized.

Copy link

carlosame commented May 3, 2018

however, shorthand serialization algorithms are usually written to handle declaration block of specified values.

Omit the shorthands like Chrome does, then. I'm asking for a meaningful serialization, and not necessarily one with shorthands. IMHO a gCS serialization with only longhands may make more sense than one with shorthands, given the nature of the potential use cases.

However, many properties are required to serialize differently for gCS, and the "uncompute" mechanism may not exactly match that requirement, so reusing it can potentially further complicate things.

But you already implement getProperyValue. All that you need is to add it to a buffer. Does not sound overly complex.

From the use case side, I'd argue that getting a serialization of a declaration block containing every property with shorthand serialized properly is hardly the ideal way for anything.

Agreed.

If you just want to persist and restore all values, you should just iterate all properties in that block, that would almost certainly be faster than relying on browser to generate the serialization of the huge declaration block, then parsing this huge serialization again

Persist and restore is just one use case. The fact that doing it that way can be inefficient does not mean that gCS serializations are useless.

Also, shorthand serialization are usually for human readability, but would anyone want to read a declaration block serialization containing hundreds of properties?

My serializations do not (generally) contain hundreds of properties. I do not include properties that take their initial values due to defaulting (and the count of properties that are cascaded or inherited is what I return in getLength(), and not the total amount of properties known to my library).

Given that this needs probably non-trivial extra work on implementations, while it doesn't seem to be very useful, we should probably just make it as simple as possible so that implementations can be interoperable on the behavior.

On UAs, that serialization is IMHO useful for debugging purposes, and for CSS tools (like mine) it can have other uses (although I do know that the WG is not very concerned about non-UA use cases).

I have use cases about putting the serialization in the style attribute of a DOM document and passing it to a rendering library that does not know how to compute styles, but can retrieve them from the attributes. It can also be useful to write tools that monitor changes in the styling of the elements in the DOM tree of a web page.

That is, on UAs gCS serialization can be useful, and on other type of implementations it is definitely useful.

And to me, "make it as simple as possible" means the Chrome behaviour (but I do not know whether it serializes all the properties or only the cascaded-or-inherited, as I mentioned).

@upsuper

This comment has been minimized.

Copy link
Member Author

upsuper commented May 3, 2018

but I do not know whether it serializes all the properties or only the cascaded-or-inherited, as I mentioned

Every element has value for every property, so it has to be listing all of them.

My serializations do not (generally) contain hundreds of properties. I do not include properties that take their initial values due to defaulting (and the count of properties that are cascaded or inherited is what I return in getLength(), and not the total amount of properties known to my library).

That is very different from what computed value means to be.

@carlosame

This comment has been minimized.

Copy link

carlosame commented May 3, 2018

Every element has value for every property, so it has to be listing all of them.

A computed style needs to be able to retrieve a value for each property (for example with getPropertyValue()), but it is unclear that the gCS serialization must include all of them.

We are discussing about what the serialization should be, and now leaping from "the empty string" to "it has to be listing all of them".

That is very different from what computed value means to be.

getLength() on a computed style becomes totally meaningless if you do not define it that way.

The basic idea is: if you need the computed value for a given property, use getPropertyValue() (I also provide getPropertyCSSValue()). But my gCS serialization behaves as described previously, and IMHO is very meaningful (and far better than the empty string).

@carlosame

This comment has been minimized.

Copy link

carlosame commented May 3, 2018

A small clarification to my previous comment: in my library, the getPropertyValue() in the computed styles returns a value for properties that aren't found in the item collection, if the library knows about its initial value. The item method only returns the properties that were cascaded or inherited.

That's what I meant with:

if you need the computed value for a given property, use getPropertyValue()

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.