Question

Question:

Is it even possible to do two different transforms on an element and have them transition at different speeds?

Example without transforms (Fiddle):

div {
  width: 100px;
  height: 100px;
  background: red;
  transition: width 1s linear, height 2s linear;
}

div:hover {
  width: 200px;
  height: 400px;
}

Notice how it takes 1 second for the width to expand to 200px, and 2 seconds for the height to expand to 400px.

Example with transforms (Fiddle):

div {
  width: 100px;
  height: 100px;
  background: red;
  transition: transform 1s linear, transform 2s linear;
}

div:hover {
  transform: scale(1.5);
  transform: rotate(45deg);
}

Notice how it only performs the second transform. How can you specify which transform to perform for the transition? Is this an oversight in the design of CSS transforms? How can I go about accomplishing this?

Was it helpful?

Solution

Don't think you can do it the way you are attempting. Possible solutions would be a wrapper object

eg

Multiple transitions

sample fiddle here

sample code (HTML)

<div class="wrap">
<div class="inner"></div>
</div>

and CSS

.wrap {
    width: 100px;
    height: 100px;
    transition: transform 1s linear;
}
.inner {
    width: 100%;
    height: 100%;
    background: red;
    transition: transform 2s linear;
}
.wrap:hover {
    transform: scale(1.5);
}
.wrap:hover .inner {
    transform: rotate(45deg);
}

or use animations and keyframes as mentioned in answer by @slynagh

Just out of note, the transform property doesn't seem to work when used in transition on chrome (i.m on V33), but it works fine on IE11, thats all I have tested this on

OTHER TIPS

You could try to use animations.

div {
  width: 100px;
  height: 100px;
  background: red;
}

div:hover {
  -webkit-animation: anim1 2s linear;
}

@-webkit-keyframes anim1{
  0% { -webkit-transform: scale(1) rotate(0deg); }
  50% {-webkit-transform: scale(1.5) rotate(22.5deg); }  
  100% { -webkit-transform: scale(1.5) rotate(45deg); }
}

You would need to also set up the reverse for that hover out effect.

Unfortunately you have not stumbled on a bug in CSS implementation.

On :hover the second transform statement is simply overwriting the first one, this is CSS core. And the same applies to transforming the same parameter twice - rules defined later in the CSS or based on selector weight take precedence.

This would work:

div {
  width: 100px;
  height: 100px;
  background: red;
  transition: transform 1s linear;
}

div:hover {
  transform: scale(1.5) rotate(45deg);
}

But for your desired different length transforms the route suggested by @OJay - transform one of the parameters on a wrapper - is a good way.

As suggested by @slynagh will not work as expected as animations/transformations on a single element are performed linearly.

But we can make @OJay sample even neater without any additional elements:

div {
    width: 100px;
    height: 100px;
    position: relative;
    transition: transform 1s linear;
}
div:before {
    content: '';
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background: red;
    transition: transform 2s linear;
}
div:hover {
    transform: scale(1.5);
}
div:hover:after {
    transform: rotate(45deg);
}

Though being able to use a pseudo element depends on the content of your div.

Do take note, that you are missing browser specific prefixes and this is not cross browser proof.

The accepted answer suggests using a wrapper element, but you can achieve this effect most elegantly by simply deploying an animation rather than a transiton.

N.B. It is crucial to use animation-fill-mode: forwards; (or the shorthand equivalent) in order that when the animation completes it does not revert back to the start values.

Working Example:

:root {
  display: flex;
  justify-content: center;
  align-items: center;
  height: 100%;
}

div {
  width: 60px;
  height: 60px;
  background: red;
}

div:hover {
  animation: scaleRotate 2s linear forwards;
}

@keyframes scaleRotate {

   0% {transform: scale(1) rotate(0deg);}
  50% {transform: scale(1.5) rotate(22.5deg);}
 100% {transform: scale(1.5) rotate(45deg);}
<div></div>

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top