- 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 UTC