Repository navigation
[css-text-3] Don't mince words about aliasing/shorthands with word-wrap #866
Description
https://drafts.csswg.org/css-text-3/#propdef-word-wrap
The spec says:
For legacy reasons, UAs must treat word-wrap as an alternate name for the overflow-wrap property, as if it were a shorthand of overflow-wrap.
The "as if it were a shorthand" is a bit hand-wavy, especially since "as an alternate name" can mean something else.
In particular, we have two different ways of "aliasing" properties. One is by making them shorthands of the aliasee. The other is by making them redirect to the other property at parse time.
The difference crops up when doing things like serializing property declaration blocks. For example, the following CSS:
#foo {
word-wrap: break-word;
overflow-wrap: break-word;
align-items: flex-end;
-webkit-align-items: baseline;
foobar: baz;
}when serialized via document.styleSheets[0].cssRules[0].cssText in Firefox produces "#foo { overflow-wrap: break-word; align-items: baseline; }", whereas in Chrome/Safari it produces "#foo { word-wrap: break-word; overflow-wrap: break-word; align-items: baseline; }". This means that Firefox implements it as a "redirect alias", but Chrome/Safari implement it as a shorthand alias. All of them handle -webkit-align-items as a "redirect alias".
Browsers already use "redirect aliases" consistently for aliasing legacy prefixed properties. This concept of an alias is not defined in the spec, but is consistently implemented in browsers as something akin to:
If foo is an alias for property bar:
- At parse time, if you encounter a property of name
foo, treat it as if it were the name you encountered was of propertybar - In CSSStyleDeclaration add accessors for the alias
foothat under the hood work with propertybar - Nowhere else should there be traces of the name
foo(including during serialization of a declaration block)
The compat spec uses this concept of "aliasing", but does not define it.
We should either explicitly spec word-wrap to be a shorthand, or define this other concept of property alias in the spec and use it here (and also use it in the compat spec). I personally prefer the latter solution since aliasing is currently unspecced but imo shouldn't be, and because this is the only case where a shorthand is used for aliasing.
Activity
dholbert commentedon Jan 6, 2017
For reference, here's a link to where Firefox implemented this property as an alias (rather than a shorthand). I think we could just as easily implement it as a shorthand if it were clearly specced as such, though I agree with @Manishearth that an alias seems strictly simpler & more appropriate for legacy stuff (if aliases are a speccable concept).
dbaron commentedon Jan 6, 2017
I'd also note that the normal rules for shorthands would produce a third result that is both (a) undesirable and (b) neither the Firefox nor the Chrome result, i.e., serializing the above rule to:
"#foo { word-wrap: break-word; align-items: baseline; }", since it's possible to "condense" the declaration into a shorthand.This is by the same principle that:
produces:
in both Firefox and Chrome.
I think that also suggests that we need to specify the concept of aliases.
dholbert commentedon Jan 6, 2017
FWIW, the spec-text for
word-wrapused to be as follows:https://www.w3.org/TR/2012/WD-css3-text-20120119/#overflow-wrap
The language was changed to its current form ("as an alternate name...as if it were a shorthand") in this commit in 2012: 0532714
dholbert commentedon Jan 6, 2017
(For the record, I filed https://bugs.chromium.org/p/chromium/issues/detail?id=679068 and https://bugs.webkit.org/show_bug.cgi?id=166782 on the odd Blink/WebKit behavior here. It doesn't seem like they're actually treating it as a shorthand -- they're doing some special alternate form of aliasing, distinct from their regular legacy-alias behavior.)
Manishearth commentedon Jan 7, 2017
cc @miketaylr since the compat spec references this concept of aliasing without defining it (and we should take input from them if we start building the exact definition)
frivoal commentedon Jan 7, 2017
The wording is unintentionally loose, but the intent was to make it a shorthand. If we want to keep that, we should update the phrasing to:
Some of the reasoning for that is documented here: https://wiki.csswg.org/ideas/aliasing
TL;DR: we had a reasonably extensive discussion about how aliasing should work when "aliasing" break-before and page-break-before, and figured that shorthands were a good way to do that: well defined (including the OM) without needing to introduce any new concept, generally well behaved, deals well with the case when the legacy prop and the new prop don't have the exact same set of values.
I still think the idea has merit to it, but if implementations generally agree on a different aliasing mechanism, we should spec it and use that. Spec-fiction doesn't help anyone. Maybe we can keep exceptions and use shorthands when the legacy prop and the new prop accept different values.
dholbert commentedon Nov 4, 2017
This doesn't actually seem to be what Chromium does for the few properties where they (ab)use shorthands to do aliasing.
Sample (live jsfiddle version):
This testcase produces
break-inside: avoid;even though they implement-webkit-column-break-insideas a shorthand forbreak-inside, as shown here in their source and as noted in https://bugs.chromium.org/p/chromium/issues/detail?id=679068#c11So, they do the Right Thing here, even though it's the opposite of normal shorthand behavior. (I wonder if that's due to a special-case codepath for shorthands that are only shorthands of a single property, maybe?)
frivoal commentedon Dec 14, 2017
@dholbert @dbaron Since you consider shorthands as a bad aliasing mechanism, could you define what you consider to be a good one?
css-meeting-bot commentedon Apr 12, 2018
The Working Group just discussed
aliasing mechanism, and agreed to the following resolutions:RESOLVED: we should define what an alias is in CSS CascadeRESOLVED: We will make the required edits for the definition resolved previouslyRESOLVED: We create a new legacy shorthand concept in Cascade L4 for those things that we have legacy shorthands that should never be serializedRESOLVED: everything that's currently defined as an alias needs to use new legacy definition or is a legacy shorthandThe full IRC log of that discussion
<fantasai> Topic: aliasing mechanism<fantasai> github: https://github.com//issues/866
<dael_> fantasai: Couple places in text with an alias like overflow-wrapa nd word-wrap and the way their aliased is not how they're impl.
<dael_> fantasai: Previously resolved that when we do alais we treat as shorthand as other prop. Moz has different mech. If we're changing I need a resolution on what to change to.
<dael_> florian: I think it's not just Moz. In general aliasing in a browser doesn't work as a shorthand.
<dael_> emilio: How to observe?
<dael_> florian: By browser engineers complaining. What is the different behavior?
<dael_> emilio: [missed]
<fantasai> dbaron's comment on observable difference - https://github.com//issues/866#issuecomment-271028230
<dael_> dbaron: One difference might be when serializing declaration you try and serialize to a shorthand first and you don't want to do that here.
<dael_> dbaron: You want that for real shorthands
<dael_> emilio: But not aliases.
<dael_> dbaron: Example if you have a declaration that says border-meduim on each direction we'll use border:medium. Same rule is that if someone decalred overflow-wrap:inherit we'd serialize to word-wrap.
<dael_> abCSSOM wording has preferred order where shorthands are above longhands, but prefixed are below all of them.
<fantasai> https://www.w3.org/TR/css-break-3/#page-break-properties
<astearns> s/abCSSOM/TabAtkins: CSSOM/
<dael_> fantasai: Tricker is page break aliases. Those ones the page-break which is old will express all the values of the longhand which is where we're moving
<dael_> dbaron: There are also things that aren't supposed to work for shorthands. We might have changed some of those things to work.
<dael_> emilio: Spec says generally that getPRopertyValue works for shorthand but in getComputedStyle only properties are actual long hands but if there's properties for shorthands also expose them there. getPropertyValue font is supposed to work.
<dael_> emilio: Both work in webkit and block, but getComputedStyle.font isn't supposed to work per spec.
<dael_> emilio: Edge and FF don't impl any shorthand in getComputedStyle
<dael_> dbaron: WE do some.
<dael_> emilio: blink and webkit support both.
<dael_> dbaron: Other question is what is the actual mech we use.
<dael_> dbaron: In old style system at the point we converted a string to an internal css property ID we also did the alias mapping so every time you had an input that's a string that was asking something about a property we would convert it.
<dael_> emilio: Now I think we preserve a bit longer to control aliases. BUt not much longer. Once they're in the declaration block.
<fantasai> s/aliases/aliases vis prefs/
<dael_> fremy: WE only have "realId"s that are HTML. If we have -webkit-something and if the same as a prefix it's the same thing.
<fantasai> s/property ID/property ID where we also did lowercasing and such/
<dael_> astearns: I'm a bit confused. dbaron you started saying it's not like a shorthand because when you serialize the property turns into alias.
<dael_> dbaron: The thing that's not the alias is turned long hand.
<dael_> emilio: Supposed to serialize the short hand. If you have foo per spec it should be -webkit-foo.
<dael_> dbaron: If it's word-wrap and overflow-wrap it's supposed to switch.
<dael_> TabAtkins: It's alphasbetical.
<dael_> emilio: one is long hand.
<dael_> TabAtkins: Yes, if they're both shorthands.
<dael_> florian: If word-wrap is defined to be a shorthand you'll serialize tot he thing that's supposed to be the shorthand
<dael_> frWhen you spec the alias it's the same thing.
<dael_> astearns: Instead of defining alias as a shorthand we define alias as a separate thing and define what browsers are doing
<dael_> myIes: If you say .font does what you spoke about work? Would the alias and the original exist there?
<dael_> emilio: Yeah.
<dael_> myles: It's not just turning strings into an ID. You also do this other thing.
<dael_> florian: What about properties that take values?
<dael_> emilio: Same Whenever you parse a property ID if you receive like the alias you once you process it it's the same as if you got the longhand
<dael_> florian: If you serialize the transition property
<dael_> dbaron: Transition property property.
<TabAtkins> s/transition property/transition-property/
<dael_> florian: If you serialize the transition property property which takes property names you do not preserve the name.
<dael_> dbaron: In old gecko we did not preserve it.
<dael_> florian: And a shorthand you do preserve?
<dael_> dbaron: Yes.
<dael_> florian: That's one reason I pushed for shorthand originally.
<dael_> dbaron: We could still spec the other way for alias
<dael_> florian: Initial reason for shorthands was double. One we looked for in page-break has a different set of values.
<dbaron> you have to say "transition-property property" because otherwise "transition-property" might be heard as "transition property"
<dael_> emilio: Parsing rules. That's what we used to have for box-transform. We impl it as a shorthand and special cased serialization.
<dael_> florian: In general I think we can do the simple thing.
<dael_> fremy: For the transition property property we keep the ID as it is. If you can't match to a property in the end it doesn't work for us.
<dael_> emilio: We preserve the ID...I agree it's not relevent.
<dael_> fremy: We're not preserving it as a shorthand.
<dael_> myles: So mechanism for alias is not shorthands.
<dael_> florian: I'd like to resolve in general and separately for page-break and friends.
<dael_> emilio: Can't change parsing rules?
<dael_> florian: No.
<dael_> astearns: Seems to me like we could define what aliases are in Cascade in general and when we have an alias that needs mapping we define that in it's own spec.
<dael_> fremy: Example some webkit-flex properties are different.
<dael_> florian: WE define separately then? If values are the same we don't do anything.
<dael_> emilio: In FF we don't have any special case. I don't have context for page-break but how is it supposed to work with page-break:foo and then break:foo
<dael_> florian: Let me pull spec up.
<dael_> florian: page-break: before|always maps to break-before:page
<fantasai> s/page-break: before|/page-break-before:/
<dael_> fremy: They're not aliases.
<dael_> florian: If we define aliasing mech it won't work here.
<dael_> emilio: Page break properties, how should they work with aliases
<dael_> florian: They're supposed to be shorthands.
<dael_> emilio: Why are we covering?
<dael_> myles: There are shorthands and aliases and they're different
<dael_> dbaron: Page-break still needs to be a shorthand.
<dael_> astearns: But that's nto relevent
<dael_> florian: They're defined as these are aliases and you do them as shorthands. We hav to change that
<fantasai> Another aliasing case is https://www.w3.org/TR/css-writing-modes-3/#glyph-orientation
<dael_> astearns: We have to change where we say alias in all our specs
<dael_> myles: Where values aren't the same.
<dael_> florian: We had resolved on their the same.
<dael_> myles: was a bad resolution.
<dael_> emilio: What's expected to happen when you seilaize page-break:always It's defined to map to break:before-page What's expected serializeation of page-break:always in .style.pagebreak
<dael_> emilio: Is it break:before-page? break-before:always?
<dael_> fremy: It's not an alias. It's a webkit thing so it's an alias.
<fantasai> s/It's a webkit thing/Alias is a webkit thing/
<dael_> florian: Let's delete alias from that paragraph and leave the rest as is. Let's define alias somewhere.
<dael_> emilio: If we define this is a shorthand then break-before:left will be page break. It's weird because page-break is legacy
<dael_> myles: define in other direction?
<dael_> fantasai: Can't because break-before has values that page-break:before can't.
<dael_> emilio: Page mpas to page
<dael_> florian: Thing on the left are everything you have things on the right are more values.
<dael_> emilio: We can special case that.
<dael_> fremy: Can have concept of legacy property that's serialized at the bottom.
<dael_> emilio: Then you have shorthands where you have to create special cases.
<dael_> fantasai: You'd have alist of properties where you're looking for a shorthand and you never look at those.
<dael_> fantasai: Right now when you try to serialize you have a list of declarations and if it corrisponds to a shorthand you serlialize as the shorthand. And we're saying when you check eliminate the legacy
<dael_> astearns: Serveral to resolve. First is we should define what an alias is in CSS Cascade
<dael_> astearns: Obj?
<dael_> RESOLVED: we should define what an alias is in CSS Cascade
<dael_> astearns: In pure alias cases where we don't want shorthand behavior we need to change to the definition written in the previous resolution.
<dael_> florian: Yes.
<dael_> astearns: We will use this definition where it's appropriate.
<dael_> RESOLVED: We will make the required edits for the definition resolved previously
<dael_> astearns: Prop: We create a new legacy shorthand concept in Cascade L4 for those things that we have legacy shorthands that should never be serialized
<dael_> astearns: Or is this a type of short hand.
<dael_> emilio: There's a tricky thing because only place for this kind of shorthand is when the new thing superceeds the old. Is there a case where they don't map?
<dael_> fantasai: glyph-orieintation which takes a keyword and a degree and those map to keywords in text-orientation.
<dael_> emilio: Okay. That's fine as long as you can map.
<dael_> astearns: That can be it's own section or subsection
<dael_> astearns: Obj?
<dael_> RESOLVED: We create a new legacy shorthand concept in Cascade L4 for those things that we have legacy shorthands that should never be serialized
<dael_> emilio: Then someone needs to edit.
<dael_> fantasai: TabAtkins and I can
<dael_> florian: Do we need to resolve on a list?
<dael_> emilio: If they have same syntax you're fine otherwise use legacy.
<dael_> astearns: Let's do what we resolved and look at the fallout from that. Better to have them take time and find places it doesn't work.
<dael_> florian: Principle stated is if they take same values it's alias otherwise it's legacy.
<dael_> emilio: They're different things.
<dael_> astearns: florian is asking that we resolve to put thing in one bucket or the other and if we find problems we bring that to the group.
<dael_> astearns: Prop: everything that's currently defined as an alias needs to use new legacy definition or is a legacy shorthand
<dael_> RESOLVED: everything that's currently defined as an alias needs to use new legacy definition or is a legacy shorthand
<dael_> fantasai: If you're using aliasing mech what does that mean...you'll always serialize as the new thing and we don't have objects in OM rep that?
<dael_> emilio: We do.
<dael_> fantasai: WE should spec that
<dael_> myles: if you set the old object you should be able to read that from the new object
<dael_> fantasai: So this also applies to style.
<dael_> emilio: Yes.
<dael_> fantasai: Anywhere name is exposed. Okay.
<dael_> fantasai: I think that's it.
<dael_> fantasai: If you type in word-wrap:break-word and reserialize that you get overflow-wrap:break-word That's okay?
<dael_> many: yes
22 remaining items
fantasai commentedon Aug 17, 2018
Forgot, need to keep Needs Edits on for css-text/css-break/etc.
frivoal commentedon Sep 14, 2018
opened #3109 for the cssom part.
[css-text-3][css-break-3] Clarify aliasing mechanisms w3c#866
[css-text-3][css-break-3] Clarify aliasing mechanisms #866
frivoal commentedon Oct 8, 2018
We have a test for that: https://github.com/web-platform-tests/wpt/blob/master/css/css-text/overflow-wrap/word-wrap-alias.html, removing the label saying we need tests.
Bug 1465912 [wpt PR 11282] - Convert word-wrap to an alias of overflo…