Creating a smoother CSS zoom effect

A zoom effect can be created with the transform and transition CSS properties. I have been using this on a project and was not entirely happy with the result. For the project I created a grid with articles that become larger if you move the mouse over the article. The article contains an image and text. During the zooming the article gets blurry. This is very noticeable with text. Also the effect is not always very smooth, especially if you have more than a couple of article elements.

Below is a code example for the zoom effect:

<style>
article {
  transition: all 300ms;
}
article:hover {
  transform: scale(1.08);
}
</style>

<article>
  <div class="image"><img src="thumbnail.jpg" alt=""></div>
  <div class="content"><a href="/link/to/article">Title</a></div>
</article>

By scaling image and text the browser has to do a lot of work, especially if it is also doing a transition. So I figured faking the zoom effect would perform better.

My idea was not to scale anything. This way the browser has to do less work. I added a border on top of the article with an :after pseudo-element. On mouse over I can animate the border width, creating the illusion that the article becomes larger. This worked quite well, but wasn’t entirely smooth. I suspect that this is happening because border is part of the CSS box model.

Below is the CSS code of the zoom effect with the border property:

<style>
article {
  position: relative;
}
article:after {
  border: 10px solid #fff;
  bottom: 0;
  content: "";
  left: 0;
  position: absolute;
  right: 0;
  top: 0;
  transition: all 300ms;
}
article:hover:after {
  border-width: 0;
}
</style>

So next, I tried box-shadow. This CSS property offers an inset value, that puts a shadow inside an element. And by setting the blur radius to 0, you create an hard edge like with border. The spread radius can then be used to create a border. This turned out to animate nicely. For Internet Explorer and Edge browsers I had to use -1px for the article:after positions to always cover the edges.

Below is the CSS code of the zoom effect with the box-shadow property:

<style>
article {
  position: relative;
}
article:after {
  bottom: -1px;
  box-shadow: inset 0 0 0 10px #fff; 
  content: "";
  left: -1px;
  position: absolute;
  right: -1px;
  top: -1px;
  transition: all 300ms;
}
article:hover:after {
  box-shadow: inset 0 0 0 0 #fff;
}
</style>

[Update] Another option is clip-path, but it doesn’t work in Internet Explorer or Edge.

<style>
article {
  clip-path: inset(10px);
  transition: all 300ms;
}
article:hover {
  clip-path: inset(0);
}
</style>

You can try the 4 different solutions in my zoom effect demo.

To support older browsers, you might want to put the CSS code through the autoprefixer.

I am pretty pleased with the result. It reminds me, that achieving an effect does not need to be technically correct, to be convincing to the eye.