60 FPS
Web Applications
Hello!
My name is Alex Bardanov.
I'm a front-end developer in GlobalLogic Ukraine.
GitHub: dnbard
Skype: dnbard
Contents
- What is 60 fps and why they are so important ?
- Imperative and Declarative animations.
- What browser are doing between frames?
- Layers
- Benchmark first, test later
What is 60 fps ?
I heard that 24 frames per second are enough!
24 fps / 41.67 ms
60 fps / 16.67 ms
up to
84 fps / 11.9 ms
60 frames per second
only 16.67ms to prepare
next frame to paint
Imperative vs Declarative Animations
Imperative Animations
( javascript )
- using JavaScript
- using the Browser's main thread (which is already busy with other JavaScript, style calculations, layout and painting)
- animating in JavaScript does give you a lot of control: starting, pausing, reversing, interrupting and cancelling are trivial
Imperative Animations: requestAnimationFrame
- requestAnimationFrame should be used instead of setTimeout, setInterval
- it will run the callback in sync with refresh rate of your display (usually 60fps)
- decouple animations from scroll, resize, mouse and keyboard events(don't change anything in event handler; redraw all changes in requestAnimationFrame callback)
- parameter passed into the callback function is a high resolution timestamp
Declarative Animations
( transitions and animations in CSS )
- browser can optimize CSS animations
- additional layers are going to be created
- some actions are going to be executed off main thread
- lack the expressive power of JavaScript animations
- very hard to combine properly with Imperative animations
What browser are doing between frames?
Pixel Conveyor
16.66 ms
Pixel Conveyor - JavaScript
- Imperative Animations
- Any changes that are done with help of JavaScript (data sorting, adding elements to the page, element's class name changes etc)
Pixel Conveyor - Style
- Declarative Animations
- Applying styles to elements according CSS selector rules
Pixel Conveyor - Layout
- Calculated size and position of element
- Size and position could affect layout of child elements so layout of these elements could be changed as well
Pixel Conveyor - Paint
- Pixels are going to have own colors at this point
- Next core elements are affected:
- text (font, color, style etc)
- background (color)
- images
- borders
- shadows
- any other visual elements
- Paint can be done on several Layers
Pixel Conveyor - Composite
- Layers are drawn in different position with correct order
Example: Full Cycle
If you would change any property that would involve any change in Layout (geometry, width, height, positioning) then full cycle of Pixel Conveyor would be involved.
Example: Full Cycle
Styles that affects Layout:
width height
padding margin
display border-width
border top
position font-size
float text-align
overflow-y font-weight
overflow left
font-family line-height
vertical-align right
clear white-space
bottom min-height
Example: Paint & Compose
Changing an element may also trigger painting. Depending on how the elements in your app are grouped into layers, other elements besides the one that changed may also need to be painted.
color border-style
visibility background
text-decoration background-image
background-position background-repeat
outline-color outline
outline-style border-radius
outline-width box-shadow
background-size
Example: Composite Only
4 things that Browser can animate fast:
Position - transform: translate(x, y);
Scale - transform: scale(n);
Rotation - transform: rotation(deg);
Opacity - 0...1;
Paint vs Composite
Guidelines for animation:
- Use CSS keyframe animation or CSS transitions, if at all possible
- Use requestAnimationFrame if needs to be it’s JavaScript-based animation. Avoid setTimeout & setInterval
- Avoid changing inline styles on every frame if you can, declarative animations in CSS can be optimized by the browser
- Using 2D transforms instead of absolute positioning will provide better FPS
TL;DR:
Only transform & opacity;
never top & left!
Layers
Layers
transform: translateZ(0);
Hack to create a new layer.
New Layer is created if element:
- is <svg /> or <input />
- display isn't inline or inline-block
- height isn't percentage, implicit or auto
- overflow equal to scroll, auto, hidden
- not descendant of <table />
- position equal to absolute, relative, fixed
Layout trashing
Layout Thrashing occurs when JavaScript writes, then reads, from the DOM, multiple times causing document reflows.
// Read
var h1 = element1.clientHeight;
// Write (invalidates layout)
element1.style.height = (h1 * 2) + 'px';
// Read (triggers layout)
var h2 = element2.clientHeight;
// Write (invalidates layout)
element2.style.height = (h2 * 2) + 'px';
// Read (triggers layout)
var h3 = element3.clientHeight;
// Write (invalidates layout)
element3.style.height = (h3 * 2) + 'px';
Layout trashing: quick fix
// Read
var h1 = element1.clientHeight;
var h2 = element2.clientHeight;
var h3 = element3.clientHeight;
// Write (invalidates layout)
element1.style.height = (h1 * 2) + 'px';
element2.style.height = (h2 * 2) + 'px';
element3.style.height = (h3 * 2) + 'px';
// Document reflows at end of frame
Solution for bigger project
var h1 = element1.clientHeight;
// Write
requestAnimationFrame(function() {
element1.style.height = (h1 * 2) + 'px';
});
// Read
var h2 = element2.clientHeight;
// Write
requestAnimationFrame(function() {
element2.style.height = (h2 * 2) + 'px';
});
Use requestAnimationFrame!
Solution for bigger project
Benchmark first, fix later
Benchmark first, fix later
Benchmark first, fix later
Canvas? WebGL?
Yes!
Update
Rendering
Update
Update and rendering cycles
requestAnimationFrame
Images
Combine similar images into the texture.
This are going to improve performance, loading time and memory consumption.
Pre-load all assets (images, fonts etc) before usage.
Shaders
Shaders
Explore WebGL shaders @ https://www.shadertoy.com/
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
vec2 uv = fragCoord.xy / iResolution.xy;
fragColor = vec4(uv,0.5+0.5*sin(iGlobalTime),1.0);
}
Or learn them @ https://aerotwist.com/tutorials/an-introduction-to-shaders-part-1/
Thanks!
60 FPS
By Alex Bardanov
60 FPS
- 1,251