csstransformscalecss-transitions

css3: two transitions with different timing functions (css3)


I want to use a transform for both scale and translateX, but each with a different timing function. Currently I have it working with absolute positioning instead of translateX, as follows:

transition: transform 500ms cubic-bezier(0.390, -0.600, 1.000, -0.600), 
            left 500ms cubic-bezier(0.270, 0.875, 0.575, 0.870);

.

left: -50px ;
transform: scale(2,2) ;

How would you rewrite this to achieve the same, but use translateX instead of left ?


Solution

  • live CodePen demo

    2020s solution

    CSS has changed and we now have individual transform properties:

    .el {
      margin: 3em auto;
      width: 10em;
      aspect-ratio: 2;
      background: lightblue;
      transition: 
            translate .5s cubic-bezier(.27, .875, .575, .87), 
            scale .5s cubic-bezier(.39, -.6, 1, -.6);
        
        &:hover {
            scale: 2;
            translate: -6em
        }
    }
    <div class='el'></div>

    Note that applying the scaling on a wrapper and the translation on the element inside as in the 2013 solution meant the scaling was applied first, so it was also scaling the translation distance.

    With individual transform properties, translation is applied first, so we need to double it in order to get the same result as when using the reverse order.

    2013 solution, preserved for web history reasons

    In this case, I would probably use a wrapper and transition one of the two transforms for the wrapper and the other one for the element itself.

    HTML:

    <div class='wrap'>
      <div class='el'></div>
    </div>
    

    Relevant CSS:

    .wrap {
      transition: transform .5s cubic-bezier(.39, -.6, 1, -.6);
    }
    .el {
      transition: transform .5s cubic-bezier(.27, .875, .575, .87);
    }
    .wrap:hover { transform: scale(2,2); }
    .wrap:hover .el { transform: translateX(-50px); }
    

    .wrap {
      margin: 3em auto;
      width: 10em; height: 5em;
      transition: transform .5s cubic-bezier(.39, -.6, 1, -.6);
    }
    
    .el {
      height: inherit;
      background: lightblue;
      transition: transform .5s cubic-bezier(.27, .875, .575, .87);
    }
    
    .wrap:hover { transform: scale(2); }
    .wrap:hover .el { transform: translateX(-50px); }
    <div class='wrap'>
        <div class='el'></div>
    </div>

    Not sure it's a better idea than simulating a translateX by using left.

    Another idea would be not to use a transition, but an animation and set the keyframes such that to obtain the desired effect.