Reputation: 90
After reading an article on CSS animations and how to build them, I have built my own, and I am trying to increase the performance of my CSS animation. My animation consists of three HTML elements that change widths to indicate media is playing.
Upon checking the timeline and resource tab in Chrome dev tools, I saw that the animation causes a high CPU load.
How could I convert the animation to GPU hardware acceleration instead of the browser renderer, which causes a high CPU load? I have read that you can use hardware acceleration that forces the animation to run on GPU.
Is there a way to convert this (animating the width of the bar) to a GPU layer instead? Can I translate it somehow? or is there something better?
There are 3 bars. This is the animation for it, not the styling.
@keyframes music {
0% { width:17px; }
10% { width:11px; }
20% { width:37px; }
30% { width:30px; }
40% { width:15px; }
50% { width:10px; }
60% { width:24px; }
70% { width:17px; }
80% { width:21px; }
90% { width:32px; }
100% { width:17px; }
}
.lines-ani {
transform: rotateY(180deg);
}
.lines-ani .lines {
animation: music 1.5s 2s ease-out alternate infinite;
}
.lines-ani .lines:before {
animation: music 1.5s 1.5s ease-out alternate infinite;
}
.lines-ani .lines:after {
animation: music 1.5s 2.5s ease-out alternate infinite;
}
Upvotes: 3
Views: 3350
Reputation: 89780
If you want to avoid repainting and move the animation to GPU then you could use 3D transforms to produce the effect instead of animating the width
. As mentioned in this article, using 3D transforms mean that the browser would make the animation GPU accelerated.
CSS animations, transforms and transitions are not automatically GPU accelerated, and instead execute from the browser’s slower software rendering engine. So what exactly forces the browser to swap to GPU mode? Many browsers provide GPU acceleration by means of certain CSS rules.
Currently, browsers like Chrome, FireFox, Safari, IE9+ and the latest version of Opera all ship with hardware acceleration; they only use it when they have an indication that a DOM element would benefit from it. With CSS, the strongest indication is that a 3D transformation is being applied to an element.
Converting the animation into its 3D transform equivalent itself is not a big process. All that is needed is to set a initial width
on all the three elements and convert the width
within the @keyframes
rules into their corresponding ratio value based on the initial width that is set.
A width animation is generally just a scaleX
but scale3d
is used since we need the animation to be moved to the GPU. Since scale3d
takes 3 parameters (for scale in each of the three axes), we can provide 1 (initial scale) as the value for the other two axes. So, it would be scale3d(x ratio, 1, 1)
.
For example, the 10%
frame provided in question has width: 11px
setting and here is how we can get its equivalent scale3d
value:
width
on the element. In the below snippet, I have set it as 17px.scale3d(0.64, 1, 1)
. @keyframes color-bar {
0% {
transform: scale3d(1,1,1);
}
10% {
transform: scale3d(0.64,1,1);
}
20% {
transform: scale3d(2.17,1,1);
}
30% {
transform: scale3d(1.76,1,1);
}
40% {
transform: scale3d(0.88,1,1);
}
50% {
transform: scale3d(0.58,1,1);
}
60% {
transform: scale3d(1.41,1,1);
}
70% {
transform: scale3d(1,1,1);
}
80% {
transform: scale3d(1.23,1,1);
}
90% {
transform: scale3d(1.88,1,1);
}
100% {
transform: scale3d(1,1,1);
}
}
.lines-ani {
width: 25vw;
transform: rotateY(180deg);
}
.lines-ani .lines {
position: relative;
width: 17px;
height: 10px;
background: red;
transform-origin: left;
animation: color-bar 1.5s 2s ease-out alternate infinite;
}
.lines-ani .lines:before {
position: absolute;
content: '';
top: 125%;
height: 100%;
width: 100%;
background: green;
transform-origin: left;
animation: color-bar 1.5s 1.5s ease-out alternate infinite;
}
.lines-ani .lines:after {
position: absolute;
content: '';
top: 250%;
height: 100%;
width: 100%;
background: green;
transform-origin: left;
animation: color-bar 1.5s 2.5s ease-out alternate infinite;
}
<div class='lines-ani'>
<div class='lines'>
</div>
</div>
Note: If you don't wish to use scale3d
you could make use of scaleX() translateZ(0)
also. The translateZ(0)
is a 3D transform and the whole thing will still produce the same effect.
Upvotes: 4