<main>
<h1>Performant Shadow Animation</h1>
<p>
This is a comparsion of animating:
<ul>
<li><code>box-shadow</code>,</li>
<li>the <code>opacity</code> of an <code>::after</code> pseudo-element which has a bigger box shadow,</li>
<li>and <code>filter:drop-shadow()</code></li>
</ul>
</p>
<div class="img-container">
<img src="https://cdn.imgpaste.net/2021/01/17/jKprq.png" alt="perf comparsion different properties" />
</div>
<p>
The image above summarises the findings for a low end mobile device. The green striped bars indicate that activity is off the main thread for the pseudo-element and <code>drop-shadow()</code> animations, which accounts for the major difference in performance.</p>
<p>The smoothest animation is the pseudo-element. The most efficient is
<code>drop-shadow()</code> (least amount of painting/rendering time). The best overall choice is the pseudo-element.
</p>
<p>You check out examples of each method below.</p>
<h2>Hover animation with <code>box-shadow</code></h2>
<div class="container">
<div class="box boxShadow"></div>
<div class="box boxShadow"></div>
</div>
<pre><code class="language-css">:root {
--intial-state: 0 2px 2px rgba(0, 0, 0, 0.2);
--final-state: 0 5px 15px rgba(0, 0, 0, 0.4);
}
.boxShadow {
box-shadow: var(--intial-state);
transition: all 0.3s cubic-bezier(0.165, 0.84, 0.44, 1);
}
.boxShadow:hover {
box-shadow: var(--final-state);
}</code></pre>
<h2>Hover animation with <code>::after</code> pseudo-element</h2>
<div class="container">
<div class="box pseudo"></div>
<div class="box pseudo"></div>
</div>
<pre><code class="language-css">:root {
--intial-state: 0 2px 2px rgba(0, 0, 0, 0.2);
--final-state: 0 5px 15px rgba(0, 0, 0, 0.4);
}
.pseudo {
box-shadow: var(--intial-state);
}
.pseudo::after {
content: "";
border-radius: 5px;
position: absolute;
z-index: 1;
top: 0;
left: 0;
width: 100%;
height: 100%;
box-shadow: var(--final-state);
opacity: 0;
transition: opacity 0.3s cubic-bezier(0.165, 0.84, 0.44, 1);
}
.pseudo:hover::after {
opacity: 1;
}
</code></pre>
<h2>Hover animation with <code>drop-shadow()</code></h2>
<div class="container">
<div class="box dropShadow"></div>
<div class="box dropShadow"></div>
</div>
<pre><code class="language-css">:root {
--intial-state: 0 2px 2px rgba(0, 0, 0, 0.2);
--final-state: 0 5px 15px rgba(0, 0, 0, 0.4);
}
.dropShadow {
filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.1));
transition: all 0.3s cubic-bezier(0.165, 0.84, 0.44, 1);
}
.dropShadow:hover {
filter: drop-shadow(0 5px 15px rgba(0, 0, 0, 0.3));
}
</code></pre>
</main>
:root {
--intial-state: 0 2px 2px rgba(0, 0, 0, 0.2);
--final-state: 0 5px 15px rgba(0, 0, 0, 0.4);
}
.container {
display: flex;
justify-content: center;
}
.box {
position: relative;
display: inline-block;
width: 100px;
height: 100px;
background-color: rgb(56, 159, 255);
border-radius: 5px;
margin: 0 20px;
}
.boxShadow {
box-shadow: var(--intial-state);
transition: all 0.3s cubic-bezier(0.165, 0.84, 0.44, 1);
}
.boxShadow:hover {
box-shadow: var(--final-state);
}
.pseudo {
box-shadow: var(--intial-state);
}
.pseudo::after {
content: "";
border-radius: 5px;
position: absolute;
z-index: 1;
top: 0;
left: 0;
width: 100%;
height: 100%;
box-shadow: var(--final-state);
opacity: 0;
transition: opacity 0.3s cubic-bezier(0.165, 0.84, 0.44, 1);
}
.pseudo:hover::after {
opacity: 1;
}
.dropShadow {
filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.1));
transition: all 0.3s cubic-bezier(0.165, 0.84, 0.44, 1);
}
.dropShadow:hover {
filter: drop-shadow(0 5px 15px rgba(0, 0, 0, 0.3));
}
h1,
h2 {
text-align: center;
}
main {
width: calc(100% - 10px);
margin: 0 auto;
max-width: 1200px;
font-size: calc(1rem + 0.25vw);
font-family: Roboto, Georgia, Times, serif;
}
.img-container {
overflow-x: scroll;
}
img {
display: block;
width: 1159px;
}