Command Palette

Search for a command to run...

Hectal
Shots in this scene
SHOT 1.1Beginner ~20 min · shot 1 of 6

Frames and the Flipbook

In one line

A screen never shows motion. It shows still pictures, one after another, so fast that your eye joins them up. How many pictures there are each second, and how long the browser has to make each one, decides whether motion looks smooth or jerky.

0/6 · 0%

Think of it like this

Draw a stick figure in the corner of every page of a notebook, with the arm a little higher on each page. Flick the pages with your thumb and the arm seems to wave. Nothing on any page moves. Your eye and brain join the pictures up. A screen is a flipbook that flips itself, many times a second.

Words you'll meet

New words in this topic, in plain English. Come back here whenever one feels fuzzy.

frame
One complete picture of the page, made by the browser and shown on the screen.
fps (frames per second)
How many frames the browser makes each second.
refresh rate (Hz)
How many times per second the screen can show a new picture. 60 Hz is 60 times a second.
frame budget
The time one frame may take: 1000 ms divided by the refresh rate (16.7 ms at 60 Hz, 8.3 ms at 120 Hz).
dropped frame
A frame that was not ready in time, so the screen showed the previous picture again.
jank
The visible stutter that dropped or uneven frames cause.
motion blur
The smear a camera records on a moving object. It hides the gaps between frames. Browser frames have none.

Step by step

01Play the flipbook

In "The flipbook" below press Play the flipbook. Four dots make the same 200 px move in 1 second. The label shows how many still pictures each one is cut into: 6, 12, 30 and 60. The top dot is clearly stepping. The bottom one looks smooth.

02Pause and step

Press Pause, then Play the flipbook, then press Step once. One step is one 60 Hz frame (16.7 ms). Click the 6-frame dot's track in the timeline: its details say the easing is steps(6). Keep pressing Step and watch which dots moved on each press.

03Find the jumps

Slow the page to 0.1× and press Play. The 6-frame dot waits, jumps, waits, jumps. It holds still for almost 167 ms between jumps. That wait is what your eye reads as stepping. Moving a dot 200 px in six jumps leaves 33 px gaps. In sixty jumps the gaps are 3 px.

04Read the frame budget

"The frame budget" below prints the budget for common refresh rates, and what one slow frame costs on a 60 Hz screen. It prints text only: nothing on the page moves. The table at the bottom is the dropped-frame rule in numbers.

Try it yourself

  1. 1

    Step to 200 ms and compare the rows

    In "The flipbook" press Pause, then Play the flipbook, then press Step 12 times (12 × 16.7 ms is 200 ms). Measured: the 6-frame dot has made one jump and sits 33.3 px along. The 30-frame dot has made six small jumps and sits 40 px along. Both started together and cover the same distance in 1 second. The one with more pictures is further along between the big jumps.

  2. 2

    Add a 120-picture row

    Copy the last row in the HTML and change its --n: 60 to --n: 120. Press Pause, Play the flipbook, and step to the 3rd and the 6th frame (50 ms and 100 ms). Measured: both the 60-picture and the 120-picture dot are at exactly 10 px, then 20 px. A 60 Hz screen only looks at the page at those instants, so the extra pictures are never shown. On a 120 Hz screen they would be.

  3. 3

    Print another refresh rate

    In "The frame budget" add 240 to the first list. The console gains 240 Hz -> 4.2 ms per frame. A 240 Hz screen leaves a quarter of the time a 60 Hz screen does.

Code & diagrams

The flipbook

The same move, cut into 6, 12, 30 and 60 pictures with the CSS `steps()` timing function (it makes the move jump from picture to picture instead of gliding). A real 60 Hz screen cannot show more than 60 different pictures in a second, so the bottom row is as smooth as this move gets at 60 Hz.

Press Run to see the page.
00:00.000
animations
0.00s0.10s0.20s0.30s0.40s0.50s0.60s0.70s0.80s0.90s

Nothing is moving yet. Hover, click or scroll the page: every animation it starts shows up here as a track.

frames

Console

Nothing logged yet.
The frame budget

The first list is 1000 divided by the refresh rate. The second list is a model of a 60 Hz screen: if the work takes longer than 16.7 ms, the screen shows the old frame again for each refresh it missed.

Press Run to see the page.
00:00.000
animations
0.00s0.10s0.20s0.30s0.40s0.50s0.60s0.70s0.80s0.90s

Nothing is moving yet. Hover, click or scroll the page: every animation it starts shows up here as a track.

frames

Console

Nothing logged yet.

Expected console output

24 Hz -> 41.7 ms per frame
30 Hz -> 33.3 ms per frame
60 Hz -> 16.7 ms per frame
90 Hz -> 11.1 ms per frame
120 Hz -> 8.3 ms per frame
144 Hz -> 6.9 ms per frame
--- work per frame on a 60 Hz screen ---
4 ms of work -> new picture on refresh 1, old picture repeated 0 time(s)
16 ms of work -> new picture on refresh 1, old picture repeated 0 time(s)
17 ms of work -> new picture on refresh 2, old picture repeated 1 time(s)
34 ms of work -> new picture on refresh 3, old picture repeated 2 time(s)
48 ms of work -> new picture on refresh 3, old picture repeated 2 time(s)
120 ms of work -> new picture on refresh 8, old picture repeated 7 time(s)

Break it on purpose

Errors are the best teachers. Make each change, read the error, guess what went wrong, then reveal the answer.

Break #1

Ask for zero steps

In "The flipbook", change steps(var(--n)) in the CSS to steps(0) and press Play the flipbook.

terminal
$ Press Play the flipbook and look at the timeline
── what you'll see ──
The dots jump to the end at once. The timeline shows no track, and the computed `transition-timing-function` is `ease`, not a steps value.
Measured with the page's clock frozen: the transform is already 200 px at 0 ms, and there were no animations.

Myth vs fact

Myth

The more frames per second, the better, always.

Fact

More frames help only if the browser can make each one in time. If the work needs 12 ms, a 120 Hz screen (budget 8.3 ms) shows a stutter that a 60 Hz screen would not. A steady rate that you can keep up with beats a high rate you sometimes miss.

Myth

My code has 16.7 ms per frame at 60 Hz.

Fact

That is the whole frame. The browser's own work (styles, layout, painting, sending the picture to the screen) comes out of it, so your JavaScript has noticeably less.

Pro corner

Extra depth for experienced readers. New to this? Skip it for now and come back later.

  • ▸

    Browsers align frames to the screen's refresh (the "vsync" signal). If a frame misses it, the next chance is one refresh later. That is why a slow frame costs whole multiples of the budget (2, 3, 8 refreshes in the table above), not a small overrun.

  • ▸

    Variable refresh screens change their rate while you use them: lower when nothing moves, higher while you scroll. Design for the budget at the highest rate your users have, and test the lowest.

Remember this

  1. 1

    The problem this solves: people say an animation is "smooth" or "jerky", but those are feelings, and you cannot fix a feeling. To fix motion you need numbers: how many pictures per second, and how many milliseconds the browser has to make each one. This topic gives you both.

  2. 2

    A frame is one complete picture of the page. The browser makes a new frame only when something changed (a transition is running, you scrolled, a script moved an element). Frames per second (fps) is how many frames it makes each second. Refresh rate, measured in hertz (Hz), is how many times per second the screen can show a new picture. A 60 Hz screen can show 60 frames a second. Many phones and laptops run at 90 or 120 Hz, and some gaming screens at 144 Hz or more.

  3. 3

    The frame budget is the time the browser has to finish one frame: 1000 ms divided by the refresh rate. At 60 Hz that is 16.7 ms. At 120 Hz it is 8.3 ms. All the work for the frame must fit inside it: your JavaScript, and the browser's own steps (Topic 1.4 lists them). The browser needs part of the budget for itself, so your code gets less than the full number.

  4. 4

    Why a film at 24 fps looks smooth but an interface at 24 fps does not. A film camera keeps its shutter open for a fraction of each frame, so a fast-moving object is recorded as a smear. That smear is motion blur, and it fills the gap between one picture and the next. A browser draws a sharp picture of one instant, with no smear. Your eye sees a crisp object at one position, then at another, and the motion looks like it is stepping. That is why web motion needs a higher frame rate than film.

  5. 5

    A dropped frame happens when the work for a frame is not finished before the screen refreshes. The screen cannot wait, so it shows the old picture again. On a 60 Hz screen a frame that takes 20 ms is not ready at 16.7 ms, so it appears at 33.3 ms. That one step lasted twice as long as the others, and moving things seem to stall for a moment. People call this jank. Uneven frames are easier to notice than a steady, lower rate.

  6. 6

    The frame rate you design for is not the one every user has. Your laptop may run at 60 Hz, a new phone at 120 Hz, and a device in power-saving mode, or a very busy one, at much less. Motion that works only at one rate is fragile. Topic 1.3 shows how to write motion that keeps its timing at any rate.

Explain it without notes

01

What is a frame budget, and how do you work it out for a 120 Hz screen?

02

Why does a 24 fps film look smooth when a 24 fps animated button does not?

Practice

01

What is the frame budget at 144 Hz, to one decimal place? If the browser needs 4 ms of it for its own work, how much is left for your JavaScript?

02

Write the CSS for a dot that moves 120 px in 800 ms in 8 jumps, like a flipbook of 8 pages.

Done when you can

  • You can say what a frame is and what refresh rate means

  • You can work out the frame budget for 60, 90, 120 and 144 Hz

  • You can explain a dropped frame and why it costs whole refreshes

  • You can say why interface motion needs more frames than film