W3C home > Mailing lists > Public > www-style@w3.org > July 2014

Re: [css-transforms] Making 'transform' match author expectations better with specialized 'rotate'/etc shorthands

From: Dirk Schulze <dschulze@adobe.com>
Date: Wed, 16 Jul 2014 12:54:28 +0000
To: Dean Jackson <dino@apple.com>
CC: Shane Stephens <shans@google.com>, Tab Atkins Jr. <jackalmage@gmail.com>, Alan Stearns <stearns@adobe.com>, www-style list <www-style@w3.org>
Message-ID: <B5665F95-3170-4B2F-A3E3-0D27363F8374@adobe.com>

On Jul 16, 2014, at 1:39 PM, Dean Jackson <dino@apple.com> wrote:

> 
>> On 16 Jul 2014, at 7:32 pm, Shane Stephens <shans@google.com> wrote:
>> 
>> > Yes, order matters when you need the transforms to interact.  When you
>> > don't (when they're all "local"), there's one specific order that does
>> > what you want.
>> 
>> “local” seems to be confusing here. All transformations are local for an element and take affect on rendering into the parents graphics context.
>> 
>> Yeah, local is confusing - all transforms act locally. I think what Tab means is that there's one specific order for which transforms appear to act globally as well.
> 
> I don't think they appear to act globally. I think you're making a simplification that could cause people to make dangerous assumptions, kind of like telling someone that they can learn how to multiply a number by 11 by simply repeating it. 11, 22, 33, 44, 55, 66, 77, 88, 99, 1010, 1111... The simplification works up to a point but then fails.
> 
> I expect this is why people don't teach linear algebra in the manner you explained. 
> 
>> Say I have an element {top: 0px, left: 0px}, which I want to:
>>  * move by 500px in x and 200px in y
>>  * rotate by 25 degrees; and
>>  * scale by 1.2 in x and 1.1 in y
> 
> Let's make the example more simple. Let's say I have a 100x100 square:
> * move by 200px in x and 200px in y
> * rotate by 45 degrees; and
> * scale by 2 in x and 1 in y
> 
> Should authors expect to see a 200x100 rectangle rotated 45deg? It turns out the result is a diamond. (Of course, I applied the transforms in the order you specify below, not the order in which you described them above. If I'd done them in the order you describe above, I would get a 200x100 rectangle rotated 45 degrees... because order matters :)

Talked a bit with Shane off-list since I didn’t understand his concept of “local” and “global” and why you would be able to switch the order without having a different result. I think I understand what he is up to. We all agree that for transform-lists the order matters. rotate() translate() is not the same as translate() rotate(). Each transformation applies to the CTM immediately and influences the next transformation decision.

For example:

	transform: rotate(90deg) translateX(200px)

With CSS Transforms this would rotate the CTM first and then apply the translation after that. Because we rotated the CTM already, we wouldn’t translate the context in the horizontal direction but in the vertical dimension.

What if we actually want to describe the desired behavior after all transformation? Without thinking about the intermediate steps and states? You know upfront that you want to rotate by 90 degree and that you want to have the object positioned 200px right from it’s current position. With CSS Transforms you either need to modify the order of the transformation or use a different approach like: rotate(90deg) translateY(200px).

Shane’s approach is that you don’t need to think about all intermediate steps and just *describe* the desired transformed behavior at the end upfront. Since we do not allow the ‘translate’ property to apply more than once it is the same like setting up a fixed order.

Lets assume we wouldn’t have a fixed order and take the order the values were specified. Then each transformation would need to compensate all previous transformations.

Example:

	scale: 2;
	translate: 200;

With the transform property, it would result in a translation of 400px. With Shane’s approach each transformation would compensate all previous transformations and internally switch the 200px to 100px.

I agree that this difference is hard to realize. It is a different concept to think about transformations… a more object oriented transformation concept in comparison to the coordinate space transformation concept.

With that concept it indeed doesn’t matter if you write:

	rotate: 90deg;
	translate: 200px 0;

or

	translate: 200px 0;
	rotate: 90deg;

The author already described the desired end result. The idea solves the problem of “I wrote translate: 200px; instead of transform: translate(200px)” by accident. It is more of a side effect.

I tried to come up with some examples… since we do not allow multiple translate, rotate or scale properties, it actually is hard to visualize the differences between the two concepts. Adding origins for scale and rotate makes the whole concept more interesting. However, animations can be described more easily. I would need more time to check what you can or can not do with this concept. Especially involving the ’transform’ property part needs some thoughts. 

Greetings,
Dirk


> 
> Since you list rotation first below, you seem to value that. Is the element globally rotated by 45deg if we apply your rules? It doesn't look that way, since it is a diamond.
> 
>> 
>> Regardless of the order in which I apply these operations, the element is always locally moved, rotated and scaled - that is, according to the element's local coordinate system (which changes with respect to the global coordinate system) the operations are a translate(500px, 200px), a rotate(25deg), and a scale(1.2, 1.1) regardless of the order in which they're applied.
>> 
>> Of course, globally, it's a different story. Mostly the element is not translated globally by 500px, 200px, is not rotated by 25 degrees, or is not scaled in x and y by 1.2 and 1.1 respectively. For example:
>> rotate(25deg) scale(1.2, 1.1) translate(500px, 200px)
>> Globally, this is rotated by about 27 degrees. It's also significantly skewed, and it's translated in both x and y by about 450px.
>> 
>> However, there is one ordering for which the local transformations produce matching global transformations:
>> translate(500px, 200px) scale(1.2, 1.1) rotate(25deg)
>> Globally, this is at position (500px, 200px) (well almost. Technically the origin has moved by this much). It's scaled by 1.2 in x and 1.1 in y, and it's rotated against the global x and y coordinate system by 25 degrees.
> 
> This is subjective. It's a skewed rectangle, so it's difficult to see what the "global" rotation is, but if you try to make the top and bottom edges parallel with the X axis, you need something more like 23deg, and if you want to make the left and right edges parallel with the Y axis you need about 27deg. Let's go back to my example, which has exaggerated values to make it more obvious. However, let's throw out the translate since it confuses things and doesn't change my point.
> 
> 100x100 square, with translate(0px, 0px) scale(2, 1) rotate(45deg)
> 
> Under your explanation that should have a global rotation of 45deg. So if you undo that "global" rotation, you should end up with something aligned to the X,Y axes right?
> 
> <div style="transform: rotate(-45deg)">
>   <div style="transform: scale(2, 1) rotate(45deg)">
>   </div>
> </div>
> 
> Except you don't. You don't get anything near it. You get two opposite corners that are in the original location, but a skewed rectangle that is still pointing off at 45deg.
> 
> It turns out in this case it is the "global" scale you can undo. But that's only because that's how transform ordering works.
> 
> <div style="transform: scale(0.5, 1)">
>   <div style="transform: scale(2, 1) rotate(45deg)">
>   </div>
> </div>
> 
> Thinking in terms of global transformations sounds like a good idea, but it isn't. You really should think in terms of a list of local transformations. I'm sorry that it is more difficult.
> 
> So I'm slightly worried that you were explaining this concept of global transformations matching local transformations, but assuming everyone would agree with your subjective choice.
> 
> And saying these new properties are independent leads to describing why this doesn't work:
> 
> <div style="rotation: -45deg">
>   <div style="rotation: 45deg; scale: 2, 1;">  <!-- equivalent to scale(2,1) rotate(45deg) according to your ordering -->
>   </div>
> </div>
> 
> After all, if rotation is truly independent, why can't I undo it like that? Answer: it's not independent.
> 
> Dean
> 
> 
>> 
>> This ordering is clearly special, and clearly has strong advantages for the purposes of individual rotate, translate and scale properties - the result of setting these properties will always match across a global and a local coordinate system. Essentially, we want people to be able to specify:
>> 
>> {
>>   translation: 500px 200px;
>>   rotation: 25deg;
>>   scale: 1.2 1.1;
>> }
>> 
>> and have it Just Work.
>>  
>> I think what you meant to say is (correct me if I am wrong) that authors most likely just will use one of the transform properties: Either rotate, or translate, or scale or transform. And therefore you just want to have a sane fallback if an author uses them in combination.
>> 
>> That isn't what we are trying to say. We want beginner authors to be able to naively specify translations, rotations and scales as if they were global, and to have them do what they almost certainly wanted them to; but we want more advanced authors to be able to use the transform property and control the ordering of transform components as well.
>> 
>> A handy bonus is that having separate translation: rotation: and scale: properties means it's easy to animate these channels independently of each other, without resorting to additive animation.
>>  
>> Cheers,
>>     -Shane
> 
Received on Wednesday, 16 July 2014 12:55:05 UTC

This archive was generated by hypermail 2.3.1 : Monday, 2 May 2016 14:39:23 UTC