How to animate Box – Shadow with Silky smooth Performance

This article is not a literal translation, because I think this technique is very interesting and useful, so I started the article.

Box-shadow is used more and more in our work, and the animation that accompanies shadow is more or less a little bit. Suppose we have the following box:

div {
    width: 100px;
    height: 100px;
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
}
Copy the code

To hover, the box shadow moves from box-shadow: 0 2px 4px rgba(0, 0, 0, 0.3) to box-shadow: 0 5px 15px rgba(0, 0, 0, 0.3).

  • Box-shadow: 0 2px 4px rgba(0, 0, 0, 0.3) –> Box-shadow: 0 5px 15px rgba(0, 0, 0, 0.3)

OK, the easiest way is of course:

div:hover {
    width: 100px;
    box-shadow: 0 5px 15px rgba(0, 0, 0, 0.3);
}
Copy the code

Since the transition animation takes place in two different box shadows, the browser will constantly redraw the box shadows during the transition animation. And because shadows are a consumption style, the animation feels somewhat sluggish.

Here is a tip to optimize shadow animation in this case.

Optimize with pseudo-elements and transparency

To optimize with pseudo-elements and transparency, we add a before pseudo-element with the same size as the parent div, and give the element the desired final box shadow state in advance, but the transparency of the element is 0.

div {
    position: relative;
    width: 100px;
    height: 100px;
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
}

div::before {
    content: "";
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    box-shadow: 0 5px 15px rgba(0, 0, 0, 0.3);
    opacity: 0;
}
Copy the code

Then, with hover, we simply set the transparency of the pseudo-element from 0 to 1.

div:hover::before {
    opacity: 1;
}
Copy the code

The nice thing about this is that the actual shadow changes that are going on are just the opacity changes, rather than the constant repainting of the shadow, which effectively improves the smoothness of the shadow animation and makes it look silky.

Why is animating opacity better than box-shadow? Take a look at this table, which lists the effects of different attribute changes on page rearrangement and redrawing:

very few CSS properties

Finally, the Demo can look at:

CodePen Demo — Optimized box-shadow animation

There are problems with another scheme

The above scheme in the original text is not perfect, because the final effect is a superposition of two shadows, which may make the overall feeling of the shadow a little darker.

So we need to tweak the final state of the shadow, weaken the effect a little bit, try to make two shadow overlay effect is similar to a single shadow effect.

Of course, we can optimize the scheme again by using ::after pseudo-element, ::after pseudo-element set to initial state and transparency 1, ::before pseudo-element set to last state and transparency 0:

div {
    position: relative;
    width: 100px;
    height: 100px;
}

div::before {
    box-shadow: 0 5px 15px rgba(0, 0, 0, 0.3);
    opacity: 0;
}

div::after {
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
}
Copy the code

When actually hover, perform one show and one hide on two pseudo-elements, so that the final effect is only one shadow effect, no shadow overlay, which is the same as the effect of direct shadow transition change:

div:hover::before {
    opacity: 1;
}

div:hover::after {
    opacity: 0;
}
Copy the code

CodePen Demo — Optimized box-shadow animation

The last

Well, the end of this article, I hope to help you 🙂

More interesting CSS technology articles are summarized in my Github — iCSS, constantly updated, welcome to click on the star subscription favorites.