Make your animations perform well
Pablo Castro - @castrinho18
Based on an
Anna Migas
talk
castrinho8.github.io/animations-performance
Index
- Intro web rendering
- Layers
- FLIP
- Animation frame
- Tools
Web animations CSS vs JS
CSS -> performance
JS -> control
1. How a browser paints a website?
- GET request
- HTML parsing and DOM creation
- Styles are applied
- Layout calculation
- Everything is painted
- Layers composition
Any change on a page
- Javascript
- Recalculate Styles
- Layout
- Paint
- Layers composition
(width, margin, left...)
- Javascript
- Recalculate Styles
- Layout
- Paint
- Layers composition
(background-color, shadows...)
- Javascript
- Recalculate Styles
- Layout
- Paint
- Layers composition
(opacity, transform)
- Javascript
- Recalculate Styles
- Layout
- Paint
- Layers composition
csstriggers.com
2. Optimizations with layers
@keyframes rotate {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
.rotate-button {
border: 2px solid black;
animation: rotate 2s infinite;
}
@keyframes rotate {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
.rotate-button {
border: 2px solid black;
}
.rotate-button:hover {
animation: rotate 2s infinite;
}
will-change: transform
will-change
- Every layer consumes memory
- You can use event listeners to remove it when animation finish
- Use it if animation happens a lot
- IE/Edge doesn't support it
3. FLIP: First, Last, Invert, Play
100ms gap to start interactions
Use this time to calculate animations
Typical solution
.element {
position: absolute;
left: -200px;
}
.element.active {
transform: translateX(200px);
}
Good solution
.element {
position: absolute;
transform: translateX(-200px);
transition: transform 1s;
}
.element.active {
transform: none;
}
1 frame == 16ms*
- Javascript
- Recalculate Styles
- Javascript
- Layout
- Paint
- Layers composition
* (1s == 1000ms)/60fps = 16ms
var start = null;
var element = document.getElementById('SomeElementYouWantToAnimate');
element.style.position = 'absolute';
function step(timestamp) {
if (!start) start = timestamp;
var progress = timestamp - start;
element.style.left = Math.min(progress / 10, 200) + 'px';
if (progress < 2000) {
window.requestAnimationFrame(step);
}
}
window.requestAnimationFrame(step);
requestAnimationFrame()
- Need vendor prefixes
- Polyfill for older browsers
- Not needed in WAAPI, GSAP, jQuery 3+
- Animations in inactive tabs will stop
- Better than setInterval
Summary
- Less animations
- Animate only transform/opacity
- Use will-change (carefully) and requestAnimationFrame
- Don't overuse layers
- Animate elements on top layers
thanks!
@castrinho18 | Pablo Castro
pablo.castro@mobgen.com