w3c / csswg-drafts

CSS Working Group Editor Drafts
https://drafts.csswg.org/
Other
4.5k stars 660 forks source link

[cssom] How safe is it really to shorthandify properties? #8398

Open andruud opened 1 year ago

andruud commented 1 year ago

I'm trying to understand how risky it is to change an already-established longhand into a shorthand. I'm opening this issue against cssom, because it's the only spec I can think of (at the moment) which makes problematic distinctions on longhand/shorthand.

Example: white-space is a longhand in css-text-3, but a shorthand in css-text-4 which expands to text-space-collapse, text-wrap, text-space-trim.

This is observable in that e.g. Array.from(getComputedStyle(e)) will no longer contain white-space.

Are there other problems?

So the only real problem I see is when enumerating things in cssom. It does not seem easy to create a use-counter for this or otherwise investigate the impact of such a change. At the same time, being able to make a longhand into a shorthand seems quite important for future spec development, so the question is: should we do something to make the longhand->shorthand transition (near-)zero-risk? For example, include shorthands in the enumeration? (Or perhaps just those that have been converted).

@emilio @Loirooriol @tabatkins (can you think of other places where the conversion to shorthand is problematic?)

Loirooriol commented 1 year ago

Other than CSSOM it's problematic for toggle() as it's currently specified, see #6764

emilio commented 1 year ago

Longhand enumeration is the biggest change, yeah. I think there might be others around web animations. I think if you transition a shorthand you might get multiple CSSTransition objects rather than one? This is from memory, but should be easy to check (not at a computer atm).

SebastianZ commented 1 year ago

For what it's worth, there are precedents like text-decoration, which was a longhand in CSS 2.1 but got turned into a shorthand in CSS Text Decoration 3. Also text-align got turned into a shorthand in CSS Text 3 while it was a longhand in CSS 2.1. And to go away from text related styling, overflow was initially defined as a longhand in CSS 2.1. In CSS Overflow 3 it then got turned into a shorthand.

So this is nothing new. So, any changes to CSSOM should take that into account. An API change like adding shorthands to the enumeration might break some logic. Admittedly, the risk for that is probably very low, though it should be considered, nonetheless.

Sebastian

Loirooriol commented 1 year ago

I initially thought the pending-substitution value might be a problem

Well, I guess it can be a problem if you are trying to copy all the specified styles. Iterating them will just provide the longhands, and they will serialize as empty string. cssText is typically safer, but an author who only used variables on longhands may not have thought about this.

emilio commented 1 year ago

So this is nothing new. So, any changes to CSSOM should take that into account. An API change like adding shorthands to the enumeration might break some logic. Admittedly, the risk for that is probably very low, though it should be considered, nonetheless.

Actually this seems fairly risky, both performance-wise and breakage-wise.

If we keep the enumeration order alphabetic, there's a chance that a shorthand is enumerated after its longhands, and serializes as the empty string. So something like a loop calling setPropertyValue(prop, value) deletes all the shorthand's properties already set. Unless you enumerate shorthands before longhands, but then you're back at square one.

andruud commented 1 year ago

To serialize as an empty string, the site would need to use the new longhands (which it doesn't know about), no? Also, using setPropertyValue with an empty string has no effect, doesn't it? But yes, even though I didn't quite follow the above example, I see that variations of that could break. E.g. setting white-space first, then e.g. setting text-wrap:initial through enumeration. (That's not alphabetical order, but ignore that ..)

Loirooriol commented 1 year ago

To serialize as an empty string, the site would need to use the new longhands

Not necessarily explicitly, e.g. this would work if overflow wasn't a shorthand, without directly using overflow-x/y:

var style = document.createElement("div").style;
style.overflow = "var(--overflow)";
var clone = document.createElement("div").style;
for (let p of style) {
  clone.setProperty(p, style.getPropertyValue(p), style.getPropertyPriority(p));
}
clone.cssText // "" :(

using setPropertyValue with an empty string has no effect

It has effect, it removes the previous value (for all longhands in case of a shorthand):

document.body.style.cssText = "grid: 1px / 2px; grid-auto-flow: column";
var cs = getComputedStyle(document.body);
var clone = document.createElement("div").style;
for (let p of cs) { // Imagine this iterates `grid` after its longhands, like [...cs, "grid"]
  clone.setProperty(p, cs.getPropertyValue(p), cs.getPropertyPriority(p));
}
[...clone].includes("grid-template-rows"); // Would be false
gsnedders commented 1 year ago

This is observable in that e.g. Array.from(getComputedStyle(e)) will no longer contain white-space.

Whether gCS should include shorthands is #2877.

LeaVerou commented 1 year ago

This could be fixed and improve DX in one fell swoop by simply including shorthands that can be serialized in getComputedStyle(). Shorthands not being included has been a huge PITA for authors.

I recall @tabatkins saying that it is well defined whether a shorthand can be serialized from longhands, but I can't remember where.

Loirooriol commented 1 year ago

The PITA was getPropertyValue() failing to serialize shorthands in a computed style, which used to happen in Firefox, but works now as resolved in #2529.

Not including shorthands in item() seems desirable to me.

Whether a shorthand can be serialized is defined in https://drafts.csswg.org/cssom/#dom-cssstyledeclaration-getpropertyvalue, basically:

fantasai commented 1 year ago

Blink keeps deciding to ship weird things that are not spec-compliant and using this issue as an excuse, so adding it to the agenda.

gsnedders commented 1 year ago

Blink keeps deciding to ship weird things that are not spec-compliant and using this issue as an excuse, so adding it to the agenda.

…can you actually give at least one example here, rather than just vaguely alluding to things here? For those of us not closely paying attention to everything, we lack context, which isn't an ideal place to be going into a meeting.

fantasai commented 1 year ago

@gsnedders See thread at https://groups.google.com/a/chromium.org/g/blink-dev/c/f5eLz6PIXaI/m/a9OGhvaNAAAJ for the latest

dbaron commented 1 year ago

I've seen 3 such discussions: baseline-source, text-wrap: balance thread #1, text-wrap: balance thread #2 (cited above).

dbaron commented 1 year ago

Also, baseline-source is tied in to a longhand-to-shorthand refactoring that has a very complicated history and is thus significantly more risky (particularly for existing SVG content, I think) than a "normal" refactoring of a longhand into a shorthand.

birtles commented 1 year ago

I think there might be others around web animations. I think if you transition a shorthand you might get multiple CSSTransition objects rather than one?

Yes, that's right. Not only will there be one CSSTransition per animated longhand but CSS Transitions will also dispatch one TransitionEvent per animated longhand (as exposed by TransitionEvent's propertyName member).

You can see an example here: https://codepen.io/birtles/pen/wvYrdPo

Web Animations is able to handle shorthands, but CSS Transitions is defined in terms of transitions on longhand properties hence the behavior here.

This is probably fine for white-space since we only just recently made it possible to transition discrete-value properties, but in general changing longhands to shorthands can break code that is expecting to find a TransitionEvent with a given propertyName or CSSTransition object for a given transitionProperty.

For example, code such as the following:

// Trigger a transition on the white-space property
elem.style.whiteSpace = 'normal';
elem.style.transition = 'white-space 2s';
getComputedStyle(elem);
elem.style.whiteSpace = 'pre';

// Fetch the corresponding CSSTransition object
const whiteSpaceTransition = elem
  .getAnimations()
  .find(
    (anim) =>
      anim instanceof CSSTransition && anim.transitionProperty === 'white-space'
  );

whiteSpaceTransition.finished.then(() => {
  // Update the rest of the UI
});

This will break once white-space becomes a shorthand. Similar code can be written in terms of TransitionEvents.

I suppose we could introduce some sort of mapping in CSS Transitions for "legacy longhands" to maintain the existing behavior.

There's also potential breakage in the keyframes exposed for CSS Animations since they end up getting expanded to longhands as part of the cascade.

anhtaiH commented 1 year ago

Hello 👋🏼 — I'm Tai an engineer at Webflow. Within this context, I'm a developer building a visual abstraction for HTML/CSS using the underlying browser APIs (like getComputedStyle).

We recently had a regression due to changes to white-space. Here's the report https://bugs.chromium.org/p/chromium/issues/detail?id=1449763.

We've found a workaround to unblock our users in the meantime, but just wanted to drop by and provide feedback that these types of changes may unexpectedly break sites that assumed that APIs worked a certain way.

Thank you all! 🙇🏼

LeaVerou commented 1 year ago

Hi @anhtaiH! 👋🏼 It’s great to have participation here from tools like Webflow, hope to see more of y'all around!

You could use the newer computedStyleMap(), which does support shorthands when they are serializable 😊

dbaron commented 1 year ago

For the case in https://github.com/w3c/csswg-drafts/issues/8398#issuecomment-1568802501, I think the underlying issue is not whether the property is present in the result of getComputedStyle() (it should be) but whether you see the property when enumerating that result (it is not).

andruud commented 1 year ago

I initially thought css-typed-om might be a problem, since there is no shorthand support there. (But then I found that the spec seems to allow it, it's just Blink's incomplete implementation that doesn't support it).

@kojiishi points out that this is actually a (spec) problem too:

https://drafts.css-houdini.org/css-typed-om/#computed-stylepropertymapreadonly-objects:

If this’s [[computedStyleMapCache]] internal slot is set to null, set its value to a new StylePropertyMapReadOnly object, whose [[declarations]] internal slot are the name and computed value of every longhand CSS property supported by the User Agent, every registered custom property, and every non-registered custom property which is not set to its initial value on this, in the standard order.

Loirooriol commented 1 year ago

Just like for getComputedStyle, I think that only having the longhands is reasonable. It's just that StylePropertyMapReadOnly.get() should somehow handle shorthands, like CSSStyleDeclaration.getPropertyValue()

tabatkins commented 1 year ago

@kojiishi points out that this is actually a (spec) problem too: [spec says the map only contains longhand properties]

Huh, I'm not sure why I wrote that, actually. Weird. Definitely should be fixed.

css-meeting-bot commented 1 year ago

The CSS Working Group just discussed [cssom] How safe is it really to shorthandify properties?.

The full IRC log of that discussion <dael> [hunting for the agenda + reason]
<dael> astearns: This isn't the first time we got to it and didn't know what to discuss. I suggest we take agenda + off until we have an idea what to discuss.
<dael> fantasai: That's fine. I think it's a non-APAC item. I'd like the issue resolved
tabatkins commented 5 months ago

Okay, so if I'm correctly re-reading the above, whenever you shorthandify a property, it changes behavior in the following two back-compat-relevant ways:

  1. It's no longer enumerated in CSSStyleDeclarations (its longhands are, instead).
  2. It no longer shows up in CSSTransition or TransitionEvent objects (its longhands do, instead).

The longer a property has been not a shorthand, the more likely it is that one or both of the above will break in deployed code, thus making it incompatible to shorthand the property. (See, for example, https://g-issues.chromium.org/issues/40269890 reporting that (1) caused breakage for a site due to white-space becoming a shorthand.)

Chrome is, in fact, doing something custom for white-space and text-wrap rather than shorthanding normally, to avoid some of these issues. (I'm not sure of the exact details; Koji or Ian would know better.) We're fairly certain we'll have similar problems with position (from #10321).


We have a big set of existing shorthands that we also can't change the behavior of - they need to not enumerate, and not show up in transitions.

So, the simplest answer is just: we define, for a small set of compat-required new shorthands, that they do enumerate and do show up in transition JS objects, despite being shorthands.

Enumeration ordering is likely important to preserve. Alphabetical ordering will usually automatically place the shorthand before its longhands, but when that isn't the case, we'll have to explicitly specify a break from alphabetical ordering to maintain the "shorthand comes first" property. Assuming the shorthand is the legacy property, we'd leave it where it always was and say that the new longhands, which would otherwise precede it, instead come right after it.

Open question: is this a behavior we want to apply to all shorthands going forward (and thus we require an explicit, fairly large, list of grandfathered shorthands that don't serialize)? Or do we want to let new stuff stay consistent with old stuff, and only invoke this special behavior when we're doing a compat-constrained "upgrade" shorthandification? I suspect we want the latter; it's far fewer cases overall, and the existing behavior is well-established across dozens of shorthand properties.

Is there anything else we'd need to define for these "upgraded" properties? Or is that it?

Loirooriol commented 5 months ago

How does the indexing work if you have both the shorthand and its longhands? For example:

var {style} = document.createElement("div");
style.cssText = "white-space: pre";
[...style]; // Presumably [ "white-space", "white-space-collapse", "text-wrap-mode", "text-wrap-style" ] ?
s.removeProperty("text-wrap-style");
[...style]; // Maybe [ "white-space-collapse", "text-wrap-mode" ] ???
            // Or [ "white-space", "white-space-collapse", "text-wrap-mode" ] ???
s.removeProperty("white-space-collapse");
s.removeProperty("text-wrap-mode");
[...style]; // Hopefully not [ "white-space" ] ??????

It seems this would need extra logic in setProperty and removeProperty to automatically insert or remove a shorthand if necessary (maybe when all longhands are present, or when any longhand is present). Need to ensure this doesn't cause perf regressions.

Loirooriol commented 4 months ago

I'm also concerned that the proposal might affect code doing something along these lines:

for (let i = style.length - 1; i >= 0; i -= 1) {
  style.removeProperty(style[i]);
}

If removing longhands can remove a preceding shorthands, this will mess the indices, making style[i] go out-of-bounds, or if only some properties are removed, possibly revisit an already iterated one. The specific code above won't throw nor anything, but if the author is doing additional things with style[i], it could be bad.

fserb commented 4 months ago

@Loirooriol this particular code snippet would also be broken even with only longhands. steelmanning the argument: the problem is that having both shorthands and longhands would make it extremely hard to "do the right thing" in a loop.

But one could argue that removing things in indexed loops is always a bit cursed.

tabatkins commented 4 months ago

Yeah, if you were doing that you'd have to index in reverse for safety, but the shorthand disappearing would still mess things up.

Loirooriol commented 4 months ago

@fserb How is it broken with only longhands? Iterating backwards should be fine, currently.

css-meeting-bot commented 4 months ago

The CSS Working Group just discussed [cssom] How safe is it really to shorthandify properties?.

The full IRC log of that discussion <emeyer> fantasai: We often want to extend CSS by turning an existing proeprty into a shorthand
<emeyer> …There are compatiobility problems with that
<emeyer> …This shows up in ennumeration of CSS style declarations, which is only supposed to ennumerate longhands
<emeyer> TabAtkins: We have some compatibility issues with turning anything into a shorthand
<emeyer> …A few APIs only care about longhands
<emeyer> …Sudden losses of properties cause bugs in people's programs
<emeyer> …We saw this with white-space and another one that escapes me
<emeyer> …Chrome got some bugs reported and ended up implementing a third, worse behavior
<lea> Seems like the appropriate solution is to fix these APIs, not to stop shorthandifying properties. Shorthands not showing up in these APIs (when they could be serialized) is a common author pain point.
<emeyer> …we prefer not to do that again, especially for things like positoin
<dbaron> (were you thinking of vertical-align as the other one?)
<emeyer> …We suspect position is un-shorthand-able
<lea> q+
<emilio> we did shorthandify something really old (overflow) without that much pain, right?
<oriol> q+
<emeyer> …David, you're right, it was vertical-align
<emeyer> …Emilio, I don't know how much pain there was with overflow
<fantasai> emilio, that was expanded out a very very long time ago; we just expanded the shorthand to allow two keywords recently
<emeyer> florian: Were you going to explain how to work around this with that behavior?
<dbaron> (I think overflow was a shorthand in WebKit from very long ago.)
<emeyer> TabAtkins: No, we really don't like it, and we don't want to do it any more
<astearns> ack lea
<emeyer> lea: Seems like we should fix the APIs, not stop fixing CSS
<una> q+
<emeyer> …Shorthands not showing up in APIs is a perpetual author pain point
<fserb> +1 to that
<emeyer> oriol: Don't completely agree with Lea
<emilio> q+
<emeyer> …if you ask for a shorthand, you get a list of all the longhands, which seems normal
<emeyer> …I think it's duplicated information to have both shorthands and longhands
<florian> q+
<emeyer> …From Tab, I have concerns about duplicating things
<emeyer> …Inline styles can be modified by CSSOM and that concerns me
<fserb> q+
<astearns> ack oriol
<emeyer> …If you remove some longhands, keeping the shorthands would be broken, so there would need to be checks to avoid that
<emeyer> …If you're iterating longhands from end to beginning, and removing some, that would mess up indexes and you could end up going out of bounds
<emeyer> …Depending on what the author is doing, the application can break
<lea> q+ to say the current design is clearly problematic, and these don't seem like dealbreakers, just like the usual design decisions we need to make with every feature. And they certainly don't prove that we shouldn't even explore that avenue. I don't see how removing shorthands when the longhands are removed is that different from adding longhands when a shorthand is specified, it's not like what the author specified is preserved exactly
<astearns> ack una
<emeyer> una: An example of where shorthands add confusion is recently we implemented transition-behavior with discrete value
<TabAtkins> transition-behavior: allow-discrete
<emeyer> …The transition acutally overrides the longhand
<emeyer> …This is one example where we'd let authors opt in, but we can't do that now
<emilio> q-
<emeyer> …Shorthands aren't always better and can add confusion
<astearns> ack florian
<una> s/discrete/allow-discrete
<emeyer> florian: Need to think about this further, but for these APIs that care about the difference between short and longhands
<emeyer> …If the values in use can be represented through the shorthand, then we include the shorthand only in the serialization
<emeyer> …If not, then we'd include the longhands only in the APIs
<emeyer> emilio: That causes really weird behavior
<emeyer> …The set of anuimated properties can become longer, and would change longstanding behavior
<emeyer> …You would maybe expect the four margin longhands, but suddenly you just get margin
<emeyer> …This would make computing the length of the ennumerator difficult
<emeyer> TabAtkins: I presume this would only apply for the handful of properties we list out
<emeyer> florian: I think emilio's point is good; there are a bunch of proeprties we can't do this for
<emeyer> …But could it work if we scoped it to certain properties?
<emeyer> …We could let existing proeprties continue to act as is, but open up new behaviors
<emeyer> dbaron: I think a bunch of this is going in a direction that's not the problem we need to address
<emeyer> …This is more about ennumeration and not about serialization
<astearns> ack fserb
<emeyer> fserb: I'm confused about the scope of the question, whether it's about ennumeration or is it more generic?
<emeyer> florian: I think if you could serialize as the shorthand, you would do that; if you can't, then you wouldn't
<astearns> ack fantasai
<Zakim> fantasai, you wanted to discuss minimal compat fix
<emeyer> fantasai: I think as Tab said, we can't do this for all proeprties
<emeyer> …For transition stuff, perhaps we could include both shorthand and longhand safely
<emeyer> …For the ennumeration, we'd keep a list and if the longhands can be represented as a shorthanded value that's one of the values that are legacy-constrained
<oriol> q+
<emeyer> …If the longhands have extra values that can't be represented in that limited syntax, we ennumerate the longhands
<emeyer> …So for white-space, if you gave it some new unrecognized value, then you'd ennumerate the longhands
<emeyer> dbaron: My understanding of the ennumeration problem is that there's no concern whatsoever about the values
<emeyer> …I believe the problem is that if you do a JS ennumeration through CSSOM, it gives you a list of every longhand property in CSS
<florian> q+
<emeyer> …It doesn't matter what's been specified, it's just a list of everything
<emeyer> …I think we've fixed the serialization problems
<emeyer> …We have problems with mechanisms that let you ennumerate weverything in CSS, which have no value depends at all
<astearns> ack dbaron
<emeyer> s/depend/dependence/
<emeyer> …It's possible there are other problems here, but does anyone think I was wrong about that?
<emeyer> TabAtkins: No
<astearns> ack lea
<Zakim> lea, you wanted to say the current design is clearly problematic, and these don't seem like dealbreakers, just like the usual design decisions we need to make with every feature.
<Zakim> ... And they certainly don't prove that we shouldn't even explore that avenue. I don't see how removing shorthands when the longhands are removed is that different from adding
<Zakim> ... longhands when a shorthand is specified, it's not like what the author specified is preserved exactly
<astearns> q+ dbaron
<emeyer> lea: Back to what Oriol was saying, we know the CSSOM is problematic
<emeyer> …We need to explore some of these avenues to see if what we come up with, we need to check if it will make things worse or better
<emeyer> …Authors specifying shorthands and getting back longhands is just as confusing as making shorthands disappear when longhnads disappear
<emilio> q+
<emeyer> …Authors almost never intend to get back the entire list of of all properties
<TabAtkins> These enumerations are used by some tooling, that's who reported compat bugs
<emeyer> …If authors ask for a border, they can't get any shorthands, they have to get a very specific longhand
<emilio> dbaron: In specified declarations, we do only enumerate specified longhands
<emeyer> oriol: If you ask for the border, you get the border, you get the serialized values
<emeyer> …I do agree with dbaron, this isn't a value problem
<astearns> ack oriol
<emilio> It's only getComputedStyle() which returns all longhands
<emeyer> …If you change the value of a longhand or a shorthand, a shorthand stops being serializable
<emeyer> …This would make things unreliable
<astearns> ack florian
<emeyer> lea: I was just writing that parts of the CSSOM seem to have improved
<emeyer> florian: I'm not approaching this as serialization, I agree it's about ennumeration
<emeyer> …It may be this is a bad idea, but I think all the cases you mentioned about ennumeration, they all depend on contexts where you could go on to get the value
<emeyer> …If there isn't the notion of being able to ask, then what I propose would become impossible
<emeyer> …If you can go on to ask about the values after you ennumerate, then this linkage can be made
<emeyer> …In order to preserve shorthands as standalone properties, this would introduce a dependency, and has the downside that the set of properties and their indexes would change
<lea> +1 to florian
<emeyer> …Itæs a tradeoff, but it might be a worthwhile tradeoff
<astearns> ack dbaron
<emeyer> dbaron: I think from the JS perspective, what Oriol is suggesting would be really strange
<emeyer> …I admit I haven't paid a ton of attention to JS engine optimizations, but back when I did, there was much done based on type inference
<emeyer> …Making an object have different properties means now CSS style isn't really a type, it's hundreds of types
<emeyer> iank_: It changes the shape
<emeyer> dbaron: We're talking at the boundary of the CSSOM and JS
<emeyer> florian: Not quite undoable, but very near>
<emeyer> dbaron: Yes
<emeyer> fantasai: So you're saying this thing we're ennumerating always returns every property in CSS?
<emeyer> dbaron: Yes
<emeyer> …If you use an ennumeration in JS to ask what all the fields in a CSS style are, you get all the CSS properties
<emeyer> fantasai: And ennumerating the short and longhands would break in what ways?
<bramus> +1 to dbaron
<lea> q?
<astearns> ack emilio
<emeyer> dbaron: If we could do it, that might work, but I don't know if that would break anything
<emeyer> emilio: I don't know if that's true
<fantasai> s/short and longhands/shorthands in question and their longhands/
<lea> q+ Not sure I understand what's strange from a JS perspective. Enumerating objects whose properties have dependencies between them is pretty common? Also, is the proposal to *only* include shorthands? I thought it was to include both…
<lea> q?
<emeyer> …When you ennumerate specific CSS declarations, you get the longhands that are specified in that declaration
<florian> s/ but very near>/ but very weird?
<lea> q+
<emeyer> … .length is how many longhands you have in there
<dbaron> https://www.software.hixie.ch/utilities/js/live-dom-viewer/?%3C!DOCTYPE%20html%3E%0A%3Cbody%20style%3D%22margin%3A%202em%22%3E%0A%3Cscript%3E%0Afor%20(var%20i%20in%20document.body.style)%20%7B%0A%20%20document.write(i%20%2B%20%22%3Cbr%3E%22)%3B%0A%7D%0A%3C%2Fscript%3E
<emeyer> iank_: I believe dsome of our compatibility problems came from ennumerating
<dbaron> emilio, see above testcase
<emeyer> emilio: Preserving shorthands in specified styles is a relatively big change, but seems doable
<florian> q+
<emeyer> …Doing it in getComputedStyle is a bit tricky
<emeyer> dbaron: I don't think that's the issue
<dbaron> dbaron: I think it was (for i in document.body.style)
<lea> dbaron's demo with values: https://codepen.io/leaverou/pen/KKLXqBw?editors=1111
<emeyer> emilio: A lot of things we've been discovering have been different
<astearns> ack lea
<emeyer> lea: ASking David what is weird from the JS perspective
<emeyer> …Is the proposal to remove longhands?
<emeyer> dbaron: I'm not sure what you mean by dependencies and if there was a proposal
<emeyer> …I think maybe it was to include shorthands in a place that only has longhands
<fserb> q+
<emilio> `for (let i in document.body.style) { console.log(i) }` does include shorthands
<emilio> (In Gecko at least)
<emeyer> TabAtkins: That appears to be a requirement of whatever we settle on
<astearns> ack florian
<emilio> q+
<emeyer> florian: I think we effectively have three proposal to consider
<emeyer> …1. Sometimes don';t include longhands
<lea> What I was proposing was to include *both* longhands and shorthands.
<dbaron> emilio, it doesn't include "font" in the url I gave above
<emeyer> …2. The list of properties you ennumerate depends on the actual values
<emeyer> …3. For a subset of properties, list both the shorthands and longhands only
<emeyer> …You'd have to make it a subset because there are historical properties where doing that would break things
<emilio> dbaron: it does for me? (the codepen console eats it because too many properties)
<emeyer> fserb: This is just about the ennumeration?
<emeyer> florian: Yes
<fantasai> s/dbaron:/dbaron,
<lea> emilio: Open the browser console
<emeyer> …I suspect alternative 3 is the simplest, but I don't know if it's possible
<astearns> ack iank_
<astearns> ack IanK
<Zakim> IanK, you wanted to clarify what exactly the problems are that we're running into
<emeyer> fantasai: Ian, what are the problems and what are we trying to solve?
<emeyer> iank_: I'd have to go back and see what we found
<dbaron> emilio, oops, you're right -- they're in a very strange order!
<emilio> lea, `{ let found = false; for (let i in document.body.style) { found = found || i == "font" } console.log(found) } ` logs true here
<emeyer> …I worry that optoin 3 would open a separate can of worms
<emeyer> astearns: We could resolve on opening that can of worms to see what we find
<florian> q?
<lea> emilio: Yes, that's what I'm noticing in Chrome too. Then what's the issue?
<florian> qq+
<emilio> q+
<emilio> dbaron, See above? ^
<fantasai> [note to scribe to keep lea/emilio chat as a side-converstaion, not as corrections to the minutes]
<astearns> ack fserb
<emeyer> fserb: Can someone speak to the use case here?
<emeyer> …What's the use case for ennumeration?
<dbaron> ok, yeah, chrome and gecko both seem to include shorthands in enumeration... I'm not sure what the issue is
<emeyer> …What do we care about, and what do we not?
<emeyer> florian: I'm not approaching this as any particular use case, but from the place where thaere are cases where it's useful
<emeyer> …But things are not posisble with how we do ennumeration now
<oriol> for...in just does the normal JS thing, right? I thought we were talking about for...of
<emeyer> fserb: This works when we query the properties, yes?
<emilio> dbaron, my understanding is that `style.cssText = "font: ...;"; [...style].includes("font")` is `false`, but that's the same `.length` bit that I commented above
<masonf> q+
<emeyer> …There is a thing about people getting confused, but I would argue having both would make people more confused
<oriol> +1 that having both is just more confusing
<emeyer> …If you want just a sense of properties, having to do the extra work of knowing the shorthand means you can't get the bag of properties
<emeyer> florian: The way I'm thinking about this is not about what makes sense in theory but what we can do that doesn't break compaibility
<emilio> oriol, so yeah, my understanding is that what you said is correct, but that might be solvable in different ways depending on whether compat issues are in the specified style and computed styles
<lea> q+ to say This discussion makes me think we also need a data structure that allows authors to read what is a shorthand of what. Also relevant to this future TAG principle: https://github.com/w3ctag/design-principles/issues/300
<emeyer> …So I had a question to Ian, earlier, what kind of can or worms were you talking about?
<emeyer> …Did you mean there are some properties where changing this breaks things?
<astearns> ack florian
<Zakim> florian, you wanted to react to IanK
<emeyer> …Or is this more about the API shape itself?
<astearns> zakim, close queue
<Zakim> ok, astearns, the speaker queue is closed
<emeyer> iank_: My thesis at the moment is that properties that have been around since time immemorial is more likely to have author depending ont he ennumeration
<emeyer> …Things that are more recent, much less likely
<masonf> q-
<emeyer> …What we had to do with white-space was a lot more extensive
<emeyer> florian: So I propose for all properties that exist, we do what we've been doing, but for any new property or newly shorthanded properties, we list both shorthand and longhand
<dbaron> emilio, here's the actual testcase (thanks to Ian): https://www.software.hixie.ch/utilities/js/live-dom-viewer/?%3C!DOCTYPE%20html%3E%0A%3Cbody%3E%0A%3Cscript%3E%0Avar%20cs%20%3D%20getComputedStyle(document.body)%3B%0Afor%20(var%20i%20%3D%200%3B%20i%20%3C%20cs.length%20%3B%20%2B%2Bi)%20%7B%0A%20%20document.write(cs%5Bi%5D%20%2B%20%22%3Cbr%3E%22)%3B%0A%7D%0A%3C%2Fscript%3E
<emeyer> …Is that something we can do, whether or not we should?
<emilio> I think I have a proposal, if this is for the computed style
<emeyer> andruud: Would that help?
<lea> In terms of API design, that seems like the worst of all worlds. How are we supposed to explain this to authors?
<emeyer> …In the position case, we don't touch that since it's been around since forever?
<emeyer> florian: No, if we shorthandify that, we would do the new thing, but we don't do it to things like margin
<emeyer> andruud: Can we research this can of worms without opening it?
<emeyer> iank_: I don't know
<lea> q?
<matthieud> q+
<emeyer> astearns: I've closed the queue since I'm not hearing consensus or conclusions
<emeyer> emilio: We need to distinguish the computed and specified styles
<emeyer> …We can have a shorthand list and the only thing we need to make sure is the whole longhand space can be represented by the shorthand
<emeyer> iank_: I think it depends on how it's being used
<oriol> +1 most of my concerns are about non-computed styles, since you can modify them
<emeyer> emilio: I propose that if this is about the computed style, we can do this easily
<emeyer> …If this is about the specified style, that's a bigger change
<emeyer> …When the CSS parser parses white-space, it ends up with a bunch of longhands
<emeyer> …We could make it not do that, but that would be a big change
<matthieud> q-
<emeyer> …Having a flag on a shorthand would be trivial-ish?
<astearns> ack emilio
<emeyer> dbaron: Ian and I have been test casing and one of the things I said earlier was wrong
<emeyer> …`i in foo` is wrong for where the compatibility exists
<emeyer> …it's more in `i to length`
<emeyer> …The ennumeration order has the shorthands first and then the longhands
<emeyer> …The problem may be computed-style only
<masonf> The `white-space` compat problem we encountered was that `for(s of getComputedStyle)` was missing `white-space`.
<astearns> ack lea
<Zakim> lea, you wanted to say This discussion makes me think we also need a data structure that allows authors to read what is a shorthand of what. Also relevant to this future TAG
<emeyer> …Again, we probably need more test cases to be sure we're talking about the right thing.
<Zakim> ... principle: https://github.com/w3ctag/design-principles/issues/300
<emeyer> lea: I think we have consusensus we don't want to stop shorthandifying properties
<emeyer> …Breaking properties into BC/AD seems like the worst solution
<emeyer> …Exceptions make APIs really hard to explain
<emeyer> …By principle of least surprise and assuming most authors use lookup instead of ennumeration, we could make changes
<emeyer> …We could really use methods that allow authors to ask what is a shorthand of what
<astearns> +1 to introspection of shorthand/longhand relationships
<emeyer> …This is also compatible with the TAG future design principle of allowing introspection
<oriol> You can currently know what is a shorthand of what with the current API. The proposals here would break that.
<emeyer> astearns: Sounds like we need more tests and finding the smallest can of worms we can open
<lea> s/Exceptions make APIs really hard to explain/How are we supposed to explain this to authors? I'd much rather add one-off exceptions, but I'm not convinced we even need to do that./
<emeyer> fantasai: There was also an issue around transition events
<emeyer> dbaron: I think that's the harder half
<emeyer> …That said, I think we made the easy half hard by talking about what it is instead of solving it
<emeyer> …And I also think we still don't know
<lea> s/We could really use methods that allow authors to ask what is a shorthand of what/There should be a data structure for authors to read what is a shorthand of what, so that if they're doing some complicated thing they at least can figure out what is happening, which is incredibly tricky right now (I’ve tried to do it!)./
<emeyer> astearns: Leaving this for now
chrishtr commented 4 months ago

Overall, the Chrome team's consensus position is that shorthandifying well-established properties after the fact is risky, has significant implementation and developer-churn/confusion cost, and generally doesn't provide enough developer benefit to justify this risk, churn and cost. So we're opposed to doing that generally.

Therefore, I suggest we resolve the issue (8398) with this design guidance: "don't shorthandify well-established CSS properties".

(Aside: in addition, Tab commented here about additional reasons beyond the above why we should't shorthandify position for anchor positioning. However, his arguments have some relationship to my points above, since they are an example of how shorthands can be more confusing than the alternative.)

css-meeting-bot commented 4 months ago

The CSS Working Group just discussed [cssom] How safe is it really to shorthandify properties?.

The full IRC log of that discussion <chrishtr> fantasai: this was a question we discussed during the F2F
<chrishtr> fantasai: wanted to follow up and see what the issues are, and what it takes to resolve them
<fantasai> scribe+
<chrishtr> fantasai: in order to make progress
<fantasai> chrishtr: For well-established CSS properties (have significant usage across browsers), it's not worth it to shorthandify them after the fact
<fantasai> chrishtr: so we shouldn't do that
<fantasai> chrishtr: It's not worth the effort / risk / churn / cost of implementation and testing and potential compat risk
<florian> q+
<chrishtr> florian: you're right that there is a significant cost, churn, etc. and so we shouldn't do it lightly
<Rossen7> ack florian
<chrishtr> florian: but if there are strong reasons for a particular case we might want to do it despite the risk and cost
<chrishtr> florian: for such cases we should figure out how to do it, for such rare cases
<Rossen7> ack fantasai
<chrishtr> fantasai: this is a kind of important extension point for CSS, so it'd be good to find out how we can mak it less risky, in cases where it's justified
<chrishtr> rossen: should we continue such discussion in the issue?
<chrishtr> rossen: or should we accept the proposed resolution, and then continue to work on the issue for exception situations?
<flackr> q+
<oriol> q+
<fantasai> https://github.com/w3c/csswg-drafts/issues/8398#issuecomment-2123561486
<chrishtr> fantasai: chris are there issues other than the ones Tab mentioned on issue 10004?
<chrishtr> chrishtr: my other concerns are the ones I mentioned in the comment (developer confusion/churn, cost of implementation, ...)
<fantasai> s/10004/8398/
<dbaron> (with the caveat that I think the description of the first of Tab's 2 issues is more complicated than what Tab described, as we discussed at the face-to-face)
<chrishtr> chrishtr: don't know of specific compat risks other than then ones mentioned in Tab's comment on 8398 above
<Rossen7> ack flackr
<chrishtr> flackr: maybe we could resolve not to do standard shorthandification, but if there was a way we can do it that avoids compat risk we could accept that?
<emilio> +1 to fantasai
<chrishtr> fantasai: i f we don't have a mitigation then it would have to be on a case-by-case basis
<dbaron> fantasai: If we don't have a mitigation I think it should be on a case-by-case basis.
<chrishtr> oriol: wondering what is meant by "well-established", maybe we could experiment with a specific case and learn more?
<florian> q+
<chrishtr> chrishtr: what I meant by well-established is a CSS property that has been around a while and is relatively widely used on sites
<Rossen7> ack oriol
<chrishtr> oriol: for particular cases it's still possible it wouldn't break anything
<chrishtr> oriol: is the position that implementations don't want to take the risk?
<chrishtr> chrishtr: yes, chrome would prefer to spend its effort elsewhere
<chrishtr> florian: not shorthandifying would lead to us introducing more longhands from the get go even when they're not needed yet when we can imagine needing them for a later extension of a feature
<chrishtr> florian: whereas shorthandifying we'd potentially be able to have fewer
<chrishtr> florian: think we should still try to find mitigations
<fantasai> +1 florian, we've done this multiple times
<Rossen7> ack florian
<chrishtr> florian: we shouldn't do things with risk without limitation, but shouldn't ban it either
<fantasai> s/more longhands/more longhands when designing new features, for example we often design a simpler feature in the first iteration/
<chrishtr> florian: don't think we should ban it
<chrishtr> flackr: don't think anyone is proposing a ban
<chrishtr> florian: proposed resolution would amount to a ban?
LeaVerou commented 4 months ago

The proposed resolution the minutes are referring to doesn't seem to have been captured but strong -1 to what @chrishtr proposed above. Shorthandifying properties are one of the very few paths we have to evolve CSS without balooning its number of primitives. Unless we come up with an alternate path (e.g. actually deprecating properties with the intent to later remove), I don’t think it’s a good idea to stop doing this.

If the issue is the CSS OM inconsistencies, let’s fix the CSS OM, and add introspection so that authors can read a data structure about what is a shorthand of what.

nt1m commented 3 months ago

Not sure this is relevant, but WebKit has logic to enumerate all longhands instead of just enumerating the shorthand: https://searchfox.org/wubkat/rev/b36cbce69fddb7da33823f316bd8ead5bebee970/Source/WebCore/css/StyleProperties.cpp#201

Apparently this behavior is already defined: https://www.w3.org/TR/css-cascade-5/#legacy-shorthand

Can't we reuse this for whatever new shorthands we introduce?