How to Apply Multiple Transform Declarations to One Element

How can I apply multiple transform declarations to one element?



I'm guessing this does not work because the classes override each other's transform property?

Correct. This is an unfortunate limitation as a side-effect of how the cascade works.

You will have to specify both functions in a single transform declaration. You could simply chain both class selectors together instead of creating a new class for a combined transform:

.doublesize.rotate {
-webkit-transform: scale(1) rotate(0deg);
}

.doublesize.rotate:hover {
-webkit-transform: scale(2) rotate(360deg);
}

... but as you can see, the issue lies in the transform property rather than in the selector.


This is expected to be rectified in Transforms level 2, where each transform has been promoted to its own property, which would allow you to combine transforms simply by declaring them separately as you would any other combination of CSS properties. This means you would be able to simply do this:

/* Note that rotate: 0deg and scale: 1 are omitted
as they're the initial values */

.rotate:hover {
rotate: 360deg;
}

.doublesize:hover {
scale: 2;
}

... and take advantage of the cascade rather than be hindered by it. No need for specialized class names or combined CSS rules.

How to apply multiple transforms to the same element

Without seeing your code it is hard to answer. BUT I think the reason this is happening is because transform is being overwritten in the animation.

Here is simple working example:

<div class="triangle"></div>
.triangle {
border: 20px transparent solid;
border-right-color: red;
display: inline-block;
animation-name: example;
animation-duration: 1s;
transform: rotate(45deg);
animation-fill-mode: forwards;

}

@keyframes example {
from {
transform: translate(0px, 0px) rotate(45deg);
}
to {
transform: translate(1000px, 0px) rotate(45deg);
}
}

[EDIT] Here are my suggestions after the author shared the code.

Basically, you are declaring transform more than once for a given element. in CSS the last occurrence overrides all previous occurrences. In order to solve this, you need to work around this. There is four ways you can do this:

  1. Convert
<div class="triangle topleft green column7 row2"></div>

to something like

<div class="triangle-holder topleft column7 row2">
<div class="triangle green"></div>
</div>

This allows you to have two different transforms on two different elements without overriding each other (as what's happening in the original code) The transform: rotate() is applied to .triangle, while transform: translate() is applied to .triangle-holder


  1. Get rid of transform: rotate() completely (as well as the background image), by using borders (see above for an example). This will only work for 90 degree rotations

  2. Get rid of transform: translate() and use margin or top/left for positioning.

  3. Animate each triangle explicitly in order to combine your transforms into one transformation.

I would recommend the second option, as it requires minimal changes to your code, and AFAIK is browser compatible way of creating CSS triangles.

How to apply multiple transforms in CSS?

You have to put them on one line like this:

li:nth-child(2) {
transform: rotate(15deg) translate(-20px,0px);
}

When you have multiple transform directives, only the last one will be applied. It's like any other CSS rule.


Keep in mind multiple transform one line directives are applied from right to left.

This: transform: scale(1,1.5) rotate(90deg);

and: transform: rotate(90deg) scale(1,1.5);

will not produce the same result:

.orderOne, .orderTwo {  font-family: sans-serif;  font-size: 22px;  color: #000;  display: inline-block;}
.orderOne { transform: scale(1, 1.5) rotate(90deg);}
.orderTwo { transform: rotate(90deg) scale(1, 1.5);}
<div class="orderOne">  A</div>
<div class="orderTwo"> A</div>

How do I connect html transforms in multiple classes?

You may look at CSS var(--X) (see links below snippet's demo) and , set all transformation you intend to 0 by default and update them via the className :(mind support before use : https://caniuse.com/#feat=mdn-css_properties_custom-property_var and eventually a polyfill https://github.com/nuxodin/ie11CustomProperties )

possible exemple without JavaScript https://codepen.io/gc-nomade/pen/RwWLOWr :

.foo {
--rotate: 20deg;
}

.bar {
--skewY: 20deg;
}

div[class] {
transform: rotate( var(--rotate, 0)) skewY( var(--skewY, 0));/* fallback value is here 0 */
}


/* demo purpose */

div[class] {
float: left;
border: solid;
}

html {
display: flex;
height: 100%;
}

body {
margin: auto;
}
<div class="foo bar">foo bar</div>
<div class="foo ">foo</div>
<div class="bar">bar</div>
<div class="nop">no transform</div>

Using multiple .style.transform on same element

When applying multiple transforms to the same element, they should be added as space separated values to the same property like below. Otherwise, they would get overwritten (only the rotateY will be applied because it is the latest).

object.style.transform = "rotateX(" + x + "deg)";
object.style.transform += "rotateY(" + y + "deg)";

I have added an alert of the object.style.transform to both the original snippet and the modified version and we can see how the original one always outputs only the rotateY whereas the changed one outputs both rotateX() and rotateY() together.

Original Code with Alerts added |
Modified Code with Alerts added

How to combine transforms in CSS?

As commented, I recommend you use an animation library for this, a good example is Velocity JS.

If a library like suggested is not an option, then read on!

If you were looking to do multiple transforms like that in one on top of your previous transforms, then you'd need to use the matrix value for the transform. Things get a little complicated with the matrix. The parameters for the matrix are in this order: -

matrix(scaleX(),skewY(),skewX(),scaleY(),translateX(),translateY());

Let's use the example of starting off with the initial fish animation you mentioned: -

fish {
animation: fishanimation 4s ease-in-out infinite alternate;
}

@keyframes fishanimation {
0% {
transform: matrix(1, 0, 0, 1, 0, 20);
}

100% {
transform: matrix(1, 0, 0, 1, 0, 80);
}
}

To dynamically change this in JavaScript will require some unpleasant string manipulation and getting the transform property of the element (which is more awkward than you think). Here's an example of how you might do it.

function getTransformValues(obj) {
var transform = {
scaleX: 1,
skewX: 0,
skewY: 0,
scaleY: 1,
translateX: 0,
translateY: 0
};

var matrix = obj.css("-webkit-transform") ||
obj.css("-moz-transform") ||
obj.css("-ms-transform") ||
obj.css("-o-transform") ||
obj.css("transform");

if (matrix && matrix !== 'none') {
var values = matrix.split('(')[1].split(')')[0].split(',');
transform.scaleX = parseFloat(values[0]);
transform.skewY = parseFloat(values[1]);
transform.skewX = parseFloat(values[2]);
transform.scaleY = parseFloat(values[3]);
transform.translateX = parseFloat(values[4]);
transform.translateY = parseFloat(values[5]);
}

return transform;
}

var values = getTransformValues($('#test'));
console.log(values);
// Object {scaleX: 1, skewX: 0, skewY: 0, scaleY: 2, translateX: 50, translateY: 40}

Now you've got those values you can start creating a new matrix by only changing the one you want, for example: -

var old = {
scaleX: 1,
skewX: 0,
skewY: 0,
scaleY: 2,
translateX: 50,
translateY: 40
};

$('#test').css('transform', 'matrix(' + old.scaleX + ', ' + old.skewY + ', ' + old.skewX + ', ' + old.scaleY + ', ' + old.translateX + ', ' + old.translateY + ')');

If you want to start manipulating the rotation angle things get even more complicated. To avoid bogging this answer so much, this part of the question has a solution at the following link: Get element -moz-transform:rotate value in jQuery

Hopefully you can see why adopting libraries such as Velocity JS, at least at the time of writing, is the best way to go for quick, easy, clean and smooth cross-browser animation.

Apply two different CSS transforms simultanesouly

transform is a single property, so you can't target from CSS for only part of it, e.g, you cannot set different CSS transition-duration for two transform-functions applied in the same transform property.

You could write everything through js, updating yourself both transform-functions values over time, but that would be a lot of work, for a potentially non-hardware accelerated result, while there is a simple workaround.

The easiest solution is to change a little bit your structure so that you apply the scale on a wrapper element, and the translate on the inner-one.

This way, both transforms are applied on your inner <img>, but they don't conflict each other.

// JavaScript source codevar catchX = 0,  catchY = 0,  x = 0,  y = 0,  burn = 1 / 28;
function imageWatch() { x += (catchX - x) * burn;
translate = 'translate(' + x + 'px, ' + y + 'px)';
$('.image-area img').css({ '-webit-transform': translate, '-moz-transform': translate, 'transform': translate });
window.requestAnimationFrame(imageWatch);}
$(window).on('mousemove click', function(e) {
var mouseX = Math.max(-100, Math.min(100, $(window).width() / 2 - e.clientX)); catchX = (26 * mouseX) / 100;
});
imageWatch();
html,body {  height: 100%}
body { margin: 0; padding: 0;}
*,*::before,*::after { content: "\0020"; box-sizing: border-box;}
.poster { display: inline-block; width: 32vw; height: 100vh; position: relative; overflow: hidden !important}
.image-area { position: absolute; width: 100%; height: 100vh; opacity: .24; transition: 2.5s ease;}
.image-area { opacity: 1;}
.image-area img { margin-top: -312px; margin-left: -913px; width: auto; /* height: auto */ height: 1000px; /* here we can remove the transition */}

/* scaling on hover is only applied on the parent elmt */
.image-area>.scaler { transform: scale(1, 1); transition: 8s transform;}
.poster:hover .image-area>.scaler { transform: scale(1.3, 1.3);}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script><div class="poster">  <div class="image-area">    <!-- the scaling wrapper-->    <div class="scaler">      <img class="poster" src="https://vignette1.wikia.nocookie.net/logopedia/images/f/fc/Sky_Believe_in_better_logo.jpg/revision/latest?cb=20110910152552" alt="Sky" />    </div>  </div></div>
<div class="poster"> <div class="image-area"> <!-- the scaling wrapper--> <div class="scaler"> <img class="poster" src="https://vignette1.wikia.nocookie.net/logopedia/images/f/fc/Sky_Believe_in_better_logo.jpg/revision/latest?cb=20110910152552" alt="Sky" /> </div> </div></div>
<div class="poster"> <div class="image-area"> <!-- the scaling wrapper--> <div class="scaler"> <img class="poster" src="https://vignette1.wikia.nocookie.net/logopedia/images/f/fc/Sky_Believe_in_better_logo.jpg/revision/latest?cb=20110910152552" alt="Sky" /> </div> </div></div>


Related Topics



Leave a reply



Submit