CSS 2D Transforms allows elements rendered by CSS to be transformed in two-dimensional space.
This section is not normative.
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 dimensional space. 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.
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 as a containing block for fixed positioned descendants.
A two-dimensional 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.
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 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.
Name: | transform-origin |
Value: | [ [ <percentage> | <length> | left | center | right ] [ <percentage> | <length> | top | center | bottom ]? ] | [ [ left | center | right ] || [ top | center | bottom ] ] |
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: | For <length> the absolute value, otherwise a percentage |
The value of the transform property is 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. In this list the type <translation-value> is defined as a <length> or <percentage> value, and the <angle> type is defined by CSS Values and Units.
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,
<div style="transform:translate(-10px,-20px) scale(2) rotate(45deg) translate(5px,10px)"/>
is functionally equivalent to:
<div style="transform:translate(-10px,-20px)"> <div style="transform:scale(2)"> <div style="transform:rotate(45deg)"> <div style="transform:translate(5px,10px)"> </div> </div> </div> </div>
div { transform: translate(100px, 100px); }Move the element by 100 pixels in both the X and Y directions.
div { height: 100px; width: 100px; transform: translate(80px, 80px) scale(1.5, 1.5) rotate(45deg); }Move the element by 80 pixels in both the X and Y directions, then scale the element by 150%, then rotate it 45 degrees clockwise about the Z axis. Note that the scale and rotate operate about the center of the element, since the element has the default transform-origin of 50% 50%.
When animating or transitioning the value of a transform property the rules described below are applied. The 'from' transform is the transform at the start of the transition or current keyframe. The 'end' transform is the transform at the end of the transition or current keyframe.
For example, if the 'from' transform is "scale(2)" and the 'to' transform is "none" then the value "scale(1)" will be used as the 'to' value, and animation will proceed using the rule above. Similarly, if the 'from' transform is "none" and the 'to' transform is "scale(2) rotate(50deg)" then the animation will execute as if the 'from' value is "scale(1) rotate(0)".
The identity functions are translate(0), translateX(0), translateY(0), scale(1), scaleX(1), scaleY(1), rotate(0), rotateX(0), rotateY(0), skewX(0), skewY(0), and matrix(1, 0, 0, 1, 0, 0).
When interpolating between 2 matrices, each is decomposed into the corresponding translation, rotation, scale, skew, and perspective values. Not all matrices can be accurately described by these values. Those that can't are decomposed into the most accurate representation possible, using the technique below. This technique is taken from The "unmatrix" method in "Graphics Gems II, edited by Jim Arvo". The pseudocode below works on a 4x4 homogeneous matrix. A 3x2 2D matrix is therefore first converted to 4x4 homogeneous form.
Input: matrix ; a 4x4 matrix Output: translation ; a 3 component vector rotation ; euler angles, represented as a 3 component vector scale ; a 3 component vector skew ; skew factors XY,XZ,YZ represented as a 3 component vector perspective ; a 4 component vector Returns false if the matrix cannot be decomposed, true if it can Supporting functions (point is a 3 component vector, matrix is a 4x4 matrix): float determinant(matrix) returns the 4x4 determinant of the matrix matrix inverse(matrix) returns the inverse of the passed matrix matrix transpose(matrix) returns the transpose of the passed matrix point multVecMatrix(point, matrix) multiplies the passed point by the passed matrix and returns the transformed point float length(point) returns the length of the passed vector point normalize(point) normalizes the length of the passed point to 1 float dot(point, point) returns the dot product of the passed points float cos(float) returns the cosine of the passed angle in radians float asin(float) returns the arcsine in radians of the passed value float atan2(float y, float x) returns the principal value of the arc tangent of y/x, using the signs of both arguments to determine the quadrant of the return value Decomposition also makes use of the following function: point combine(point a, point b, float ascl, float bscl) result[0] = (ascl * a[0]) + (bscl * b[0]) result[1] = (ascl * a[1]) + (bscl * b[1]) result[2] = (ascl * a[2]) + (bscl * b[2]) return result // Normalize the matrix. if (matrix[3][3] == 0) return false for (i = 0; i < 4; i++) for (j = 0; j < 4; j++) matrix[i][j] /= matrix[3][3] // perspectiveMatrix is used to solve for perspective, but it also provides // an easy way to test for singularity of the upper 3x3 component. perspectiveMatrix = matrix for (i = 0; i < 3; i++) perspectiveMatrix[i][3] = 0 perspectiveMatrix[3][3] = 1 if (determinant(perspectiveMatrix) == 0) return false // First, isolate perspective. if (matrix[0][3] != 0 || matrix[1][3] != 0 || matrix[2][3] != 0) // rightHandSide is the right hand side of the equation. rightHandSide[0] = matrix[0][3]; rightHandSide[1] = matrix[1][3]; rightHandSide[2] = matrix[2][3]; rightHandSide[3] = matrix[3][3]; // Solve the equation by inverting perspectiveMatrix and multiplying // rightHandSide by the inverse. inversePerspectiveMatrix = inverse(perspectiveMatrix) transposedInversePerspectiveMatrix = transposeMatrix4(inversePerspectiveMatrix) perspective = multVecMatrix(rightHandSide, transposedInversePerspectiveMatrix) // Clear the perspective partition matrix[0][3] = matrix[1][3] = matrix[2][3] = 0 matrix[3][3] = 1 else // No perspective. perspective[0] = perspective[1] = perspective[2] = 0 perspective[3] = 1 // Next take care of translation translate[0] = matrix[3][0] matrix[3][0] = 0 translate[1] = matrix[3][1] matrix[3][1] = 0 translate[2] = matrix[3][2] matrix[3][2] = 0 // Now get scale and shear. 'row' is a 3 element array of 3 component vectors for (i = 0; i < 3; i++) row[i][0] = matrix[i][0] row[i][1] = matrix[i][1] row[i][2] = matrix[i][2] // Compute X scale factor and normalize first row. scale[0] = length(row[0]) row[0] = normalize(row[0]) // Compute XY shear factor and make 2nd row orthogonal to 1st. skew[0] = dot(row[0], row[1]) row[1] = combine(row[1], row[0], 1.0, -skew[0]) // Now, compute Y scale and normalize 2nd row. scale[1] = length(row[1]) row[1] = normalize(row[1]) skew[0] /= scale[1]; // Compute XZ and YZ shears, orthogonalize 3rd row skew[1] = dot(row[0], row[2]) row[2] = combine(row[2], row[0], 1.0, -skew[1]) skew[2] = dot(row[1], row[2]) row[2] = combine(row[2], row[1], 1.0, -skew[2]) // Next, get Z scale and normalize 3rd row. scale[2] = length(row[2]) row[2] = normalize(row[2]) skew[1] /= scale[2] skew[2] /= scale[2] // At this point, the matrix (in rows) is orthonormal. // Check for a coordinate system flip. If the determinant // is -1, then negate the matrix and the scaling factors. pdum3 = cross(row[1], row[2]) if (dot(row[0], pdum3) < 0) for (i = 0; i < 3; i++) { scale[0] *= -1; row[i][0] *= -1 row[i][1] *= -1 row[i][2] *= -1 // Now, get the rotations ou rotate[1] = asin(-row[0][2]); if (cos(rotate[1]) != 0) rotate[0] = atan2(row[1][2], row[2][2]); rotate[2] = atan2(row[0][1], row[0][0]); else rotate[0] = atan2(-row[2][0], row[1][1]); rotate[2] = 0; return true;
Each component of each returned value is linearly interpolated with the corresponding component of the other matrix. The resulting components are then recomposed into a final matrix as though combining the following transform functions:
matrix3d(1,0,0,0, 0,1,0,0, 0,0,1,0, perspective[0], perspective[1], perspective[2], perspective[3]) translate3d(translation[0], translation[1], translation[2]) rotateX(rotation[0]) rotateY(rotation[1]) rotateZ(rotation[2]) matrix3d(1,0,0,0, 0,1,0,0, 0,skew[2],1,0, 0,0,0,1) matrix3d(1,0,0,0, 0,1,0,0, skew[1],0,1,0, 0,0,0,1) matrix3d(1,0,0,0, skew[0],1,0,0, 0,0,1,0, 0,0,0,1) scale3d(scale[0], scale[1], scale[2])
This section describes the interfaces and functionality added to the DOM to support runtime access to the functionality described above.
The Point
interface represents a point in two-dimensional space.
interface Point { attribute float x; attribute float y; };
x
of type float
y
of type float
The following 2 functions are added to the Window
interface. They provide conversions
between the page and node coordinate spaces.
interface Window { ... Point convertPointFromPageToNode(in Node node, in Point point); Point convertPointFromNodeToPage(in Node node, in Point point); ... };
convertPointFromPageToNode
convertPointFromPageToNode
method returns a point in the coordinate space of
the passed Node that is at the same location in the page as the passed point, which is in the
coordinate space of the page.
node
of type Node
point
of type Point
Point
convertPointFromNodeToPage
convertPointFromNodeToPage
method returns a point in the coordinate space
of the page that is at the same location in the page as the passed point, which is in
the coordinate space of the passed Node.
node
of type Node
point
of type Point
Point
The CSSMatrix
interface represents a 4x4 homogeneous matrix.
interface CSSMatrix { attribute float a; attribute float b; attribute float c; attribute float d; attribute float e; attribute float f; void setMatrixValue(in DOMString string) raises(DOMException); CSSMatrix multiply(in CSSMatrix secondMatrix); CSSMatrix inverse() raises(DOMException); CSSMatrix translate(in float x, in float y); CSSMatrix scale(in float scaleX, in float scaleY); CSSMatrix rotate(in float angle); };
a-f
of type float
setMatrixValue
setMatrixValue
method replaces the existing matrix with one computed from
parsing the passed string as though it had been assigned to the transform property in a CSS
style rule.
string
of type DOMString
SYNTAX_ERR
multiply
multiply
method returns a new CSSMatrix which is the result of this matrix
multiplied by the passed matrix, with the passed matrix to the right. This matrix is not modified.
secondMatrix
of type CSSMatrix
CSSMatrix
inverse
inverse
method returns a new matrix which is the inverse of this matrix. This
matrix is not modified.
CSSMatrix
NOT_SUPPORTED_ERROR
translate
translate
method returns a new matrix which is this matrix post multiplied
by a translation matrix containing the passed
values. This matrix is not modified.
x
of type float
y
of type float
CSSMatrix
scale
scale
method returns a new matrix which is this matrix post multiplied by a
scale matrix containing the passed values. If the z component is undefined, a 1 value is used in
its place. If the y component is undefined, the x component value is used in its
place. This matrix is not modified.
scaleX
of type float
scaleY
of type float
CSSMatrix
rotate
rotate
method returns a new matrix which is this matrix post multiplied by
a rotation matrix. The rotation value is in degrees. This matrix is not modified.
angle
of type float
CSSMatrix
The CSSTransformValue
interface represents one transform function in the transform property. The
operationType
defines which operation is represented. The object also contains a list of values,
which are the parameters of the function, in the same order in which they appear in the transform functions.
interface CSSTransformValue : CSSValueList { // 2D OperationTypes const unsigned short CSS_TRANSLATE = 1; const unsigned short CSS_TRANSLATEX = 2; const unsigned short CSS_TRANSLATEY = 3; const unsigned short CSS_ROTATE = 4; const unsigned short CSS_SCALE = 5; const unsigned short CSS_SCALEX = 6; const unsigned short CSS_SCALEY = 7; const unsigned short CSS_SKEW = 8; const unsigned short CSS_SKEWX = 9; const unsigned short CSS_SKEWY = 10; const unsigned short CSS_MATRIX = 11; attribute unsigned short operationType; CSSMatrix getCSSMatrix() raises(DOMException); };
operationType
of type unsigned short
getCSSMatrix
getCSSMatrix
method returns
a CSSMatrix object representing this transform.
CSSMatrix
NOT_SUPPORTED_ERROR
In addition to the interfaces listed above, the getComputedStyle
method of the Window
object has been updated. The transform
property of the style object returned by
getComputedStyle
contains a single CSSTransformValue with a type of CSS_MATRIX. The 6 parameters
represent the 3x2 matrix that is the result of applying the individual functions listed in the
transform
property.