Animated Websites That Are Fast and Rich in Motion
Learn how to design interactive and animated websites that feel rich and cinematic without wrecking Core Web Vitals or driving away impatient visitors.
A single Lottie animation can add 400 KB to a page. Multiply that across a hero, a product tour, and a scroll-triggered feature section, and you are looking at two megabytes of motion before the first paragraph loads. The real challenge of designing interactive and animated websites is not learning the tools. It is knowing when the tools are costing you more than they earn.
Most performance problems with animated sites are not caused by animation itself. They are caused by animation that was never budgeted into the page’s total weight, never tested against real device constraints, and never questioned during design review. This article walks through the mechanisms that let you keep the motion and lose the lag.
Get a performance-focused design audit for your site’s animations and interactions.
Why animation hurts performance (and why it does not have to)
Browsers render frames at 60 fps on most displays, which gives you roughly 16 milliseconds per frame. Every animation that triggers layout recalculation or paint operations eats into that budget. The usual culprits: animating width, height, top, or left instead of transform and opacity. Animating properties that force the browser to reflow the document turns a smooth scroll into a janky stutter, especially on mid-range Android phones where the audience actually lives.
The GPU can handle transform and opacity changes almost for free. Compositing those layers happens on the graphics card, not the main thread. This single distinction separates sites that feel cinematic from sites that feel broken. Chrome DevTools will show you exactly which properties trigger layout, paint, or composite. Checking that panel before committing an animation to production is the minimum.
The other cost people miss is JavaScript execution. A scroll-linked parallax effect driven by a scroll event listener that fires hundreds of times per second will block the main thread. The fix: the Intersection Observer API for enter/exit triggers, and CSS scroll-timeline (now supported in Chromium browsers) for continuous scroll-driven motion. Both keep the work off the main thread entirely.
Set a performance budget before you open Figma
A performance budget is a hard limit on page weight, request count, and key metrics. Without one, every designer adds “just one more” animation until the Lighthouse score collapses. Here is a practical process:
This budget becomes a design constraint, not a development afterthought. When you scope a redesign, building the performance budget into the discovery phase prevents the painful conversation three weeks before launch where engineering asks design to cut half the animations.
Define your Largest Contentful Paint target:
Google’s threshold for a "good" LCP is 2.5 seconds. If your hero includes a full-screen video or complex Lottie, you need to account for its load time within that window.
Allocate a total transfer budget:
A reasonable target for a marketing page is 1.5 MB total transfer on first load. Decide upfront how much of that goes to motion assets versus images, fonts, and scripts.
Cap Cumulative Layout Shift at the source:
Reserve explicit dimensions for every animated container. A section that expands on scroll without a defined height will shift content below it and spike your CLS.
Test on a throttled connection:
Simulate a 4G connection (roughly 1.5 Mbps throughput, 150 ms round-trip) in DevTools. If the animation is not visible within five seconds on that connection, it is not earning its place.
Choosing the right animation technique for each job
Not all motion is created equal. The technique you pick determines both the visual ceiling and the performance floor.
CSS transitions and keyframes are the lightest option. They run on the compositor thread when you stick to transform and opacity. Use them for hover states, reveals, micro-interactions, and simple entrance animations. They cost essentially zero JavaScript and add no extra network requests.
Lottie and Rive handle complex, illustrative motion: character animations, product demos, explainer sequences. A Lottie file is a JSON description of an After Effects composition. It can be beautiful. It can also be 800 KB if the designer exports it without optimizing. Run every Lottie through LottieFiles optimization tools. Simplify paths, remove hidden layers, and set a maximum canvas size. Rive offers a binary format that is typically 5 to 10 times smaller than equivalent Lottie JSON, with runtime interactivity built in.
WebGL and Three.js are for immersive 3D scenes: product configurators, virtual environments, data visualizations that need to rotate in space. They are also the most expensive option. A Three.js scene initializes its own rendering pipeline, loads textures into GPU memory, and runs a continuous render loop. If you do not need actual 3D, you do not need WebGL. A CSS perspective transform faking depth will look almost identical and cost almost nothing.
The highest-performing animated sites do not use one technique everywhere. They match the technique to the job: CSS for micro-interactions, Lottie or Rive for narrative sequences, and WebGL only where three dimensions are genuinely required.
Lazy loading motion, not just images
Most teams lazy-load images below the fold. Fewer think to do the same with animation assets. A Lottie player in the footer should not start downloading its JSON payload until the user scrolls near it. The same goes for Rive files, GSAP-driven sequences, and any video texture feeding a WebGL scene.
The pattern is straightforward. Use Intersection Observer to detect when the animation’s container enters the viewport (or is within one screen-height of it). Only then load the library code and the animation data. For Lottie, this means dynamically importing lottie-web and calling loadAnimation on intersection. For GSAP’s ScrollTrigger, set lazy: true so it waits to calculate positions until scroll brings elements close.
This approach directly improves two Core Web Vitals. LCP improves because the browser is not competing with animation payloads to render the hero. Interaction to Next Paint (INP) improves because less JavaScript is parsing and executing during the critical first seconds.
What the render thread actually sees
Here is a detail that separates teams who understand performance from teams who just paste Lighthouse suggestions into a ticket. When you animate an element, the browser decides whether to promote it to its own compositing layer. If it does, the GPU handles the animation independently. If it does not, every frame triggers a repaint on the main thread.
You can force layer promotion with will-change: transform or translateZ(0). But promoting too many elements creates its own problem: each layer consumes GPU memory, and on devices with limited VRAM (most phones), excessive layers cause frame drops or even browser crashes.
The rule of thumb: promote elements that are actively animating. Remove the promotion when the animation ends. In CSS, apply will-change via a class that gets added just before the animation starts and removed on animationend. In JavaScript-driven animation, GSAP handles this automatically for transform-based tweens, which is one reason it remains the industry standard for complex choreography.
If you are evaluating whether to build on top of custom design versus templates, this is exactly the kind of detail that matters. Templates rarely optimize layer promotion or manage will-change lifecycle. Custom implementations can.
Measuring what matters
Lighthouse scores in a lab environment are a starting point, not a verdict. Real-user monitoring (RUM) tells you what actually happens on your visitors’ devices. Chrome User Experience Report provides field data aggregated from real Chrome sessions. Pair that with your own RUM setup (tools like SpeedCurve, Vercel Analytics, or the Web Vitals JavaScript library) to track LCP, INP, and CLS across device segments.
Pay particular attention to the 75th percentile, not the median. Google uses the 75th percentile for Core Web Vitals assessment. A site can have a median INP of 150 ms and still fail the threshold because the 75th percentile sits at 250 ms. Animation-heavy pages often have this exact profile: fast for users on flagship phones, slow for everyone else.
If your animated site scores well in Lighthouse but field INP is above 200 ms, the animation is likely blocking the main thread on real devices. Lab tools do not replicate the memory pressure and CPU throttling of a two-year-old phone running thirty background tabs.
When budgeting for a redesign, allocate time and budget for RUM setup and a two-week field-data review after launch. Performance tuning is not a pre-launch task. It is a post-launch discipline.
Practical patterns that work right now
These are not theoretical. They are techniques shipping on production sites today.
Scroll-driven animations via CSS. The animation-timeline: scroll() property, supported in Chrome and Edge, lets you bind a CSS animation’s progress to scroll position with zero JavaScript. No event listeners, no requestAnimationFrame loops, no main thread cost. For Firefox and Safari fallback, use a small polyfill or degrade gracefully to a simple fade-in.
View Transitions API. For page-to-page animation in multi-page apps, the View Transitions API handles cross-fade and morph effects at the browser level. It avoids the SPA overhead of maintaining a persistent animation layer across routes.
Reduced motion media query. Always respect prefers-reduced-motion. This is not optional. Beyond accessibility compliance, it is a performance escape hatch: users who set this preference often do so because their devices struggle with animation. Serve them a static, fast experience and save the motion for devices that can handle it.
Responsive animation density. Serve fewer animated elements on mobile. A desktop hero might have three layered parallax planes. On a 375px viewport with a Snapdragon 680 processor, one gentle fade is enough. Use CSS media queries or JavaScript device-capability checks to scale animation complexity, not just layout.
The takeaway
Animated websites do not have to be slow websites. The constraint is not the animation. It is the absence of a budget, the wrong technique for the job, and the failure to measure on real devices. Set the budget in discovery, pick the lightest technique that achieves the creative intent, lazy-load everything below the fold, and validate with field data after launch.
FAQs
Do animated websites always score poorly on Core Web Vitals?
No. Animations that use CSS transforms and opacity, are lazy-loaded below the fold, and respect a defined performance budget can achieve passing Core Web Vitals scores. The problems start when animation assets load eagerly, animate layout-triggering properties, or block the main thread with heavy JavaScript.
Which animation library is best for web performance?
CSS transitions and keyframes are the lightest option for simple motion. For complex sequencing, GSAP remains the industry standard because it automatically uses GPU-friendly properties and manages layer promotion. For illustrative animation, Rive typically produces smaller files than Lottie. The best choice depends on the complexity of the motion you need.
How do I test animation performance on real devices?
Use Chrome DevTools with CPU and network throttling enabled to simulate mid-range phones. For field data, set up Real User Monitoring with tools like SpeedCurve or the Web Vitals JavaScript library, and review the 75th percentile for INP and LCP. The Chrome User Experience Report also provides aggregated field data from real Chrome sessions.
Should I disable animations for users who prefer reduced motion?
Yes. The prefers-reduced-motion media query should always be respected. It is an accessibility requirement and also improves performance for users whose devices struggle with complex motion. Serve them a static, fast experience while keeping rich animation for capable devices.
How much of my page budget should animation assets consume?
On a typical marketing page with a 1.5 MB total transfer budget, animation assets (Lottie JSON, Rive files, animation libraries) should stay under 300 to 400 KB combined. If a single animation exceeds that, optimize it by simplifying paths, removing hidden layers, or switching to a more efficient format like Rive’s binary.
Make your animated site fast, not fragile
Rich motion and strong Core Web Vitals are not mutually exclusive when the performance budget is set in discovery. We design and build interactive experiences that pass field-data thresholds on real devices.