W3C home > Mailing lists > Public > www-style@w3.org > November 2007

Apple's Proposal for CSS Transformations

From: David Hyatt <hyatt@apple.com>
Date: Tue, 06 Nov 2007 14:29:55 -0600
To: www-style@w3.org
Message-id: <83E7B4BB-1FB2-485B-AC53-5189E76E984D@apple.com>

CSS Transforms

6 Nov 2007

Authors:
Dave Hyatt (hyatt@apple.com), Apple
Dean Jackson (dean.jackson@apple.com), Apple
Chris Marrin (cmarrin@apple.com), Apple
The CSS visual formatting model describes a coordinate system within  
which each element is positioned. Positions and sizes in this  
coordinate space can be thought of as being expressed in pixels,  
starting in the upper left corner of the parent with positive values  
proceeding to the right and down.

This coordinate space can be modified with the 'transform' property.  
Using transform, elements can be translated, rotated and scaled in  
two or three dimensional space. A perspective transform can also be  
applied to give a sense of depth to the way elements are displayed.  
In two dimensions, the coordinate space behaves as described in the  
coordinate system transformations section of the SVG 1.1  
specification. This is a coordinate system with two axes: the X axis  
increases horizontally to the right; the Y axis increases vertically  
downwards. In three dimensions, a Z axis is added, with positive z  
values conceptually rising perpendicularly out of the window toward  
the user and negative z values falling into the window away from the  
user.

Specifying a value other than 'none' for the 'transform' property  
establishes a new local coordinate system at the element that it is  
applied to. Transformations are cumulative. That is, elements  
establish their local coordinate system within the coordinate system  
of their parent. In this way, a 'transform' property effectively  
accumulates all the 'transform' properties of its ancestors. The  
accumulation of these transforms defines a current transformation  
matrix (CTM) for the element.

The transform property does not affect the flow of the content  
surrounding the transformed element. However, the value of the  
overflow area takes into account transformed elements. This behavior  
is similar to what happens when elements are translated via relative  
positioning. Therefore, if the value of the 'overflow' property is  
'scroll' or 'auto', scrollbars will appear as needed to see content  
that is transformed outside the visible area.

Any value other than 'none' for the transform results in the creation  
of both a stacking context and a containing block. The object acts as  
though position: relative has been specified, but also acts a  
containing block for fixed positioned descendants. The z position of  
a transformed element does not affect the order within a stacking  
context. With elements at the same z-index, objects are drawn in  
order of increasing z position.

Need to go into more detail here about why fixed positioned objects  
should do this, i.e., that it's much harder to implement otherwise.
Transforms should perhaps be allowed to affect layout. Using the  
position property to do this seems to be the logical choice, but  
there are lots of questions about how this would work.
What do fixed backgrounds do in transforms? They should probably  
ignore the transform completely, since - even transformed - the  
object should be acting as "porthole" through which the fixed  
background can be viewed in its original form.
Note that while 'transform' uses a three-dimensional coordinate  
system, the elements themselves are not three-dimensional objects.  
Instead, they exist on a two-dimensional plane (a flat surface) and  
have no depth. Furthermore, elements do not intersect with each other  
in the manner of real-world objects: an element always appears  
completely in front of or behind another element. In other words,  
even though the z axis may not be perpendicular to an element's  
surface, an element always has a single z position, calculated at the  
center of the element.

This property should also be applicable to SVG elements, but since  
SVG doesn't have stacking contexts we'd have to describe how the  
painters' model is changed by z position.
We also need to specify that SVG transforms *do* combine with this  
transform, e.g., if a <foreignObject> is inside transformed SVG and  
then defines a transform of its own. This means we may potentially  
have to examine the current SVG transform and combine with it to set  
the correct transform.
The 'transform' Property

A 2D or 3D transformation is applied to an element through the  
'transform' property. This property contains a list of transform  
functions. The final transformation value for an element is obtained  
by performing a matrix concatenation of each entry in the list. The  
set of transform functions is similar to those allowed by SVG. There  
are also additional functions to support 3D transformations.

Name:	transform
Value:	none | [ <transform-function> ]* <transform-function>
Initial:	none
Applies to:	block-level and inline-level elements
Inherited:	no
Percentages:	refer to the size of the element's box
Media:	visual
Computed value:	Same as specified value.
The 'transform-origin' Property

The 'transform-origin' property establishes the origin of  
transformation for an element. This property is applied by first  
translating the element by the negated value of the property, then  
applying the element's transform, then translating by the property  
value. This effectively moves the desired transformation origin of  
the element to (0,0) in the local coordinate system, then applies the  
element's transform, then moves the element back to its original  
position. Since the transform origin only describes X and Y values,  
moving the origin along the Z axis must be done in the transformation  
(using the translate3d() transform function).

Name:	transform-origin
Value:	[ [ <percentage> | <length>]{1,2} | [top | center | bottom] ||  
[left | center | right] ] ]
Initial:	50% 50%
Applies to:	block-level and inline-level elements
Inherited:	no
Percentages:	refer to the size of the element's box
Media:	visual
Computed value:	Same as specified value.
This needs to be extended to 3d.
The 'transform-style' Property

The 'transform-style' property defines how nested elements are  
rendered in 3D space. If the 'transform-style' is 'flat', all  
children of this element are rendered flattened into the 2D plane of  
the element. Therefore, rotating the element about the X or Y axes  
will cause children positioned at positive or negative Z positions to  
appear on the element's plane, rather than in front of or behind it.  
If the 'transform-style' is 'perspective', this flattening is not  
performed, so children maintain their position in 3D space.

This flattening takes place at each element, so preserving a  
hierarchy of elements in 3D space requires that each ancestor in the  
hierarchy have the value 'perspective' for 'transform-style'. But  
since the 'transform-style' affects only an element's children, the  
leaf nodes in a hierarchy do not require the perspective style.

Name:	transform-style
Value:	flat | perspective
Initial:	flat
Applies to:	block-level and inline-level elements
Inherited:	no
Percentages:	N/A
Media:	visual
Computed value:	Same as specified value.
Does transform-style:perspective need to establish a stacking context  
and containing block like transform does?
The 'perspective' Property

The 'perspective' property applies the same transform as the  
perspective(<number>) transform function, except that it applies only  
to the children of the element, not to the transform on the element  
itself. If the value is 'none' no perspective transform is applied.

The use of this property with any value other than 'none' establishes  
a stacking context. It also establishes a containing block (somewhat  
similar to position:relative), just like the 'transform' property does.

Name:	perspective
Value:	none | <number>
Initial:	none
Applies to:	block-level and inline-level elements
Inherited:	no
Percentages:	N/A
Media:	visual
Computed value:	Same as specified value.
The 'perspective-origin' Property

The 'perspective-origin' property establishes the origin for the  
perspective property. It effectively sets the X and Y position at  
which the viewer appears to be looking at the children of the element.

Name:	perspective-origin
Value:	[ [ <percentage> | <length>]{1,2} | [top | center | bottom] ||  
[left | center | right] ] ] | inherit
Initial:	50% 50%
Applies to:	block-level and inline-level elements
Inherited:	no
Percentages:	refer to the size of the box itself
Media:	visual
Computed value:	Same as specified value.
The Transformation Functions

The value of the transform property is a <transform-list>, which is  
defined as a list of transform functions, applied in the order  
provided. The individual transform functions are separated by  
whitespace. The following is a list of allowed transform functions.

matrix(<number>, <number>, <number>, <number>, <number>, <number>)
specifies a 2D transformation in the form of a transformation matrix  
of six values. matrix(a,b,c,d,e,f) is equivalent to applying the  
transformation matrix [a b c d e f].
matrix3d(<number>, <number>, <number>, <number>,
                 <number>, <number>, <number>, <number>,
                 <number>, <number>, <number>, <number>,
                 <number>, <number>, <number>, <number>)
specifies a 3D transformation as a 4x4 homogeneous matrix of 16  
values in column-major order.
translate(<translation-value>[, <translation-value>])
specifies a 2D translation by the vector [tx, ty], where tx is the  
first translation-value parameter and ty is the optional second  
translation-value parameter. If <ty> is not provided, ty has zero as  
a value.
translate3d(<translation-value>, <translation-value>, <translation- 
value>)
specifies a 3D translation by the vector [tx,ty,tz], with tx, ty and  
tz being the first, second and third translation-value parameters  
respectively.
translateX(<translation-value>)
specifies a translation by the given amount in the X direction.
translateY(<translation-value>)
specifies a translation by the given amount in the Y direction.
translateZ(<translation-value>)
specifies a translation by the given amount in the Z direction.
scale(<number>[, <number>])
specifies a 2D scale operation by the [sx,sy] scaling vector  
described by the 2 parameters. If the second parameter is not  
provided, it is takes a value equal to the first.
scale3d(<number>, <number>, <number>)
specifies a 3D scale operation by the [sx,sy,sz] scaling vector  
described by the 3 parameters.
scaleX(<number>)
specifies a scale operation using the [sx,1,1] scaling vector, where  
sx is given as the parameter.
scaleY(<number>)
specifies a scale operation using the [1,sy,1] scaling vector, where  
sy is given as the parameter.
scaleZ(<number>)
specifies a scale operation using the [1,1,sz] scaling vector, where  
sz is given as the parameter.
rotate(<angle>)
specifies a 2D rotation by the angle specified in the parameter about  
the origin of the element, as defined by the transform-origin  
property. The operation corresponds to the matrix [cos(a) sin(a) -sin 
(a) cos(a) 0 0].
rotate3d(<angle>, <number>, <number>, <number>)
specifies a clockwise 3D rotation by the angle specified in first  
parameter about the [x,y,z] direction vector described by the last 3  
parameters. This vector should be normalized (have a length of 1),  
otherwise the results are typically non-intuitive.
rotateX(<angle>)
specifies a clockwise rotation by the given angle about the X axis.
rotateY(<angle>)
specifies a clockwise rotation by the given angle about the Y axis.
rotateZ(<angle>)
specifies a clockwise rotation by the given angle about the Z axis.
skewX(<angle>)
specifies a skew transformation along the X axis by the given angle.
skewY(<angle>)
specifies a skew transformation along the Y axis by the given angle.
skewZ(<angle>)
specifies a skew transformation along the Z axis by the given angle.
perspective(<number>)
specifies a perspective projection matrix. This matrix maps the  
viewing cube (the region bounded by the 4 edges of the viewport plus  
the nearest and furthest visible z values) onto a truncated pyramid  
whose base represents the furthest visible z value and whose peak  
represents the viewer's position. The depth, given as the parameter  
to the function, represents the height of this pyramid. Lower values  
give a more flattened pyramid and therefore a more pronounced  
perspective effect. The value is given in pixels, so a value of 1000  
gives a moderate amount of foreshortening and a value of 200 gives an  
extreme amount. The matrix is computed by starting with an identity  
matrix and replacing the value at row 3, column 4 with the value -1/ 
depth.
The 3d versions could be folded into the 2d primitives using extra  
optional arguments. It's really just a question of how user agents  
that can't do 3d should be handled.
Transform Values and Lists

The <translation-value> values are defined as [<percentage> |  
<length>]. All other value types are described as CSS types. If a  
list of transforms is provided, then the net effect is as if each  
transform had been specified separately in the order provided. For  
example,

is functionally equivalent to:








div {
     transform: translate(100px, 100px);
}
Move the element by 100 pixels in both the X and Y directions.

div {
     transform: translate(50px, 50px) scale(1.40, 1.4) rotate(30deg);
}
Move the element by 50 pixels in both the X and Y directions, then  
scale the element by 140%, then rotate it 30 degrees clockwise about  
the Z axis.
Received on Tuesday, 6 November 2007 20:30:33 GMT

This archive was generated by hypermail 2.2.0+W3C-0.50 : Monday, 27 April 2009 13:54:56 GMT