Reputation: 1801
Is there any way to combine (mix) css transform properties without overriding? For example there I want to rotate and scale. http://jsfiddle.net/hyzhak/bmyN3/
<div class="item rotate-90 tiny-size">
Hello World!
</div>
.rotate-90 {
-webkit-transform: rotate(90deg);
}
.tiny-size {
-webkit-transform: scale(0.25, 0.25);
}
I just have a lot of elements and a lot of simple classes to transform view of the elements. And I just want to tune view of them by adding and removing some classes. Combining of all classes doesn't work because it will be hundreds of combinations.
As well I want to do it in realtime.
The number of transformations can be approximately 5 and each of them can hold about 10 states - so just describe all combinations of them with hands give you approximately
10*10*10*10*10 = 100000 cases
It is a bad solution.
Upvotes: 27
Views: 17692
Reputation: 81
One thing you could do is get the computed transform style in JS and concatenate your secondary transform value:
HTML
<div class="rotate-scale"></div>
CSS
.rotate-scale {
transform: rotate(90deg);
}
JS
var el = document.querySelector('.rotate-scale'),
// rotation will get the transform value declared in css
rotation = window.getComputedStyle(el).getPropertyValue('transform');
el.style.transform = rotation + 'scale(0.25, 0.25)';
Upvotes: 1
Reputation: 897
The way I get around this issue is to add a wrapper class around the one I want. For example, I have the wrapper which has its position set via javascript, and then the internal which is is affected by css animations - both on the transform property.
I know adding DOM nodes isn't ideal but it circumvents the script-heavy solution and lets the browser optimise the animations and transitions as it would normally.
Upvotes: 8
Reputation: 25954
Currently there is no way to do this, it only accepts one command for transform
at a time and cannot add or subtract like you'd like. Thus you'll have to add or remove a class depending on what the first and second type is and write a custom transform
for that element
Using a CSS preprocessor language like SASS or LESS could make combining transitions easier, the following allows for any number of transition
s to be combined into one, but requires being told which ones to add (this is SCSS)
.item {
width:500px;
height:500px;
font-size:150px;
background:blue;
}
$firstTransform: rotate(90deg);
$secondTransform: scale(0.25, 0.25);
@mixin transform($transform...) {
-webkit-transform: $transform;
-moz-transform: $transform;
-ms-transform: $transform;
-o-transform: $transform;
transform: $transform;
}
.rotate-90 {
@include transform($firstTransform);
}
.tiny-size {
@include transform($secondTransform);
}
.both {
@include transform($firstTransform $secondTransform);
}
Really the only way to do it currently would be to use javascript, essentially adding a class with a transform, saving a variable of that class' transforms, removing the class and doing the same with another class, then combine the two matrices of the class' transforms. EDIT: See brejep's javascript answer for more on this approach
Upvotes: 4
Reputation: 416
Here's an attempt at solving the problem with Javascript: http://jsfiddle.net/eGDP7/
I'm using a data attribute on the html to list the classes with transforms that we want to apply:
<div class="compoundtransform" data-transformations="scaletrans2, rotatetrans1">Test subject</div>
I iterate through the classes and find out what css rules they represent:
function getCSSRulesForClass( selector ) {
var sheets = document.styleSheets;
var cssRules = [];
for (var i = 0; i<sheets.length; ++i) {
var sheet = sheets[i];
if( !sheet.cssRules ) { continue; }
for (var j = 0; j < sheet.cssRules.length; ++j ) {
var rule = sheet.cssRules[j];
if (rule.selectorText && rule.selectorText.split(',').indexOf(selector) !== -1) {
var styles = rule.style;
for( var k = 0; k<styles.length; ++k ) {
var style = styles[k];
cssRules.push( {
property: style,
value: styles[style]
} );
}
}
}
}
return cssRules;
}
I find any transforms and apply the transforms to a matrix:
function convertTransformToMatrix( source, transformValue ) {
var values = transformValue.split(") "); // split into array if multiple values
var matrix = cloneObject( source );
for ( var i = 0; i<values.length; ++i ) {
var value = values[i];
if( isRotate( value ) ) {
var rotationValue = cssRotationToRadians( value );
var cosValue = Math.cos( rotationValue );
var sinValue = Math.sin( rotationValue );
var a = matrix.a;
var b = matrix.b;
var c = matrix.c;
var d = matrix.d;
var tx = matrix.tx;
var ty = matrix.ty;
matrix.a = a*cosValue - b*sinValue;
matrix.b = a*sinValue + b*cosValue;
matrix.c = c*cosValue - d*sinValue;
matrix.d = c*sinValue + d*cosValue;
matrix.tx = tx*cosValue - ty*sinValue;
matrix.ty = tx*sinValue + ty*cosValue;
} else if ( isScale( value ) ) {
var scale = cssScaleToObject( value );
matrix.a *= scale.x;
matrix.b *= scale.y;
matrix.c *= scale.x;
matrix.d *= scale.y;
matrix.tx *= scale.x;
matrix.ty *= scale.y;
} else if ( isTranslate( value ) ) {
var translate = cssTranslateToObject( value );
matrix.tx += translate.x;
matrix.ty += translate.y;
}
}
return matrix;
}
And I, finally, apply that matrix to the node as a transform.
Currently:
I might tidy it up and turn it into a utility if useful to anyone.
Upvotes: 8
Reputation: 416
Instead of rotate and scale you could use the matrix function.
transform: matrix(a, b, c, d, tx, ty);
In the example given, I believe the following would produce the desired result:
transform: matrix(0,-0.25,0.25,0,0,0);
For an explanation of matrix calculations:
And some useful tools exist for calculating these matrices as CSS, such as:
Upvotes: 2
Reputation: 43755
Hmm...as far as I know, you would have to create new class and combine them this way (separated by a space):
-webkit-transform: rotate(90deg) scale(0.25, 0.25);
Upvotes: 10