Animate transform and opacity only
GoByte Skills #20: animate transform and opacity, not top or width. Traced in Chrome: 57 layouts for left, 1 for x, same move. Plus why GSAP still freezes when your main thread does.
Arthur is one of GoByte's characters. This post was drafted by AI agents in Arthur's voice, then fact checked, run and edited by the GoByte team.
Transform and opacity skip layout, and almost all paint, so they stay smooth, while width and top force the browser to recompute the page.
Transcript
Two boxes cover the same distance at the same pace: the left box reruns layout and paint on every frame and its counters climb to 57 and 114, while the transform box runs layout once and then only composites.
The pipeline#
A frame can run four stages: style, layout (compute the geometry of every affected box), paint (record drawing commands), composite (stack painted layers on the GPU). width, top and left change geometry, so layout reruns and what it moved is repainted. transform and opacity change no geometry: the painted pixels are reused, only moved or faded.
const box = document.querySelector(".box");
// run each line alone: same trip, same time
gsap.to(box, { left: 300, duration: 1 });
gsap.to(box, { x: 300, duration: 1 });
left and top only move a positioned element, so the box needs position: relative (or absolute). GSAP's x writes transform: translate3d(...) while it runs, and offsetLeft never changes.
Measured, not folklore#
I traced each line in Chrome 154, on a page with 3,000 paragraphs wrapping around the box:
tween frames Layout Paint
left: 300 60 57 114
x: 300 60 1 3
opacity: .2 60 1 2
width matched left. On a fast machine every tween still drew 60 frames (61 on some runs), so the count is the honest number. Layout cost grows with how much of the page depends on that box, and it shares the main thread's 16.7 ms frame budget (at 60 Hz) with your JavaScript. That is where the stutter comes from.
The boundary#
- A transform does not move the neighbors. The box keeps its layout slot. If siblings must reflow, run layout once, then animate the difference as a transform (the FLIP technique).
- GSAP itself runs on the main thread. I blocked it for one second with a busy loop: a
box.animate()(Web Animations API) transform kept drawing, 60 frames, while the GSAP tween drew 0 to 2. Compositor friendly means cheap per frame, not immune to your long tasks. opacityabove 1 is clamped, so an overshooting ease on a fade does nothing past the top.
Rule of thumb#
Animate how things look, never where they are. Tweening top asks the city planner to redraw the map every time you take a step.
Your product here? Partner with us
Back to topDiscussion
No comments yet. Signed in GoByte members with a verified e-mail can join. Community guidelines
Reading is open to everyone. Commenting and voting need a GoByte account with a verified e-mail.