Introduction

I wrote about making a small CSS animation for a left to right transition, but it turns out it's a pretty bad way of doing things. So! Live and learn! It turns out that when you animate the left position of an element (for instance) some problems come up.

  • It doesn't allow for the will-change property
  • You end up re-rendering the whole page
  • You can't push the animation off to the GPU

The better way is to use CSS transforms.

Transformers!

According to MDN

The transform CSS property lets you rotate, scale, skew, or translate an element. It modifies the coordinate space of the CSS visual formatting model.

In this particular case, the goal was to make the blue box appear to shrink to reveal a red background.

Translate

I tried transform: translateX which produced a cool effect, but not the one the designers asked for. It moved the entire blue area from left to right. When I transitioned the opacity I ended up liking it a lot. If you like, you can see it here.

Scale

Instead, the transform required is scale. When used by itself, it scales both the X and Y (and possibly even Z) axes of the item. It takes numbers such as

  • scale(0)
  • scale(0.5)
  • scale(4) etc...

This makes it perfect for combining with the transition property. Even better is that you can specify that only the X (or Y) axis gets the transformation by using scaleX.

In this case, I ended up switching which element was going to change from the previous example and how the z-index is applied.

a:before,
a:after {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
}

a:before {
  background-color: #000e2f;
  z-index: -2;
}

a:after {
  background-color: red;
  z-index: -1;
  transform-origin: left;
  transform: scaleX(0);
  transition: transform 0.3s ease-in-out;
}

This puts the red "background" in front of the blue background while the text stays in front of both. The :after selector has transform: scaleX(0) which effectively gives it no size even though it's positioned to take up the full size of the element. At the same time it has the transition property applied to prepare the elements to move.

On hover or focus the :after element gets

a:hover:after,
a:focus:after {
  transform: scalex(1);
  will-change: transform;
}

This will make the element appear to grow or shrink over 0.3 seconds. The will-change property makes sure that the animation is pushed off to the GPU and that it doesn't effect the whole page.

Conclusion

All in all, this is a much better way of handling the animation. It's much more efficient and appears significantly smoother than the previous approach.