user22431569
user22431569

Reputation:

How to make transform: scale work with transition and animation on hover?

I am trying to make hover scale work smoothly with animation scale. Hover works with #test but with .rotate I can't get it to work correctly. Also, why the hover scale doesn't work when the animation-fill-mode is forwards instead of none?

https://codepen.io/yoholil/pen/qBLbYYm

let flag = false;
let test = document.querySelector("#test")


test.addEventListener("click", function() {
  console.log(1);
  flag && test.classList.add("rotate");
  !flag && test.classList.remove("rotate");
  flag = !flag;
});
#test {
  width: 200px;
  transition: 0.3s ease;
  animation: rotateRight 0.3s ease-in-out none;
}

#test:hover {
  transform: scale(1.2);
}

#test.rotate {
  transform: scaleX(-1);
  animation: rotateLeft 0.3s ease-in-out none;
}

@keyframes rotateRight {
  0% {
    transform: scaleX(-1);
  }
  100% {
    transform: scaleX(1);
  }
}

@keyframes rotateLeft {
  0% {
    transform: scaleX(1);
  }
  100% {
    transform: scaleX(-1);
  }
}
<img id="test" src="https://upload.wikimedia.org/wikipedia/commons/thumb/e/ef/Stack_Overflow_icon.svg/768px-Stack_Overflow_icon.svg.png" />

Upvotes: 1

Views: 99

Answers (3)

Temani Afif
Temani Afif

Reputation: 273838

Use the new scale property along with the transform one.

Your code can be simplified like below

let test = document.querySelector("#test")

test.addEventListener("click", function() {
  test.classList.toggle("rotate");
});
#test {
  width: 200px;
  transition: 0.3s ease;
}

#test:hover {
  scale: 1.2;
}

#test.rotate {
  transform: scaleX(-1);
}
<img id="test" src="https://upload.wikimedia.org/wikipedia/commons/thumb/e/ef/Stack_Overflow_icon.svg/768px-Stack_Overflow_icon.svg.png" />

Upvotes: 0

imhvost
imhvost

Reputation: 10002

Just use a wrapper and apply :hover to it:

test.addEventListener('click', () => test.classList.toggle('rotate'));
#test {
  width: 200px;
  transition: transform .3s ease;
}

#test:hover {
  transform: scale(1.2);
}

#test img{
  animation: rotateRight .3s ease-in-out both;
  max-width: 100%;
}

#test.rotate img{
  animation: rotateLeft .3s ease-in-out both;
}

@keyframes rotateRight {
  0% {
    transform: scaleX(-1);
  }
  100% {
    transform: scaleX(1);
  }
}

@keyframes rotateLeft {
  0% {
    transform: scaleX(1);
  }
  100% {
    transform: scaleX(-1);
  }
}
<div id="test">
  <img src="https://upload.wikimedia.org/wikipedia/commons/thumb/e/ef/Stack_Overflow_icon.svg/768px-Stack_Overflow_icon.svg.png">
</div>

Upvotes: 0

Wongjn
Wongjn

Reputation: 24408

If you need the initial flip animation, then consider using a CSS variable that carries the scaling multiplier so that it works within the animation:

let flag = false;
let test = document.querySelector("#test")


test.addEventListener("click", function() {
  console.log(1);
  flag && test.classList.add("rotate");
  !flag && test.classList.remove("rotate");
  flag = !flag;
});
#test {
  transform: scale(var(--multiplier));
  width: 200px;
  transition: 0.3s ease;
  animation: rotateRight 0.3s ease-in-out none;
  --multiplier: 1;
}

#test:hover {
  --multiplier: 1.2;
}

#test.rotate {
  transform: scale(calc(-1 * var(--multiplier)), var(--multiplier));
  animation: rotateLeft 0.3s ease-in-out none;
}

@keyframes rotateRight {
  0% {
    transform: scale(calc(-1 * var(--multiplier)), var(--multiplier));
  }
  100% {
    transform: scale(var(--multiplier));
  }
}

@keyframes rotateLeft {
  0% {
    transform: scale(var(--multiplier));
  }
  100% {
    transform: scale(calc(-1 * var(--multiplier)), var(--multiplier));
  }
}
<img id="test" src="https://upload.wikimedia.org/wikipedia/commons/thumb/e/ef/Stack_Overflow_icon.svg/768px-Stack_Overflow_icon.svg.png" />

Otherwise, if you don't need the initial flip animation, consider removing the use of any animation altogether:

let flag = false;
let test = document.querySelector("#test")


test.addEventListener("click", function() {
  console.log(1);
  flag && test.classList.add("rotate");
  !flag && test.classList.remove("rotate");
  flag = !flag;
});
#test {
  transform: scale(var(--multiplier));
  width: 200px;
  transition: 0.3s ease;
  --multiplier: 1;
}

#test:hover {
  --multiplier: 1.2;
}

#test.rotate {
  transform: scale(calc(-1 * var(--multiplier)), var(--multiplier));
}
<img id="test" src="https://upload.wikimedia.org/wikipedia/commons/thumb/e/ef/Stack_Overflow_icon.svg/768px-Stack_Overflow_icon.svg.png" />


Additionally, the hover scale doesn't work when the animation-fill-mode is forwards instead of none because the transform property value in the @keyframes would take precedence over any of properties defined in the CSS rules.

Upvotes: 0

Related Questions