Skip to content

[cssom] Define serialization of specified values with more detail #5642

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

Open
tabatkins opened this issue Oct 20, 2020 · 6 comments
Open

[cssom] Define serialization of specified values with more detail #5642

tabatkins opened this issue Oct 20, 2020 · 6 comments
Labels
cssom-1 Current Work

Comments

@tabatkins
Copy link
Member

Serialization of computed values is generally governed by applying the shortest-serialization principle to the computed value. It's a bit handwavey, and there are some exceptions, but overall it works.

But specified values do not seem to serialize according to the SSP in general; instead, they seem to usually retain more details of what the author originally wrote. Sometimes it's literally the original text, sometimes some light modification is done. (For example, Chrome sorts the 'contain' keywords specified, but doesn't combine them into shorthands like it'll do for computed values.)

I suspect there's a lot of non-interop around this, but we should have more details at least on general principles, even if we don't have all the weird specifics.

@tabatkins tabatkins added the cssom-1 Current Work label Oct 20, 2020
@Loirooriol
Copy link
Contributor

Loirooriol commented Oct 21, 2020

Some common patterns:

Remove optional components when the default value was provided (according to the shortest serialization principle)
document.body.style.margin = "1px 1px 1px 1px";
document.body.style.margin; // "1px" in Chromium, WebKit and Firefox
document.body.style.gridAutoFlow = "row dense";
document.body.style.gridAutoFlow; // "dense" in Firefox (stays as "row dense" in Chromium and WebKit)
Add optional components that were omitted (against the shortest serialization principle)
document.body.style.counterIncrement = "c";
document.body.style.counterIncrement; // "c 1" in Chromium, WebKit and Firefox
document.body.style.borderTop = "solid";
document.body.style.borderTop; // "medium solid" in Firefox (stays as "solid" in Chromium and WebKit)
Normalize to canonical order
document.body.style.flexFlow = "wrap column";
document.body.style.flexFlow; // "column wrap" in Chromium, WebKit and Firefox

@cdoublev
Copy link
Collaborator

cdoublev commented Sep 1, 2022

If I may, what is the rationale for pattern 1 (remove optional component values)? It is always extra work, for what purpose?

EDIT: from reading multiple related issues, serialization to an older syntax, which may me shorter or longer, can help back-compat. I wonder what would be the conditions/scenarios where this backward compatibility requirement might be useful, though.

@tabatkins
Copy link
Member Author

It brings the value closer to what humans would likely write, which makes it easier to read.

@cdoublev
Copy link
Collaborator

I had figured it that too, but it seems less important than back-compat. And for shorthand (eg. animation), the shorter meaning the more human-friendly, may be subjective.

@cdoublev
Copy link
Collaborator

cdoublev commented Jan 25, 2023

I do not know if math functions generally fall into the "weird case" category but the SSP is currently applied inconsistently with them.

For example, Serialization in CSS Images 3 requires omitting components when possible without changing the meaning:

For example, a gradient specified as:

Linear-Gradient( to bottom, red 0%,yellow,black 100px)

must serialize as:

linear-gradient(red, yellow, black 100px)

(The same section in CSS Images 4 serializes red, yellow, black, to rgb(), which makes me wonder if it applies to specified values though.)

Chrome/Firefox omit to calc(180deg) (same as to bottom) in <linear-gradient()> but math functions usually seem to be preserved elsewhere. And they do not omit components in the color stop list. You cannot know 75% can be omitted in linear-gradient(red 50%, blue 0%, 75%, green) without applying color stop "fixup", which is meant to resolve used values.

Obviously color stop list is a "weird case" but I think there are many cases similar to the first. Eg. Chrome/FF do not serialize specified border-radius: 1em calc(1em) to border-radius: 1em.

I guess browsers do not try too hard to resolve values until they know it is required for rendering, which makes me think that not applying the SSP for specified values (except for backward-compatibility) would be way more simple.

@cdoublev
Copy link
Collaborator

I did an in-depth specific research on serialization of optional numeric values, or optional keyword values mapping to a numeric value, in Chrome and Firefox.

They usually only seem to be omitted when they are strictly equal to a default value or an initial longhand value, without applying any resolution before the comparison (presumably with serialized strings):

  • canonicalizing dimensions
  • mapping percentages to absolute values
  • mapping keywords to numeric values (or vice-versa)
  • unwrapping resolved math functions
  • clamping or mapping degrees to [0,360)

Two numerics with a value of 0 but of a different type or with a different unit are usually not considered equal, except 0px and 0 when it matches <length> (it is presumably normalized to 0px at parse time).

Exceptions (probably not exhaustive)
  • often Chrome and sometimes Firefox preserve optional initial longhand values in shorthands
  • color functions serialize without a default <alpha-value>: 100%/1, 101%/2 calc(101%), calc(2)
  • <conic-gradient()> serializes with from 0deg as a default gradient line origin in Chrome
  • <conic-gradient()> serializes without from calc(0deg) as a default gradient line origin in Firefox
  • <linear-gradient()> serializes without a default gradient line direction: to bottom, 180deg, calc(180deg)
  • <filter-function>s serialize with default values
  • font: normal normal 400 16px "family" serializes without 400 (equivalent to the initial font-weight: normal) in Firefox
  • font-style: oblique 14deg serializes with 14deg in Chrome
  • hyphenate-limit-chars: auto 1 1 serializes as is (even if the trailing 1 is strictly equal to the previous 1)
  • transform-origin serializes with the default offset: 0px or 0
  • scale: 1 100% 1 serializes with scale: 1
  • scale: 100% 1 100% serializes with scale: 1
  • scale: calc(100%) calc(1) serializes with scale: 1 in Chrome and scale: calc(1) in Firefox
  • translate: 1px 0em 0in serializes with translate: 1px
  • translate: 1px calc(0em) serializes without calc(0em) in Chrome
  • transform: scale(1, 1) serializes with , 1 in Chrome
  • transform: translate(1px, 0px) serializes with , 0px in Chrome
  • transform: translate(1px, 0in) serializes without , 0in in Firefox
  • transform: skew(1deg, 0) serializes with , 0 in Chrome (invalid in Firefox)
  • transform: skew(1deg, 0deg) serializes without , 0deg in Firefox
  • transform: skew(1deg, 0rad) serializes without , 0in in Firefox
  • transform: skew(1deg, calc(0deg)) serializes without , calc(0deg) in Firefox
  • transform: skew(1deg, calc(0rad)) serializes without , calc(0in) in Firefox

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
cssom-1 Current Work
Projects
None yet
Development

No branches or pull requests

3 participants