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

[css-logical] Flow-relative syntax for margin-like shorthands #1282

Open
fantasai opened this issue Apr 23, 2017 · 75 comments
Open

[css-logical] Flow-relative syntax for margin-like shorthands #1282

fantasai opened this issue Apr 23, 2017 · 75 comments
Labels
css-logical-1 Current Work i18n-needs-resolution Issue the Internationalization Group has raised and looks for a response on. Needs Feedback/Review

Comments

@fantasai
Copy link
Collaborator

CSS currently assigns the values in the margin/padding/border shorthand to their physical longhands, i.e.

  margin: 1em 2em 3em 4em;

is equivalent to

  margin-top: 1em;
  margin-right: 2em;
  margin-bottom: 3em;
  margin-left: 4em;

I'm pretty sure we want some equivalent syntax for assigning into the logical longhands instead, but what should that be?

The current proposal is to put a keyword in front of the 4 values, like

  margin: relative 1em 2em 3em 4em;

Another possibility is to use a !keyword:

  margin: 1em 2em 3em 4em !relative;

or to create a new property in its place:

  margin-relative: 1em 2em 3em 4em;

or use some entirely as-yet-unused symbol or syntax.

And of course the exact keyword, if one is used, is up for debate as well; shorter would be better. People will be drawing up entire style sheets that use almost exclusively flow-relative properties, so this needs to be designed for comfort under frequent use.

Ideas welcome~

@fantasai fantasai added the css-logical-1 Current Work label Apr 23, 2017
@chharvey
Copy link

chharvey commented Apr 23, 2017

I agree with the current proposal, a keyword in front of the values. I personally like relative better than logical, because I don't think this spec really has anything to do with "Logic" per se… (the study of truth and argument forms).

A couple of points:

  1. the !relative keyword isn't already part of the standard CSS syntax and doesn't (and shouldn't) apply to all properties like the !important keyword does.
  2. adding a new property like margin-relative would have to set (or reset) its sub-properties, but sub-property names are usually extensions of the shorthand. So a margin-relative shorthand would imply its sub-properties are things like margin-relative-block-start, margin-relative-block-end, etc. There are exceptions, though, in the case of grid-gap setting grid-row-gap and grid-column-gap—property names that still make me mad!

@MurakamiShinyu
Copy link
Collaborator

MurakamiShinyu commented Apr 26, 2017

margins for logical shorthand -- is this bad idea?
I think plural word for shorthand makes sense, and columns is shorthand for column-* .

@chharvey
Copy link

@MurakamiShinyu — I see where you are going with this, but it could potentially become often confused with margin, which already exists. (Did they mean to put margins or was that a typo? Which one is relative again, I can't remember? etc etc…)

I think with a keyword such as relative prepended to the values, the code indicates very clearly and unambiguously what was intended—at the cost of just a few more bytes.

columns is okay because there is no column property, but in retrospect I would probably have preferred column for consistency.

@MurakamiShinyu
Copy link
Collaborator

I admit it's a crazy idea: 'margins' stands for "margin's writing-mode relative shorthand". But there is one advantage: 'margins' is easier to type than 'margin-relative' or 'margin: relative ...'. My concern is that people may feel troublesome to type a lot of 'relative' when css-logical-props becomes widely available.

@bradkemper
Copy link
Contributor

I like the idea of !keyword that could be added to any 4-value clockwise shorthand (and their 3-value, 2-value, and 1-value versions). How about just an unadorned !, to make it an even easier, quicker switch? So...

border-radius: 2em 1em 4em / 0.5em 3em !;

is equivalent to

border-block-start-inline-start-radius:  2em 0.5em;
border-block-start-inline-end-radius:    1em 3em;
border-block-end-inline-end-radius:      4em 0.5em;
border-block-end-inline-start-radius:    1em 3em;

Adding the ! to a 1-value version, like margin: 0 ! wouldn't have any noticeable effect, but should be allowed.

@cork
Copy link

cork commented Apr 27, 2017

Why not go the same route as for box-sizing? So something like margin-mode: relative;

Then when the support gets common you could just do:

* { margin-mode: relative; }

div {
  margin: 1em 2em 3em 4em;
}

#exception {
  margin-mode: physical;
  margin: 1em 2em 3em 4em;
}

@SebastianZ
Copy link
Contributor

Having a margin-mode property would go hand in hand with the current proposal of margin: relative 1em 2em 3em 4em;, i.e. be another longhand property for margin. The disadvantage of this is that its value infuences the handling of the other values, which might be unexpected.

I totally agree with @chharvey's comment that !relative (or ! for the same reason) and margin-relative have downsides.

Sebastian

@inoas
Copy link

inoas commented Apr 27, 2017

If I got the ticket right (because the opening post doesn't really explain):

I think I have already answered via twitter... but I am suggesting transpose again.
And from an author point of view I would not care it it was margin-transpose: val val val val or margin: val val val val transpose;

@chharvey
Copy link

chharvey commented Apr 27, 2017

@cork I do like your idea of margin-mode. That way the syntax of the margin property would not have to change. The syntax of margin-mode would be

syntax:    [ physical | relative ] | inherit | initial | unset

initial:   physical

inherited: true

One upside would be that you wouldn't have to change the margin property when you want to change the mode—taking advantage of the Cascade, resulting in more readable diff.

Alas, a recent change of the spec indicates a different order when relative values are used.

p {
  margin: 1px 2px 3px 4px;
  /* equivalent to standard order (top, right, bottom, left)
  margin-top:    1px;
  margin-right:  2px;
  margin-bottom: 3px;
  margin-left:   4px; */
}
p.relative {
  margin-mode: relative; /* <-- added */
  /* equivalent to new order:
  margin-block-start:  1px; `top`    in LTR-TB
  margin-inline-start: 2px; `left`   in LTR-TB
  margin-block-end:    3px; `bottom` in LTR-TB
  margin-inline-end:   4px; `right`  in LTR-TB */
}

So in the example above, by adding margin-mode: relative;, you would still have to add margin: 1px 4px 2px 3px; in the second ruleset to keep things the same.

Another downside: you would have to have corresponding "mode" properties for the following, which could be a bit much:

@MatsPalmgren
Copy link

I suspect margin-mode might be hard to implement - it's easier if you know at parse time how a property is supposed to be interpreted.

I like the !relative or ! proposal best so far. It would make it possible for multi-value properties to have both physical/logical values in the same declaration (if we want that). For example:
background-position: 10px, ! 20px, 30px, ! 40px;

I'm concerned though, that this might lead to new CSS properties being defined as physical-first and require ! for logical values. This would be unfortunate since logical values are superior in most cases. Perhaps ! could be interpreted as a general physical/logical switch though, so that for example grid-gap: ! 10px 20px; would set 10px on the longhand that corresponds to the vertical axis?

@MurakamiShinyu
Copy link
Collaborator

I like the idea of #1279: margin-block is shorthand for margin-block-start + margin-block-end, and margin-inline is shorthand for margin-inline-start + margin-inline-end.
These will be often more useful than single margin flow-relative shorthand, and I am ok with adding 'relative' keyword when the margin shorthand is needed. Or how about the following syntax:

  margin: [ block <'margin-block'> || inline <'margin-inline'> ]

e.g.

  margin: block 1em 3em inline 2em 4em;

@inoas
Copy link

inoas commented Apr 28, 2017

I have to raise my voice and say that short symbolic like a punctuation (!) mark are really not good practice IMHO. The gains in saved typing are minimal and the symbol does not transport its meaning. It pretty much feels regexpy and IMHO CSS should not be.

I'd favour extra logical properties. Aka margin and padding are absolute and margin-relative and padding-relative are not (dimensions for position and dimensions-relative or similar could be added later).

That is a very clear and easy interface for authors and there is no clash between old properties and new properties. Authors can also use margin and margin-relative independent of each other and thus are not breaking css parsing of older browsers!

So I really like @fantasai initial proposal.

@fantasai
Copy link
Collaborator Author

fantasai commented Apr 28, 2017

Wow, okay! Here's some responses:

  • I think it's pretty sure we are not doing a separate property to control interpretation of shorthands. First, as @MatsPalmgren mentions, this is harder to implement--we really want a switch that's syntactically part of the declaration and lets us handle this at parse time. Secondly, it creates an "action at a distance" effect, which is likely to result in confusion and errors as multiple parts of a stylesheet interact.
  • Agree that margin vs margins is going to be confusing and we shouldn't go that route. :) For languages that pluralize with s such as English, it's a mostly-unnoticeable morpheme and not something we ever want to be a distinguishing factor in any CSS syntax.
  • I agree with @inoas that using just ! alone is likely a bit too obscure (and also a bit too general, imho, as we use !keyword for other things like !important). However, I also agree with the concerns about !relative or relative or -relative potentially being too much of a typing burden; as I mentioned in the OP, we do expect this to become the default mode of assignment for many authors, so I'd say it's fair to trade a bit of obscurity for a bit of typing efficiency.
  • Wrt @MatsPalmgren’s comment about moving to flow-relative directions... new CSS models like Grid and Flexbox tend to use flow-relative directions to begin with, however for anything that's analogous to an existing CSS feature like margin or background-position, consistency is a more important consideration. Hence scroll-snap-margin is physical, even though we would have preferred it to be flow-relative.
  • transpose is not a bad name, the main downside is that it doesn't indicate what the mapping is! There's a distinct possibility that more mappings could be added in the future--Writing Modes already includes both flow-relative and line-relative mappings.
  • Fwiw, margin-block and margin-inline were resolved to add already, I just forgot to make the edits. :( I'll go do that now. ;)
  • Wrt interleaving keywords... one of the great things about the 4-value shorthand syntax is the way that it can use 1, 2, 3, or 4 values to assign to the four sides, and pairs things up in ways that both correspond to common use cases and yet also unroll syntactically in a consistent way. I think we want to keep those qualities; and also be consistent with Grid which already has a 4-value shorthand in grid-area.

@MurakamiShinyu
Copy link
Collaborator

MurakamiShinyu commented Apr 29, 2017

Agree with @fantasai. Now I feel original relative keyword or -relative suffix were better. However, I think the word relative also has obscurity. People may think the relative is related to position: relative, and may not notice that it is about "flow-relative-directional".
(For this reason I think logical keyword might be better then relative)

How about margin-bi (suffix -bi, stands for "block and inline")? I know this is exceptional in CSS property naming convention (avoid abbreviations and use complete words), but has the following advantages:

  • easy to type, only three additional characters to the original name
  • we have *-block and *-inline properties, and making the combined shorthand names using the first letters of "block" and "inline" will be easy to understand
  • "bi" indicates the order of values, block is first then inline, and convenient to remember the value syntax

and CSS already has abbreviations in some keywords, e.g., "rl" (for "right to left direction") in vertical-rl value of writing-mode, and using "bi" for "block and inline directions" will be not too bad.

@fantasai
Copy link
Collaborator Author

Sorry; typo in commit message. :/

@fantasai fantasai reopened this Apr 30, 2017
@chharvey
Copy link

chharvey commented May 7, 2017

If the keyword route is decided upon, can the syntax allow it to be at the beginning or end of the declaration? Inspired by box-shadow inset (that is, inset of the box-shadow, not the new inset positioning property).

So for margin it would be

relative? && [ <length> | <percentage> | auto ]{1,4}

@bradkemper
Copy link
Contributor

Weird. My comment was posted to the wrong page

@bradkemper
Copy link
Contributor

I really don't think we should have margin-* or *-margin as a property or !keyword for this. Because then you would need to do it for padding, border (and border-width, border-style, and border-color), border-radius, and many others. It should be a single !keyword that can be used for all (I agree that action-at-a-distance is bad for this).

If it is to be typed a lot (and really, that is the hope, that authors are considering bi-di and writing mode all the time), then it needs to be very short. I would say no more than 2-3 letters long. I still prefer an unadorned ! for that reason, even though it would more likely lead to authors adding it without understanding why.

@fantasai fantasai added i18n-tracker Group bringing to attention of Internationalization, or tracked by i18n but not needing response. Needs Feedback/Review labels Jun 20, 2017
@fantasai fantasai changed the title [css-logical] Syntax for margin-like shorthands [css-logical] Flow-relative syntax for margin-like shorthands Jun 20, 2017
@jonjohnjohnson
Copy link

jonjohnjohnson commented Apr 11, 2018

I know there are multiple arguments against having a separate property that controls interpretations of shorthands for reasons like implementation difficulty or "action at a distance", but isn't that akin to how box-sizing works? I know there have been discussions about properties like box-size (#820), so wouldn't something like box-mode: [ physical | relative ] be what we'd all get behind if this was part of the initial proposal for box shorthands?

I'd imagine anyone who wants to use logical features would be "all in", not needing to set individual "modes" and wanting something like box-mode to cascade/inherit and set interpretation for ALL shorthand box properties such as border-width,padding,margin,border-radius, background-position, etc...

@xfq
Copy link
Member

xfq commented May 13, 2018

@fantasai wrote:

I agree with @inoas that using just ! alone is likely a bit too obscure (and also a bit too general, imho, as we use !keyword for other things like !important). However, I also agree with the concerns about !relative or relative or -relative potentially being too much of a typing burden; as I mentioned in the OP, we do expect this to become the default mode of assignment for many authors, so I'd say it's fair to trade a bit of obscurity for a bit of typing efficiency.

Even if we expect this to become the default mode of assignment for many authors, I would still prefer clarity & readability to typing efficiency, because the latter can be mitigated by code completion and code snippets in authoring tools, and IMHO shouldn't be a major concern (comparing with readability & less surprise for authors who are not familiar with flow-relative properties) when designing a language like CSS.

@fantasai
Copy link
Collaborator Author

I agree strongly with @bradkemper’s comment: this needs to be generic enough that it doesn't get confused with property-specific value spaces, and it also needs to be convenient enough that authors using flow-relative syntaxes are not at a significant ergonomic disadvantage compared to authors using physical syntaxes.

Another option would be to have a longer per-declaration !keyword (for clarity) but also a higher-level syntax similar to @namespace (changing the default interpretation of an entire stylesheet) or @media (changing the default interpretation in a block). This would be the most convenient, at the cost of making it possibly confusing if someone is copy-pasting style rules out-of-context.

@fantasai
Copy link
Collaborator Author

fantasai commented Aug 17, 2018

A third option would be to have some other not-currently-used single punctuation character somewhere in the declaration, to indicate flow-relative mapping, e.g.

margin: 1em 2em 3em 4em; /* physical mapping */
~margin: 1em 2em 3em 4em; /* logical mapping, option A */
margin ~: 1em 2em 3em 4em; /* logical mapping, option B */
margin :~ 1em 2em 3em 4em; /* logical mapping, option C */

This is convenient to type and safe for out-of-context quoting, at the cost of being more obscure.

@r12a r12a added the i18n-needs-resolution Issue the Internationalization Group has raised and looks for a response on. label Sep 15, 2022
@mirisuzanne
Copy link
Contributor

There's a relevant article from Jeremy Keith this week - Let's Get Logical - about the limitations that currently exist in CSS when trying to write a logical-first site design.

@css-meeting-bot
Copy link
Member

The CSS Working Group just discussed flow-relative syntax for margin-like shorthands.

The full IRC log of that discussion <TabAtkins> Topic: flow-relative syntax for margin-like shorthands
<TabAtkins> github: https://github.com//issues/1282
<fantasai> https://github.com//issues/1282#issuecomment-952428897
<fantasai> https://github.com//issues/1282#issuecomment-1105613943
<TabAtkins> miriam: fantasai and I looked at this last year, with Jen
<TabAtkins> miriam: CSS was built around physical property - trbl, width/height
<TabAtkins> miriam: For various reasons logical props are more resilient, especially with multiple langs
<TabAtkins> miriam: Whether that's building it in pruposely, or automated translation
<TabAtkins> miriam: It woudl be great if we could move toward a world where flow-relative logical props are the defualt
<TabAtkins> miriam: The easier solution is that we just add `-logical` to various props
<TabAtkins> miriam: But long-term that feels like a second-class citizen, not the default
<TabAtkins> miriam: We'd like to get to a simple, clean way to default to relative
<TabAtkins> miriam: Our plan is multi-step, starting with a property-by-property flag of some sort
<TabAtkins> miriam: Whether tha'ts a new prop name, a !flag, or something
<TabAtkins> miriam: That says "I want this property to be read as logical"
<TabAtkins> miriam: And once we've defined that for each property...
<TabAtkins> fantasai: Adn we'd add physical equivs so you could explicitly which way, if you wanted
<TabAtkins> fantasai: Wouldn't chang the default, just let you be more specific
<TabAtkins> miriam: Once defined for all props, we could look at a block-level or even file-level change of the default
<r12a> q+
<TabAtkins> miriam: So like an at-rule that switches default to logical for everything in it
<TabAtkins> miriam: Or even a file-level switch.
<addison> q+ to clarify relationship to rtl vs. ltr
<TabAtkins> miriam: Would have to be lexically scoped to the file; separate files shouldn't interact.
<r12a> qq+
<TabAtkins> miriam: The second comment fantasai linked is someone just saying "let's add an 's' to the property 'margins' and 'paddings'"
<dbaron> Do some of the "property-by-property" mean "declaration-by-declaration"?
<TabAtkins> miriam: There's some other syntax approaches that I didn't look at closely
<astearns> ack r12a
<Zakim> r12a, you wanted to react to dholbert
<emilio> q+
<TabAtkins> r12a: You alreayd talked about cascading - I've been using these logical props for a long time as much as possible
<TabAtkins> r12a: I've been using them for arabic and hebrew pages, and I've found there are occasionally situations where you really need to leave margin-left in the code, otherwise things break
<TabAtkins> r12a: there's not many, but some cases
<TabAtkins> r12a: So we should be careful and warn people that if we provide a big switch and say "this'll fix everything" it can break things, too. careful applying it en masse
<TabAtkins> miriam: Right. The logical shorthands would likely be in a different order than the physical anyway, so updates would require more than just the flag.
<astearns> ack addison
<Zakim> addison, you wanted to clarify relationship to rtl vs. ltr
<TabAtkins> miriam: So the situation is more like you use this when writing a new file, not adapting an old file.
<TabAtkins> addison: I think Richard was saying sometimes you need both so you need both options.
<astearns> q+
<rachelandrew> q+
<TabAtkins> fantasai: Right, that's part of our proposal
<r12a> q+
<TabAtkins> addison: And it's not so much as when people are mixing langs in a page, but rather they want the same stylesheet for both their LTR and RTL translations without much fiddling.
<astearns> ack emilio
<TabAtkins> emilio: The "switch per file" doesn't work for BEM
<TabAtkins> emilio: The simplest solution is having different properties, but that's not ideal
<astearns> s/BEM/OM/
<emilio> yeah, the OM
<fremy> q?
<TabAtkins> fantasai: The browser could parse it in and use the declarations... Our proposal provides two shorthand syntaxes, both explicit, in addition to the current "ambiguous" one.
<TabAtkins> fantasai: So the ambiguous would get decided as one or the other.
<TabAtkins> emilio: How would you decide that when writing it out with JS?
<TabAtkins> fantasai: For inline styles you'd use the explicit switch
<TabAtkins> emilio: Right but then el1.style.margin = el2.style.margin loses the detail
<TabAtkins> fantasai: The OM is currently locked into physical, so we're probably stuck with that. Any ideas?
<TabAtkins> dbaron: I think if you want a file-level switch, you need it to store the information in each declaration.
<TabAtkins> dbaron: So I think when you said property-by-property, at least some of the time you meant decl-by-decl
<TabAtkins> miriam: yeah
<TabAtkins> dbaron: So a file-level switch will have to alter the declarations at parse time to store the information, and possibly indistinguishable in the OM.
<emilio> q+
<TabAtkins> fremy: It's common to bundle CSS, so per-file is an issue
<TabAtkins> [discussion about ease of "s" suffix or "l-" prefix]
<TabAtkins> fantasai: That still makes logical CSS a second-level, more awkward option
<TabAtkins> astearns: My question on file-levle switch - is there a specific set of shorthands this would apply to? Or is it just certian ambiguous properties?
<TabAtkins> astearns: If we add new shorthands, will they use this switch?
<TabAtkins> fantasai: Note it's not just shorthands, it's every property that assigns in a physical orientation.
<TabAtkins> astearns: So it's not an allowlist, it's a set of props with this characteristic
<astearns> ack astearns
<TabAtkins> fantasai: Right, so we'd like look at overflow, which is x/y, and we'd define that it can also be block/inline
<TabAtkins> miriam: But like 'left' won't change, it just gets a different property
<astearns> ack rachelandrew
<TabAtkins> fantasai: But like text-shadow shoudl be able to assign block/inline, etc
<dbaron> text-shadow may be the exception to wanting the default to be logical!
<TabAtkins> rachelandrew: Issues 'margins' (suffix), that's easily typo'd. Very confusing especially since th eorder changes
<TabAtkins> rachelandrew: Not sure if we need a file switch at all, kinda like the staged approach.
<TabAtkins> rachelandrew: Wonder if, once we have the prop-by-prop, that'll be enough, especially since we know most authors use postprocessors which can handle the "file-level" itself
<florian> q+
<TabAtkins> rachelandrew: So we can find out if we even need the second step once we've done all the properties individually.
<astearns> ack r12a
<TabAtkins> r12a: The switch sound like it could b euseful bc it maeks things easier in some circumstances, but it's more complex
<TabAtkins> r12a: We've been stuck for over a year on just margin and padding, tho
<addison> q+ to say the "order" isn't different, also that the proposal for interim work seems agreeable?
<TabAtkins> r12a: The margin-inline/etc already exist and are great, but don't have the 4-value sorted out
<TabAtkins> r12a: So it seems like just a nomenclature, wish we could sort that out.
<astearns> ack emilio
<TabAtkins> The "order" is indeed different, depending on your language, addison
<TabAtkins> emilio: So the devil is in the details of 'margin'. If a logical version of the shorthands is something we need eventually anyway
<TabAtkins> emilio: I think it would be great ot make progress here so we can just do logical margins
<TabAtkins> TabAtkins: That exact thing is step 1 of this proposal
<TabAtkins> emilio: So yeah can we resolve on that?
<TabAtkins> emilio: And come up with a consistent model second
<iank_> +1 to emilio
<astearns> ack fantasai
<astearns> ack florian
<TabAtkins> florian: The point of discussing this switch now is not to have it now, but to be consistent with the switch eventually
<emilio> s/consistent model/consistent model for how to switch margin to the logical thing
<TabAtkins> florian: bc if properties all work in different ways, we can never introduce the switch, at least not simply
<r12a> q+
<TabAtkins> florian: So we don't need to decide on the switch, just need a model where we can intro it eventually
<addison> consistency and completeness
<TabAtkins> florian: Goal is to not just *enable* logical stylesheets, but make them *not harder* than physical
<astearns> ack dbaron
<TabAtkins> dbaron: Responding to emilio, I think it wasn't clear if we want `margin-logical: values` or `margin: values !logical`
<TabAtkins> dbaron: I think we need to be careful about assuming the end-state is everything-logical
<TabAtkins> dbaron: text-shadow was mentioned, and shadows in particular you usually want consistency of light sources.
<TabAtkins> dbaron: So want the light in upper-left, even if you have vertical Japanese or RTL hebrew mixed with your English
<TabAtkins> dbaron: So might need some more thought about the end state
<astearns> ack addison
<Zakim> addison, you wanted to say the "order" isn't different, also that the proposal for interim work seems agreeable?
<TabAtkins> addison: I think the switch is an end state, and primary challenge is agreement on interim bits. Does seem to be important.
<florian> q+
<TabAtkins> addison: And to get complete
<TabAtkins> addison: So let's focus on that.
<astearns> ack r12a
<TabAtkins> astearns: Right, but agreeing that we *will* have a switch is a good impetus
<TabAtkins> r12a: Dont' agree it's a good impetus since it's been years we've been talking about it without delivering
<TabAtkins> q+
<dbaron> s/have vertical Japanese/have Japanese with a mix of vertical and horizontal/
<TabAtkins> r12a: Let's just make a decision
<TabAtkins> r12a: All the explicit logical properties already work, just the shorthand is missing
<jensimmons> :dir
<TabAtkins> r12a: Meanwhile while we wait, need a way to change properties, currently browsers use :dir to do so
<astearns> ack florian
<TabAtkins> florian: Here's a concrete proposal, tying to david's earlier point about storing state
<TabAtkins> florian: I propose we don't go with extended names. Instae we use !syntax, and add a propdef line for specifying what the property defaults to if you don't specify the !.
<TabAtkins> florian: So for like text-decoration you'd say "Default Directions: n/a", but margin would say "Default Directions: physical", etc
<TabAtkins> florian: And later we can worry about a global switch, maybe with smarts about shadows, etc.
<TabAtkins> florian: But first is the state in the propdef table.
<emilio> q+
<fantasai> TabAtkins: What Florian said.
<astearns> ack TabAtkins
<TabAtkins> emilio: Not a fan of the bang, would prefer a ? mark
<miriam> q+
<TabAtkins> emilio: Would prefer a separate shorthand, even with `-physical` and `-logical`
<emeyer> q+
<astearns> ack emilio
<TabAtkins> emilio: Less to figure out there
<TabAtkins> emilio: Lots of thing to sort out to make !logical work
<TabAtkins> ?? What things?
<TabAtkins> emilio: And I just don't like the aesthetics
<TabAtkins> florian: It helps with the mental model if the front and back look similar
<TabAtkins> emilio: Complexity - we don't have conditional shorthands that expand one way or another based on some condition
<TabAtkins> emilio: So how do we define that, how do they serialize
<TabAtkins> emilio: Easier to say that margin-logical expands to the 4 logicals, margin-physical expands to the 4 physicals
<TabAtkins> emilio: But for the ! thing margin could expand to 8 properties, choosing any 4 depending conditionally
<TabAtkins> fantasai: I think you can say it expands to all of them unconditionally, but the order is conditional
<TabAtkins> emilio: So if you have 8 declarations...
<TabAtkins> fantasai: You set the wrong ones to initial, and the right ones to the values
<TabAtkins> fantasai: Just th eorder needs changing
<TabAtkins> fantasai: And we simplify in serialization
<TabAtkins> emilio: Say you have all 8 defined, and you serialize the margin shorthand
<TabAtkins> emilio: What form do you use?
<florian> s/with the mental model if the front and back look similar/with the mental model, adding a ! in the declaration ties well with the idea that this is a state to be remembered per definition/
<astearns> zakim, close queue
<Zakim> ok, astearns, the speaker queue is closed
<astearns> q?
<TabAtkins> dbaron: I think some of these aren't much harder than today
<TabAtkins> dbaron: Dunno if we do them ideally today, but today if you declare margin and then margin-inline-start, should you serialize the margin shorthand?
<TabAtkins> dbaron: I think you shouldn't and that extends to this case
<TabAtkins> emilio: We do serialize it
<TabAtkins> dbaron: Think that's a mistake
<TabAtkins> emilio: That's how they all work, they're separate properties with separate values
<TabAtkins> dbaron: Back when we were doing logical props as huge array of expanded props, we would not ahve serialized it
<TabAtkins> dbaron: When we did it to depend on the order, we should have depended on some of the properties of the older solution that we dropped.
<astearns> ack miriam
<addison> that sounds like you (emilio) are arguing for the ! syntax?
<emilio> ?
<emilio> quite the opposite
<TabAtkins> miriam: I get it that -logical is easier to impl and more consistent, but if there's not a plan for how it becomes a first-class citizen, I don't like it
<florian> q+
<TabAtkins> miriam: That's why I like the ! solution, it's easy to toggle which is the default.
<astearns> ack emeyer
<TabAtkins> miriam: Concerned we just do the simple-to-implemenht and leave it that way, second class
<TabAtkins> emeyer: I'm not a particular fan of the ! either
<TabAtkins> emilio: We ahve already "not important" jokes, and this'll look like "not logical"
<TabAtkins> s/emilio/emeyer/
<TabAtkins> emeyer: Wonder if we can just add a keyword to the value
<TabAtkins> fantasai: Can't do it, that interferes with some property syntaxes, but we need something that's completely consistent. Has to be outside the property space.
<TabAtkins> iank_: Are there that many props...
<TabAtkins> iank_: As david said there are some we want to make physical.
<TabAtkins> iank_: What's the list?
<addison> has someone written the list?
<emilio> q+
<TabAtkins> fantasai: It's pretty long, but some that you might *usually* want physical you want logical sometimes
<TabAtkins> iank_: This does make me skeptical of the switch
<TabAtkins> fremy: What about a logical() function fo rthe top-level property syntax?
<TabAtkins> astearns: We're out of time. I think the appraoch of figuring out what we *can* do prop-by-prop, with the switch as an eventual goal, is the way to go.
<TabAtkins> astearns: Kicking things up a levle, I'm frustrated we couldn't do all the issues. Want to find a way out of this, can't always wait for tpac
<TabAtkins> [skipping some scheduling talk]
<chris> sad in particular we didn't get to https://github.com//issues/4497#issuecomment-763459971

@tabatkins
Copy link
Member

So in the interest of resolving this in our next meeting, I propose we choose among these options:

  • Generically add a -logical and -physical suffix (or -l and -p?) to all these ambiguous properties. The switch, when it's defined, causes the ambiguous property name to parse as the more specific version. (That is, if @property-type logical; is set, then writing margin is exactly equivalent to writing margin-logical. If you use the OM with the ambiguous property (reading or writing style.margin) you get the default, unswitched behavior.
  • Generically add a !logical and !physical suffix to all properties. (For non-ambiguous ones, it does nothing.) The switch, when it's defined, treats props without the ! as having the appropriate one. If you read from the OM, you get the default behavior. (If you write, you can set the bang in .setProperty().)

@Dan503
Copy link

Dan503 commented Sep 16, 2022

I prefer the second option with !logical and !physical.

It should respect both bangs if you have
margin: 10px 20px !logical !important;

I see an issue with the @property-type logical; switch.
If you have 3rd party css written with physical dimensions in mind going into your project that has been written with logical dimensions in mind, the switch could break the 3rd party CSS layout.

It would be better if there was a CSS property that you set on the html element that is then inherited down to all children elements. You then overide that property on a child element.

If there is a technical reason that it needs to be an @rule sort of thing, then can we exclude elements?
Eg. @property-type logical exclude(.thirdParty1, .thirdParty2 .child);

The selected elements, and everything inside them, ignore the logical property type switch and are then layed out using physical dimensions instead of logical dimensions.

@mirisuzanne
Copy link
Contributor

I see an issue with the @property-type logical; switch.
If you have 3rd party css written with physical dimensions in mind going into your project that has been written with logical dimensions in mind, the switch could break the 3rd party CSS layout.
It would be better if there was a CSS property that you set on the html element that is then inherited down to all children elements. You then overide that property on a child element.

This is why we specified the switch as being file-level, rather than cascading. That way it only applies locally to declarations in the immediate file, and does not cascade to other files.

I believe the inherited property is actually more likely to impact how third-party code is parsed, since the origin of the code is ignored, and parsing is based entirely on the selected element rather than the intent of the author.

@chharvey
Copy link

chharvey commented Sep 17, 2022

Issues with the file-level declarations, which were mentioned in the chat log above, reiterating here.

  1. Minifiers and bundlers like to concatenate a bunch of CSS files into one. How will that affect the scope?
  2. Sometimes you really do want physical properties. Say a certain border radius or box shadow that shouldn’t change even when writing-mode & direction are changed. This likely means a mix of physical and logical properties in your code. How would a file-level declaration affect them?

How long is the list of ambiguous shorthand properties? If the list is short, is it worth adding a whole new language feature? This might be out on a limb here, but what if there was no support for logical shorthands? What if they all remain physical, and if devs want logical properties they have to declare them explicitly (long-hand)? With tools like IDE code-completion and CSS preprocessors, how high is the demand for shorthand?

@BenjaminAster
Copy link

The only issue that prevents solutions that use the syntax of the property value to decide between logical and physical from being implemented seems to be that the user agent should know at parse time what happens with var() expressions. I would consider this an edge case, so my suggestion would be to simply take @chharvey's suggestion with the /-syntax (e.g. margin: 1em / 2em) and let authors explicitly declare what should happen with var() expressions, but only when they actually need to use them. That way, authors would have to write a lot less repeated and ugly code where every logical property shorthand includes a !logical or some sort of -logical suffix.

First of all, if no var() expressions occur in the property declaration, the shorthand expands to either the physical or the logical version, depending on the syntax of the value:

.element {
	margin: 1em 2em; /* physical */
	margin: 1em 2em 3em 4em; /* physical */
}
.element {
	margin: 1em / 2em; /* logical */
	margin: 1em 2em / 3em 4em; /* logical */
}

If a var() expression occurs in the property's value and the author hasn't specified that the property value is a logical shorthand, the user agent would assume that the variable contains a physical shorthand with a syntax of e.g. [<length-percentage> | auto]{1,4}:

.element {
	margin: var(--margin); /* physical */
}

In this case, when the computed value of --margin doesn't match the syntax [<length-percentage> | auto]{1,4}, margin gets invalid at computed value time. So here:

.element {
	--margin: 1em / 2em;
	margin: var(--margin); /* invalid at computed value time */
}

margin would become invalid at computed time because --margin is assumed to contain a physical shorthand. This is, I think, how it is currently implemented and I wouldn't change anything about it.

If the author wants their property that includes a var() expression to be treated by the user agent as logical, they should be able to explicitly opt-in to this behavior with a !logical keyword at the end of the property value (or something similar), but make it optional for property declarations that do not contain a var() expression:

.element {
	--margin: 1em / 2em;
	margin: var(--margin) !logical;
}

In this example:

.element {
	margin: 1em / 2em !logical; /* !logical would be optional */
}

the !logical would be optional because the user agent already knows that margin is a logical longhand from the /. Also, the following examples would be invalid:

.element {
	margin: 1em 2em !logical; /* invalid */
}
.element {
	--margin: 1em 2em;
	margin: var(--margin) !logical; /* invalid at computed value time */
}

Another thing to consider is what should happen when the property value consists of multiple var() expressions and/or a mixture of var() expressions and static values.

If the property value neither contains a / nor a !logical at the end, the user agent expands the shorthand to its physical longhands:

.element {
	--margin-top-bottom: 1em;
	--margin-left-right: 2em;
	margin: var(--margin-top-bottom) var(--margin-left-right); /* physical */
}

If the property value directly contains a /, the property is treated as logical:

.element {
	--margin-block: 1em;
	--margin-inline: 2em 3em;
	margin: var(--margin-block) / var(--margin-inline); /* logical, a !logical is optional */
}
.element {
	--margin-block: 1em;
	margin: var(--margin-block) / 2em 3em; /* logical, a !logical is optional */
}

If the property value has !logical set and does not contain a /, the variables themselves should contain a /:

.element {
	--firt-margin-part: 1em /;
	--second-margin-part: 2em;
	margin: var(--first-margin-part) var(--second-margin-part) !logical; /* logical */
}

@Loirooriol
Copy link
Contributor

If you write, you can set the bang in .setProperty()

How would this work? Would there be a 4th argument?

element.style.setProperty("margin", "1px 2px 3px 4px"); // non-important, physical
element.style.setProperty("margin", "1px 2px 3px 4px", "important"); // important, physical
element.style.setProperty("margin", "1px 2px 3px 4px", "", "logical"); // non-important, logical
element.style.setProperty("margin", "1px 2px 3px 4px", "important", "logical"); // important, logical

Or conflate all flags into the 3rd argument like "", "logical", "important", "logical important"?

What about reading? I bet most scripts will just use getPropertyValue("margin") without checking getPropertyMappingLogic("margin") or whatever. So things may start breaking, causing authors to avoid setting properties logically, making this feature pointless.

What about computed styles? I don't think we want to track if the value comes from a logical or physical declaration, just like we don't track the priority (computed properties are considered non-important). So should they be considered physical or logical?

From the point of view of CSSOM, using different properties seems way less problematic.

@css-meeting-bot
Copy link
Member

The CSS Working Group just discussed [css-logical] Flow-relative syntax for `margin`-like shorthands.

The full IRC log of that discussion <TabAtkins> addison: This one we discussed last year at TPAC
<TabAtkins> addison: called flow-relative syntax for margin-like shorthands
<TabAtkins> addison: But really it's about providing support for directionality by changing left/right to start/end in various properties
<TabAtkins> addison: And allowing margin-like shorthands (the 4-direction props) to follow that
<TabAtkins> addison: We've been working with some CSSWG members on the steps necessary to do this in a generic fashion across CSS
<TabAtkins> addison: There've been some action items outstanding, I think florian has one to enumerate the various props
<TabAtkins> addison: So this is a check-in to see how progress is going, see if we can encourage progress
<TabAtkins> addison: And make sure the larger WG remains aware.
<florian> q?
<TabAtkins> florian: Sorry to report I haven't progressed my Action Item
<TabAtkins> florian: But now that I'm not a board<->AB laiason I ahve a lot more time and plan to make progress. Sorry for not doing it so far.
<TabAtkins> addison: The more global thing - we've been having monthly calls, with Floriana nd Elika repping CSS, and others of us repping i18n.
<TabAtkins> addison: It's been productive (if inconveniently timed) call, and we've been handling issues
<TabAtkins> addison: If anyone wants to participate, please ping me to get notified.
<TabAtkins> addison: We welcome participation.
<TabAtkins> astearns: Besides the florian AI, any other progress on this issue?
<TabAtkins> addison: Any other concerns? Otherwise we can move on.

@747
Copy link

747 commented Nov 2, 2023

Hi, I just came around to this thread from a link in the MDN reference on the logical shorthands. I would be very happy to see 4-value logical properties to be a thing too. After quickly skimming through this interesting discussion, I have one quite elementary question: has anybody proposed a property suffix like *-all (e.g. margin-all, padding-all...) for the logical counterpart?

Obviously I have never been involved in or conducted any deep scrutiny, but wondering if such a naming has whatever kind of known pros and cons.

@Loirooriol
Copy link
Contributor

It has been proposed to add logical shorthands, with names like margin-logical or margins. But the name isn't that important, the main concern against this approach is that it treats logical longhands as 2nd class citizens.

@747
Copy link

747 commented Nov 5, 2023

@Loirooriol Are you sure that the current verdict on the distinct property approach is "2nd class citizens regardless of name"? What I got from the latest log is that "let's try to have a name that doesn't look 2nd class citizen". (Otherwise, it'd sound like margin-block-start looks inferior to margin-top because it is longer... or is it?)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
css-logical-1 Current Work i18n-needs-resolution Issue the Internationalization Group has raised and looks for a response on. Needs Feedback/Review
Projects
TPAC 2023 agenda
Thursday Morning
Development

No branches or pull requests