Skip to content

Commit 72fea3b

Browse files
committed
[css-transforms-1] Clarify difference between post-multiply, pre-multiply and multiply. Clean up examples and editorial changes. #909
1 parent d1e11d5 commit 72fea3b

File tree

1 file changed

+90
-70
lines changed

1 file changed

+90
-70
lines changed

css-transforms-1/Overview.bs

+90-70
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,14 @@ When used in this specification, terms have the meanings assigned in this sectio
145145
: <dfn>identity transform function</dfn>
146146
:: A <a href="#transform-functions">transform function</a> that is equivalent to a identity 4x4 matrix (see <a href="#mathematical-description">Mathematical Description of Transform Functions</a>). Examples for identity transform functions are ''translate(0)'', ''translateX(0)'', ''translateY(0)'', ''scale(1)'', ''scaleX(1)'', ''scaleY(1)'', ''rotate(0)'', ''skew(0, 0)'', ''skewX(0)'', ''skewY(0)'' and ''matrix(1, 0, 0, 1, 0, 0)''.
147147

148+
: <dfn>post-multiply</dfn>
149+
:: Term <var>A</var> post-multiplied by term <var>B</var> is equal to <var>A</var> &middot; <var>B</var>.
150+
151+
: <dfn>pre-multiply</dfn>
152+
:: Term <var>A</var> pre-multiplied by term <var>B</var> is equal to <var>B</var> &middot; <var>A</var>.
153+
154+
: <dfn>multiply</dfn>
155+
:: Multiply term <var>A</var> by term <var>B</var> is equal to <var>A</var> &middot; <var>B</var>.
148156

149157
The Transform Rendering Model {#transform-rendering}
150158
====================================================
@@ -156,22 +164,23 @@ Specifying a value other than ''transform/none'' for the 'transform' property es
156164
The coordinate space is a coordinate system with two axes: the X axis increases horizontally to the right; the Y axis increases vertically downwards.
157165

158166
<p id="transformation-matrix-computation">
159-
The [=transformation matrix=] is computed from the 'transform' and 'transform-origin' properties as follows:
167+
The [=transformation matrix=] is computed from the 'transform' and 'transform-origin' properties as follows:
160168

161-
1. Start with the identity matrix.
162-
2. Translate by the computed X and Y of 'transform-origin'
163-
3. Multiply by each of the transform functions in 'transform' property from left to right
164-
4. Translate by the negated computed X and Y values of 'transform-origin'
169+
1. Start with the identity matrix.
170+
2. Translate by the computed X and Y of 'transform-origin'
171+
3. Multiply by each of the transform functions in 'transform' property from left to right
172+
4. Translate by the negated computed X and Y values of 'transform-origin'
165173

166174
Transforms apply to [=transformable elements=].
167175

168176
Note: Transformations do affect the visual rendering, but have no affect on the CSS layout other than affecting overflow. Transforms are also taken into account when computing client rectangles exposed via the Element Interface Extensions, namely <a href="https://www.w3.org/TR/cssom-view/#dom-element-getclientrects">getClientRects()</a> and <a href="https://www.w3.org/TR/cssom-view/#dom-element-getboundingclientrect">getBoundingClientRect()</a>, which are specified in [[CSSOM-VIEW]].
169177

170178
<div class="example">
171-
<pre>
172-
div {
173-
transform: translate(100px, 100px);
174-
}</pre>
179+
<pre><code highlight=css>
180+
div {
181+
transform: translate(100px, 100px);
182+
}
183+
</code></pre>
175184

176185
This transform moves the element by 100 pixels in both the X and Y directions.
177186

@@ -182,13 +191,13 @@ div {
182191
</div>
183192

184193
<div class="example">
185-
<pre>
194+
<pre><code highlight=css>
186195
div {
187196
height: 100px; width: 100px;
188197
transform-origin: 50px 50px;
189198
transform: rotate(45deg);
190199
}
191-
</pre>
200+
</code></pre>
192201

193202
The 'transform-origin' property moves the point of origin by 50 pixels in both the X and Y directions. The transform rotates the element clockwise by 45&deg; about the point of origin. After all transform functions were applied, the translation of the origin gets translated back by -50 pixels in both the X and Y directions.
194203

@@ -198,28 +207,35 @@ The 'transform-origin' property moves the point of origin by 50 pixels in both t
198207
</div>
199208

200209
<div class="example">
201-
<pre>
210+
<pre><code highlight=css>
202211
div {
203212
height: 100px; width: 100px;
204213
transform: translate(80px, 80px) scale(1.5, 1.5) rotate(45deg);
205214
}
206-
</pre>
215+
</code></pre>
207216

208-
This transformation translates the local coordinate system by 80 pixels in both the X and Y directions, then applies a 150% scale, then a 45&deg; clockwise rotation about the Z axis. The impact on the rendering of the element can be intepreted as an application of these transforms in reverse order: the elements is rotated, then scaled, then translated.
217+
The visual appareance is as if the <a element>div</a> element gets translated by 80px to the bottom left direction, then scaled up by 150% and finally rotated by 45&deg;.
209218

210-
<div class="figure">
211-
<img src="examples/compound_transform.svg" alt="The transform specified above" width="270" height="270">
212-
</div>
219+
Each <<transform-function>> can get represented by a corresponding 4x4 matrix. To map a point from the coordinate space of the <a element>div</a> box to the coordinate space of the parent element, these transforms get multiplied in the reverse order:
220+
1. The rotation matrix gets multiplied with the scale matrix.
221+
2. The result of the previous multiplication is then multiplied with the translation matrix to create the accumulated transformation matrix.
222+
3. Finally, the point to map gets pre-multiplied with the accumulated transformation matrix.
223+
224+
For more details see <a href="#transform-function-lists">The Transform Function Lists</a>.
225+
226+
<div class="figure">
227+
<img src="examples/compound_transform.svg" alt="The transform specified above" width="270" height="270">
228+
</div>
213229

214-
Note that an identical rendering can be obtained by nesting elements with the equivalent transforms:
230+
Note: The identical rendering can be obtained by nesting elements with the equivalent transforms:
215231

216-
<pre>
232+
<pre><code highlight=html>
217233
&lt;div style="transform: translate(80px, 80px)">
218234
&lt;div style="transform: scale(1.5, 1.5)">
219235
&lt;div style="transform: rotate(45deg)">&lt;/div>
220236
&lt;/div>
221237
&lt;/div>
222-
</pre>
238+
</code></pre>
223239
</div>
224240

225241
For elements whose layout is governed by the CSS box model, the transform property does not affect the flow of the content surrounding the transformed element. However, the extent of the overflow area takes into account transformed elements. This behavior is similar to what happens when elements are offset via relative positioning. Therefore, if the value of the 'overflow' property is ''overflow/scroll'' or ''overflow/auto'', scrollbars will appear as needed to see content that is transformed outside the visible area. Specifically, transforms can extend (but do not shrink) the size of the overflow area, which is computed as the union of the bounds of the elements before and after the application of transforms.
@@ -312,11 +328,11 @@ If two or more values are defined and either no value is a keyword, or the only
312328
</dl>
313329

314330
For SVG elements without associated CSS layout box the initial [=used value=] is ''0 0'' as if the user agent style sheet contained:
315-
<pre>
331+
<pre><code highlight=css>
316332
*:not(svg), *:not(foreignObject) &gt; svg {
317333
transform-origin: 0 0;
318334
}
319-
</pre>
335+
</code></pre>
320336

321337
The 'transform-origin' property is a <a>resolved value special case</a> property like 'height'. [[!CSSOM]]
322338

@@ -378,7 +394,7 @@ Since the previously named SVG attributes become presentation attributes, their
378394

379395
This example shows the combination of the 'transform' style property and the <a element-attr for>transform</a> presentation attribute.
380396

381-
<pre>
397+
<pre><code highlight=xml>
382398
&lt;svg xmlns="http://www.w3.org/2000/svg">
383399
&lt;style>
384400
.container {
@@ -390,7 +406,7 @@ This example shows the combination of the 'transform' style property and the <a
390406
&lt;rect width="100" height="100" fill="blue" />
391407
&lt;/g>
392408
&lt;/svg>
393-
</pre>
409+
</code></pre>
394410

395411
<div class="figure">
396412
<img src="examples/svg-translate1.svg" width="470" height="240" alt="Translated SVG container element.">
@@ -463,7 +479,7 @@ Issue(w3c/csswg-drafts#893): User coordinate space statement breaks SVG.
463479

464480
The 'transform-origin' property on the pattern in the following example specifies a ''50%'' translation of the origin in the horizontal and vertical dimension. The 'transform' property specifies a translation as well, but in absolute lengths.
465481

466-
<pre>
482+
<pre><code highlight=xml>
467483
&lt;svg xmlns="http://www.w3.org/2000/svg">
468484
&lt;style>
469485
pattern {
@@ -480,7 +496,7 @@ The 'transform-origin' property on the pattern in the following example specifie
480496

481497
&lt;rect width="200" height="200" fill="url(#pattern-1)" />
482498
&lt;/svg>
483-
</pre>
499+
</code></pre>
484500

485501
An SVG <{pattern}> element doesn't have a bounding box. The [=reference box=] of the referencing <{rect}> element is used instead to solve the relative values of the 'transform-origin' property. Therefore the point of origin will get translated by 100 pixels temporarily to rotate the user space of the <{pattern}> elements content.
486502

@@ -507,7 +523,7 @@ With this specification, the <{animate}> element and the <{set}> element can ani
507523

508524
The animation effect is post-multiplied to the underlying value for additive <{animate}> animations (see below) instead of added to the underlying value, due to the specific behavior of <<transform-list>> animations.
509525

510-
Issue(w3c/csswg-drafts#909) Clarify post-/pre-multiply column-/row-major order.
526+
Issue(w3c/csswg-drafts#909): Clarify post-/pre-multiply column-/row-major order.
511527

512528
<var ignore=''>From-to</var>, <var ignore=''>from-by</var> and <var ignore=''>by</var> animations are defined in SMIL to be equivalent to a corresponding <var>values</var> animation. However, <var ignore=''>to</var> animations are a mixture of additive and non-additive behavior [[SMIL3]].
513529

@@ -557,16 +573,16 @@ Note: This paragraph focuses on the requirements of [[SMIL]] and the extension d
557573

558574
<div class="example">
559575

560-
A <var>by</var> animation with a by value v<sub>b</sub> is equivalent to the same animation with a values list with 2 values, the neutral element for addition for the domain of the target attribute (denoted 0) and v<sub>b</sub>, and ''additive="sum"''. [[SMIL3]]
576+
A <var>by</var> animation with a by value v<sub>b</sub> is equivalent to the same animation with a values list with 2 values, the neutral element for addition for the domain of the target attribute (denoted 0) and v<sub>b</sub>, and ''additive&#61;"sum"''. [[SMIL3]]
561577

562-
<pre>
563-
&lt;rect width="100" height="100">
578+
<pre><code highlight=xml>
579+
&lt;rect width="100" height="100">
564580
&lt;animateTransform attributeName="transform" attributeType="XML"
565-
type="scale" by="1" dur="5s" fill="freeze"/>
566-
&lt;/rect>
567-
</pre>
581+
type="scale" by="1" dur="5s" fill="freeze"/>
582+
&lt;/rect>
583+
</code></pre>
568584

569-
The neutral element for addition when performing a <var>by</var> animation with ''type="scale"'' is the value 0. Thus, performing the animation of the example above causes the rectangle to be invisible at time 0s (since the animated transform list value is ''scale(0)''), and be scaled back to its original size at time 5s (since the animated transform list value is ''scale(1)'').
585+
The neutral element for addition when performing a <var>by</var> animation with ''type&#61;"scale"'' is the value 0. Thus, performing the animation of the example above causes the rectangle to be invisible at time 0s (since the animated transform list value is ''scale(0)''), and be scaled back to its original size at time 5s (since the animated transform list value is ''scale(1)'').
570586

571587
</div>
572588

@@ -579,12 +595,14 @@ The SVG '<a href="https://www.w3.org/TR/SVG/animate.html#TargetAttributes">attri
579595

580596
In this example the gradient transformation of the linear gradient gets animated.
581597

582-
<pre>&lt;linearGradient gradientTransform="scale(2)">
583-
&lt;animate attributeName="gradientTransform" from="scale(2)" to="scale(4)"
584-
dur="3s" additive="sum"/>
585-
&lt;animate attributeName="transform" from="translate(0, 0)" to="translate(100px, 100px)"
586-
dur="3s" additive="sum"/>
587-
&lt;/linearGradient></pre>
598+
<pre><code highlight=xml>
599+
&lt;linearGradient gradientTransform="scale(2)">
600+
&lt;animate attributeName="gradientTransform" from="scale(2)" to="scale(4)"
601+
dur="3s" additive="sum"/>
602+
&lt;animate attributeName="transform" from="translate(0, 0)" to="translate(100px, 100px)"
603+
dur="3s" additive="sum"/>
604+
&lt;/linearGradient>
605+
</code></pre>
588606

589607
The <{linearGradient}> element specifies the <{linearGradient/gradientTransform}> presentation attribute. The two <{animate}> elements address the target attribute <{linearGradient/gradientTransform}> and 'transform'. Even so all animations apply to the same gradient transformation by taking the value of the <{linearGradient/gradientTransform}> presentation attribute, applying the scaling of the first animation and applying the translation of the second animation one after the other.
590608

@@ -666,32 +684,34 @@ The Transform Function Lists {#transform-function-lists}
666684

667685
If a list of <<transform-function>> is provided, then the net effect is as if each transform function had been specified separately in the order provided. For example,
668686

669-
<pre>
670-
&lt;div style="transform:translate(-10px,-20px) scale(2) rotate(45deg) translate(5px,10px)"/>
671-
</pre>
687+
<pre><code highlight=html>
688+
&lt;div style="transform: translate(-10px,-20px) scale(2) rotate(45deg) translate(5px,10px)"/>
689+
</code></pre>
672690

673691
is functionally equivalent to:
674692

675-
<pre>
676-
&lt;div style="transform:translate(-10px,-20px)">
677-
&lt;div style="transform:scale(2)">
678-
&lt;div style="transform:rotate(45deg)">
679-
&lt;div style="transform:translate(5px,10px)">
693+
<pre><code highlight=html>
694+
&lt;div style="transform: translate(-10px,-20px)" id="root">
695+
&lt;div style="transform: scale(2)">
696+
&lt;div style="transform: rotate(45deg)">
697+
&lt;div style="transform: translate(5px,10px)" id="child">
680698
&lt;/div>
681699
&lt;/div>
682700
&lt;/div>
683701
&lt;/div>
684-
</pre>
702+
</code></pre>
703+
704+
That is, in the absence of other styling that affects position and dimensions, a nested set of transforms is equivalent to a single list of transform functions, applied from the top ancestor (with the id <code>root</code>) to the deepest descendant (with the id <code>child</code>). The resulting transform is the matrix multiplication of the list of transforms.
685705

686-
That is, in the absence of other styling that affects position and dimensions, a nested set of transforms is equivalent to a single list of transform functions, applied from the outside in. The resulting transform is the matrix multiplication of the list of transforms.
706+
Issue(w3c/csswg-drafts#909): Backport point mapping from one coordinate space to another from SVG.
687707

688708
If a transform function causes the [=current transformation matrix=] of an object to be non-invertible, the object and its content do not get displayed.
689709

690710
<div class="example">
691711

692712
The object in the following example gets scaled by 0.
693713

694-
<pre>
714+
<pre><code highlight=html>
695715
&lt;style>
696716
.box {
697717
transform: scale(0);
@@ -701,7 +721,7 @@ The object in the following example gets scaled by 0.
701721
&lt;div class="box">
702722
Not visible
703723
&lt;/div>
704-
</pre>
724+
</code></pre>
705725

706726
The scaling causes a non-invertible CTM for the coordinate space of the div box. Therefore neither the div box, nor the text in it get displayed.
707727

@@ -772,7 +792,7 @@ Two different types of transform functions that share the same primitive, or tra
772792
The following example describes a transition from ''translateX(100px)'' to ''translateY(100px)'' in 3 seconds on hovering over the div box. Both transform functions derive from the same primitive ''translate()''
773793
and therefore can be interpolated.
774794

775-
<pre>
795+
<pre><code highlight=css>
776796
div {
777797
transform: translateX(100px);
778798
}
@@ -781,7 +801,7 @@ and therefore can be interpolated.
781801
transform: translateY(100px);
782802
transition: transform 3s;
783803
}
784-
</pre>
804+
</code></pre>
785805

786806
For the time of the transition both transform functions get transformed to the common primitive. ''translateX(100px)'' gets converted to ''translate(100px, 0)'' and ''translateY(100px)'' gets converted to ''translate(0, 100px)''. Both transform functions can then get interpolated numerically.
787807
</div>
@@ -792,7 +812,7 @@ If both transform functions share a primitive in the two-dimensional space, both
792812

793813
In this example a two-dimensional transform function gets animated to a three-dimensional transform function. The common primitive is ''translate3d()''.
794814

795-
<pre>
815+
<pre><code highlight=css>
796816
div {
797817
transform: translateX(100px);
798818
}
@@ -801,7 +821,7 @@ In this example a two-dimensional transform function gets animated to a three-di
801821
transform: translateZ(100px);
802822
transition: transform 3s;
803823
}
804-
</pre>
824+
</code></pre>
805825

806826
First ''translateX(100px)'' gets converted to ''translate3d(100px, 0, 0)'' and ''translateZ(100px)'' to ''translate3d(0, 0, 100px)'' respectively. Then both converted transform functions get interpolated numerically.
807827

@@ -813,27 +833,27 @@ Interpolation of Matrices {#matrix-interpolation}
813833

814834
When interpolating between two matrices, each matrix is decomposed into the corresponding translation, rotation, scale, skew. Each corresponding component of the decomposed matrices gets interpolated numerically and recomposed back to a matrix in a final step.
815835

836+
<div class="example">
816837
In the following example the element gets translated by 100 pixel in both the X and Y directions and rotated by 1170&deg; on hovering. The initial transformation is 45&deg;. With the usage of transition, an author might expect a animated, clockwise rotation by three and a quarter turns (1170&deg;).
817838

818-
<div class="example">
819-
<pre>
820-
&lt;style>
821-
div {
822-
transform: rotate(45deg);
823-
}
824-
div:hover {
825-
transform: translate(100px, 100px) rotate(1215deg);
826-
transition: transform 3s;
827-
}
828-
&lt;/style>
839+
<pre><code highlight=html>
840+
&lt;style>
841+
div {
842+
transform: rotate(45deg);
843+
}
844+
div:hover {
845+
transform: translate(100px, 100px) rotate(1215deg);
846+
transition: transform 3s;
847+
}
848+
&lt;/style>
829849

830-
&lt;div>&lt;/div>
831-
</pre>
832-
</div>
850+
&lt;div>&lt;/div>
851+
</code></pre>
833852

834853
The number of transform functions on the source transform ''rotate(45deg)'' differs from the number of transform functions on the destination transform ''translate(100px, 100px) rotate(1125deg)''. According to the last rule of <a href="#interpolation-of-transforms">Interpolation of Transforms</a>, both transforms must be interpolated by matrix interpolation. With converting the transformation functions to matrices, the information about the three turns gets lost and the element gets rotated by just a quarter turn (90&deg;).
835854

836855
To achieve the three and a quarter turns for the example above, source and destination transforms must fulfill the third rule of <a href="#interpolation-of-transforms">Interpolation of Transforms</a>. Source transform could look like ''translate(0, 0) rotate(45deg)'' for a linear interpolation of the transform functions.
856+
</div>
837857

838858
In the following we differ between the <a href="#interpolation-of-2d-matrices">interpolation of two 2D matrices</a> and the interpolation of two matrices where at least one matrix is not a [=2D matrix=].
839859

0 commit comments

Comments
 (0)