w3c / csswg-drafts

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

[css-transforms-2] Syntax of individual transforms should reflect general CSS syntax #7646

Open evayde opened 2 years ago

evayde commented 2 years ago

For example: Individual translate is only usable like so: translate: 0 0 10px But translate as an individual property should be a shorthand for translate-x, translate-y, and translate-z In my opinion, this would reflect the current CSS syntax with other properties, like overflow, background-position, scroll-snap-type, and so on. Otherwise, it feels kind of inconsistent to me.

Or is there any technical reason that we cannot provide that syntax for individual transforms?

Spec: https://www.w3.org/TR/css-transforms-2/#individual-transforms

jakearchibald commented 1 year ago

@bramus any idea why translate-x isn't a thing?

tabatkins commented 1 year ago

It wasn't part of the initial use-cases that we designed the individual transform properties for.

jakearchibald commented 1 year ago

So it could be added in future?

bramus commented 1 year ago

I think so – Can’t think of a reason why it wouldn’t be possible.

evayde commented 1 year ago

As far as I understand it, the reason for creating individual transform properties was so that we can animate stuff without writing everything again, so:

div {
  transform: translate(0,100px) scale(1.2) rotate(20deg);
}

div:hover {
  transform: translate(10px,200px) scale(1.2) rotate(20deg);
}

Can be written like this:

div {
  transform: translate(0,100px) scale(1.2) rotate(20deg);
}

div:hover {
  translate: 10px 200px;
}

For the same reasons, we could argue that this would be even better (more granular):

div {
  transform: translate(0,100px) scale(1.2) rotate(20deg);
}

div:hover {
  translate-y: 200px;
}

Also it is more consistent with how other CSS properties and their shorthand syntax works.

bramus commented 1 year ago

In addition to translate-x and translate-y, would it also make sense to have translate-inline and translate-block? Same for scale-*/rotate-*, knowing that for the *-z properties there would be no logical counterpart.

tabatkins commented 1 year ago

We don't have corresponding functions for those; I'm uncomfortable adding properties that are genuinely unexpressible in 'transform' itself.

css-meeting-bot commented 1 year ago

The CSS Working Group just discussed [css-transforms-2] Syntax of individual transforms should reflect general CSS syntax, and agreed to the following:

The full IRC log of that discussion <florian> bramus: individual transforms property now exist, and help author with control over their animations
<florian> bramus: now people want more granularity, like translate-x, -y, etc
<florian> TabAtkins: I'm fine with that
<florian> TabAtkins: the other part was the logical transforms (translate-inline, etc)
<SebastianZ> q+
<astearns> ack fantasai
<florian> TabAtkins: that I'm against, because we don't have logical transforms, and thus nothing to map them too cleanly
<florian> bramus: that's ok
<florian> fantasai: do we want to just add those?
<flackr> q+
<astearns> ack SebastianZ
<florian> TabAtkins: that's part of this issue
<florian> SebastianZ: how about scale-x, scale-y, and the same for rorate
<florian> s/rorate/rotate/
<fantasai> s/that's/not/
<florian> TabAtkins: they were deliberately omitted from the transform properties, because there's no obvious correct order
<florian> TabAtkins: sorry, skew was omitted
<florian> flackr: does rotate has a long hand
<florian> TabAtkins: you'd have rotate-axis and rotate-angle
<astearns> ack flackr
<florian> flackr: when you create an animation with these now separate props, it might be surprising to authors:
<florian> flackr: if they set translate-x in the first and last keyframe, and -y in the middle, they'd only get the transition on the -
<florian> TabAtkins: that seems fine
<florian> fantasai: if you want the other behavior, then just put the necessary properties in the relevant keyframes
<florian> flackr: seems fine, never mind
<florian> bramus: the current standalone properties have enabled that, so it would be the same
<florian> TabAtkins: aminating on the separate properties and the joint ones give different results
<florian> astearns: Proposal: translate, rotate and scale have long hands
<flackr> q+
<florian> TabAtkins: translate -x and -y, rotate -angle -axis, scale -x -y -z
<TabAtkins> (and translate-z
<TabAtkins> )
<SebastianZ> q+
<astearns> ack flackr
<florian> flackr: is it well defined how we interpolate from one rotation angle to another
<florian> TabAtkins: I forget what the answer is, but yes, it's in the spec
<astearns> ack SebastianZ
<florian> SebastianZ: why rotate-angle and rotate-axis when we have rotate-x, rotate-y and rotate-z as functions
<florian> TabAtkins: there are multiple results depending on the order when you combine them, so it'd be ambiguous
<TabAtkins> TabAtkins: So if you do want to do independent rotations, use 'transform'
<florian> RESOLVED: add the longhands to these properties as discussed above
<astearns> ack fantasai
<Zakim> fantasai, you wanted to take up this comment as its own issue https://github.com/w3c/csswg-drafts/issues/7646#issuecomment-1545399874 which is filed at
<Zakim> ... https://github.com/w3c/csswg-drafts/issues/1544 already
<florian> dbaron: I'm not sure…
<florian> dbaron: I am concerned about the complexity this adds. Need to think about it.
<florian> astearns: how about you comment on the issue after reviewing that
<florian> fantasai: wanted to comment the logical part of this problem
<florian> astearns: it is a separate issue, and the agenda is already too crowded so no
tabatkins commented 1 year ago

This would be changing the decomposition a little, tho not in a way that's observably different from what we have today.

Currently the three transform properties insert three transform functions into the transform stack. Now they'll insert 7: 3 translates, a rotate, and 3 scales. If you continue to use the (now) shorthands the behavior is identical, since translates and scales are order-independent between themselves.

dbaron commented 1 year ago

So I think there's a definitely nontrivial cost to adding these, in particular because it requires adding support for separately animating translate-x, translate-y, and translate-z, etc., on the compositor.

If there are strong use cases for the splitting I think that complexity could be justified, but I don't think we should do this just "because a lot of other CSS properties do it", since I think it has significantly more implementation cost than for many other CSS properties.

css-meeting-bot commented 1 year ago

The CSS Working Group just discussed [css-transforms-2] Syntax of individual transforms should reflect general CSS syntax, and agreed to the following:

The full IRC log of that discussion <florian> dbaron: I don't see a whole lot in terms of usecase
<florian> dbaron: it seems we want to do this for completeness and consistency
<florian> dbaron: but the cost seems high
<florian> dbaron: because you need to support animating them on separate timelines
<florian> dbaron: not theoretically hard, but adds complexity to a performance sensitive path
<florian> dbaron: would be ok given strong use cases, but otherwise, the cost might be too much
<hober> q+
<florian> TabAtkins: we'd go from 3 properties to 7
<florian> hober: I share dbaron 's concern, but would defer to simon if he has an opinion
<florian> dbaron: not absolutely opposed to doing this, but want a stronger justification than has been given so far, given the cost
<florian> bramus: I remember requests, but not what the motivating use case was.
<florian> Rossen_: the proposal is to revert the previous resolution
<florian> RESOLVED: undo previous resolution, do not add the longhands to the rotate, translate, and scale properties
clshortfuse commented 1 year ago

To note, [css-logical][css-images] flow-relative gradients

1724 is blocked until Align logical values for with the ones defined in CSS Logical Properties

549 is resolved as per https://github.com/w3c/csswg-drafts/issues/1724#issuecomment-1561542019

I'm not sure we've resolved how transform-origin would work yet.

bramus commented 1 year ago

Got another request from an author for this today:

well, I think the problem with those properties is that they still don't give you individual transforms, e.g. translateX and Y separately... so back to square one I guess.

This was explicitly in response to the existence of the current individual transform properties.

bramus commented 1 year ago

Quoting @birtles on Twitter:

Maybe we need to introduce translateX and translateY properties 😅

This was sparked by a tweet by author @mattgperry. For their framework Framer Motion, IUC, they internally pipe the passed in x/y/etc. options to Custom Properties, which they then use to build a transform themselves. This has the downside of not being hardware accelerated.

With translateX/translateY/etc. this would not be a problem, as Framer Motion could then pass these props straight into the individual transform properties.

As Matthew put it in a follow-up tweet:

Yes it would be amazing to be able to set each axis directly!

mattgperry commented 1 year ago

In terms of use-case, thinking from the perspective of gestures and/or velocity-based animations, the very first problem I’ve had to solve with every animation library I’ve written is per-axis transform animation. I was surprised when transform/scale/rotate were implemented that they weren’t per-axis. This is a big reason why people choose JS libraries over CSS.

For Motion One, which is based purely on WAAPI, the approach has been via custom properties but of course these aren’t accelerated.

They actually perform worse than the approach taken in Framer Motion. This library constructs a new transform at the end of every animation frame but of course has to run on the main thread. Framer Motion uses WAAPI when values can be hardware accelerated and if transforms could be set per axis, many more animations would be.

dbaron commented 1 year ago

So I think there are two things we could reasonably do here:

I'm curious how strong the use cases are for each of these things. It sounds like separate translate properties are quite valuable. Are there similarly strong use cases for the scale properties?


I think its less clear what to do about the rotate properties. The earlier proposal above was to split into rotate-angle and rotate-axis, but it's not clear to me how strong the use cases for such a split are.

We can't make the existing rotate property a shorthand for rotate-x/rotate-y/rotate-z since it supports a syntax that allows rotations around arbitrary vectors, and non-axis-aligned rotations can't be mapped to separate rotate-x/rotate-y/rotate-z properties. So if we wanted such properties I think we'd have to make them additional properties, and then define the order of operations across all four rotation properties. I'd also note that the order of operations just between rotate-x/rotate-y/rotate-z is not obvious.

tabatkins commented 1 year ago

I'd also note that the order of operations just between rotate-x/rotate-y/rotate-z is not obvious.

Yes, this is why I'd object to rotate-x/etc properties (and why we didn't do skew/etc properties). The TSR order gets you the least-surprising result; anything else will produce surprises at least some of the time.

birtles commented 1 year ago

My suggestion on Twitter was partly in jest. I think many of these use cases can already be addressed using animation composition. What is missing there is a better way to control the composite order of the animations.

birtles commented 1 year ago

Here is a demo showing independently animated translateX and translateY on the same element. At least in Firefox, both animations are accelerated: https://codepen.io/birtles/pen/mdaGydp

However, the order of composition for script-generated animations is currently based on the order in which the animations are created.

For libraries, I believe they would like to, for example, add a translateX animation after the fact and have it composite in a specific order. In the past we've discussed this and decided we could add methods to adjust an animation's relative composite order when the need arose.

mattgperry commented 1 year ago

It would indeed probably be enough to be able to manually set transform order rather than rely on animation creation.

On rotateX etc I'm not sure I understand why it's complicated. I've always just enforced X - Y - Z and I don't think I've had a comment or complaint in almost ten years. There is a way to define your own order already, via transform.

clshortfuse commented 1 year ago

I'm here for accessibility/localization moreso than animation.

For RTL languages we don't want to touch translate-y. We only care to modify translate-x. There's a lot of rule rewriting with translate alone.

tabatkins commented 1 year ago

I've always just enforced X - Y - Z and I don't think I've had a comment or complaint in almost ten years.

If an author writes .foo { rotate-y: 30deg; }, it's reasonable to assume they expect it to rotate 30deg around the Y axis, aka the vertical line parallel with the page. But if another class has set rotate-x: 45deg;, they won't get that result - it'll rotate around the 45deg-canted Y axis instead. That's pretty surprising!

The existing TSR order doesn't result in such surprises - without knowing anything about what other transform properties are set, you can safely set any individual one and get the result you'd expect from thinking solely about that property in a vacuum - 'rotate' spins the element around regardless of what 'translate' is, 'translate' moves it the specified distance even if it's scaled or rotated, etc.

I think it's fairly useful to maintain this property if we can, and ask authors to write 'transform' if they do want transforms that are less "separable" in this way. It might not be a property we can maintain forever! But it's one we should discard only with caution, and with significant author benefit justifying it, to overcome the downside of author confusion.

(As has been noted, we can safely split up 'translate' and 'scale' if desired; the individual effects are independent of each other and maintain the "local" property. We could split 'rotate' into 'rotate-axis' and 'rotate-angle', as those are clearly components of a rotation rather than independent operations on their own, and thus aren't expected to be understood on their own in a vacuum, but as @dbaron says it's unclear how strong the use-cases are for that particular control.)