- 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