HomeBlogAnimated Mesh Gradient Backgrounds in CSS: The Complete Developer's Guide
Engineering INTERACTIVE LESSONBeginner Difficulty

Animated Mesh Gradient Backgrounds in CSS: The Complete Developer's Guide

Learn how to build, animate, and optimize mesh gradient backgrounds using pure CSS — layered radial gradients, @property, GPU acceleration, React/Next.js patterns, and accessibility best practices.

M

Marc Sterling

Design Systems Architect

July 06, 20266 min read read15 min install
ENGINES SUPPORTED:
Blink
WebKit
Gecko

Quick Summary & Milestone Specs

WHAT YOU'LL LEARN

  • How to build hardware-accelerated animated CSS gradients
  • Optimizing repaint layers on the GPU for zero performance cost
  • Using CSS custom properties for dynamic speed adjustments

PREREQUISITES

Basic knowledge of standard HTML structure, CSS properties, and keyframe transitions.

ESTIMATED TIME

15 min install

COMPLEXITY

BEGINNER

TARGET AUDIENCE

Design Engineers

TECHNOLOGIES USED

CSS3 Custom VariablesHTML5 LayoutsGPU Compositor layers

Interactive Playground Studio

Customize visual shaders, speeds, blurs, and review structural behaviors in real-time.

Live Rendering
Active Frame Rate: 60 FPS
Animation Speed1x
Backdrop Blur0px
Layer Opacity100%
Open in Studio
Advertisement
Sponsor Advertisement
Flexible Native | In-Article

Native In-Article Stream

Slot ID: ca-pub-blog-post-mid

Google AdSense Placeholder

Animated Mesh Gradient Backgrounds in CSS: The Complete Developer's Guide

If you've scrolled through Dribbble, Linear's marketing pages, or basically any SaaS landing page redesigned in the last two years, you've seen them: soft, blurry, multi-colored blobs of light that drift slowly behind a hero section. Designers call them mesh gradients. Developers call them "that thing that's annoyingly hard to get right in CSS."

The good news is that mesh gradients are not some exotic Figma-only effect. They're just gradients — stacked, blended, and animated with a bit of intention. The bad news is that most tutorials show you a static screenshot and skip the part that actually matters: how to animate one smoothly without dropping frames on a mid-range laptop, let alone a phone.

This guide walks through the real mechanics of mesh gradient backgrounds — how they're constructed, how to animate them using modern CSS features like `@property`, why so many implementations tank performance, and how to build a reusable, themeable component you can drop into a React or Next.js project. Modern web design has quietly shifted toward these ambient, generative-feeling backgrounds because they signal polish without adding real visual noise — but that only works if the animation is buttery and the accessibility story is solid. We'll cover both.

If at any point this feels like a lot of gradient math to keep in your head, that's a fair reaction — it is. Tools like MotionCanvas CSS exist precisely so you don't have to hand-tune conic-gradient angles at 2am; you can preview a mesh-style background live, nudge the color stops, and export clean HTML/CSS/JS when it looks right. But even if you end up using a generator, understanding what's happening under the hood will make you much better at customizing the result.

Live ShowcaseGradient

Mesh Gradient Showcase

Witness smooth GPU-composited radial mesh spheres moving dynamically across the canvas.

https://motioncanvas.online/preview/animated-mesh-gradient
Scroll Down
Next-Gen Scroll Mechanics

Experience Beautiful Ambient Depth

This browser window is simulating a production webpage. As you scroll down, the ambient Animated Mesh Gradient background dynamically zooms and pulls focus in real-time, creating beautiful, cinematic parallax depth.

Built for Ultra Performance

Modern web layouts require buttery-smooth animations. Our styles run completely on the GPU, avoiding CPU reflow and main-thread layout jank.

Focus Pull Parallax

Scroll depth controls blur intensity and lens scaling simultaneously to guide focus elegantly.

GPU-Accelerated

Uses hardware transforms and native filters, optimized for stable 120fps scrolling.

Highly Customizable

Adjust speed, maximum blur limit, zoom multipliers, and filters in real-time.

© 2026 MOTIONCANVAS. ALL RIGHTS RESERVED.ACTIVE BACKGROUND: ANIMATED MESH GRADIENT
Interact with Canvas
ANIMATION SPEED1x
BLUR LEVEL5px
OPACITY100%
Tip: Hover inside the live preview window and scroll down to observe scroll-linked shifts on the background coordinates.

What a Mesh Gradient Actually Is

A "true" mesh gradient — the kind Figma and Photoshop generate — interpolates color across a grid of anchor points, blending each one smoothly into its neighbors in two dimensions. CSS has no native primitive for that. There is no `mesh-gradient()` function, and there probably won't be one for a while.

What CSS *does* have is `radial-gradient()`, `conic-gradient()`, and the ability to stack multiple backgrounds on a single element using comma-separated `background-image` values. A CSS mesh gradient is really an illusion: several soft, offset radial gradients layered on top of each other, often blurred and blended, that *read* as a continuous mesh even though mathematically they're just circles fading to transparent.

Why This Illusion Works So Well

The human eye is bad at distinguishing "true" gradient interpolation from several overlapping soft-edged shapes, especially when there's motion and blur involved. Once you add a `filter: blur()` and a slow animation, the seams between the individual radial gradients disappear entirely. This is the same trick behind a lot of "AI-generated" looking backgrounds — it's not AI, it's layered geometry.

Where This Differs From a Simple Linear or Radial Gradient

A single `linear-gradient()` or `radial-gradient()` reads as flat and static, even when animated, because there's only one axis of change. Mesh gradients feel alive because multiple light sources move independently, at different speeds, in different directions — closer to how light behaves in a physical space than how a single gradient behaves on a plane.

💡 Pro Tip: If a mesh gradient looks "off," it's almost always because every layer is moving at the same speed. Real depth comes from asymmetric timing — one blob drifting slowly, another moving faster and in a different direction.

⚡ Interactive Design Canvas

Want to fully customize this canvas background?

This technique is implemented natively in our background customizer. Launch the studio to change shaders, modify velocities, blur radius, or export responsive components with one click.

The Core CSS Technique: Layered Radial Gradients

Here's a minimal three-point mesh gradient, built with nothing but stacked `radial-gradient()` calls:

CSS
1
2
3
4
5
6
7
8
9
10
11
12
13
.mesh-background {
--mesh-color-1: #ff6ec7;
--mesh-color-2: #6e6eff;
--mesh-color-3: #6effb0;
 
background-color: #0e0e12;
background-image:
radial-gradient(circle at 20% 30%, var(--mesh-color-1) 0%, transparent 45%),
radial-gradient(circle at 80% 20%, var(--mesh-color-2) 0%, transparent 50%),
radial-gradient(circle at 50% 80%, var(--mesh-color-3) 0%, transparent 55%);
background-blend-mode: screen;
filter: blur(60px) saturate(130%);
}

Three things are doing the heavy lifting here:

1. Percentage-based positioning (`circle at 20% 30%`) so the effect scales with the element instead of breaking on resize.

2. `background-blend-mode: screen`, which lightens overlapping colors instead of muddying them — critical for that glowing, luminous look.

3. `filter: blur()`, which is what actually erases the hard circular edges and turns three overlapping shapes into something that reads as continuous.

Adding a Conic Layer for Organic Rotation

Pure radial gradients tend to look symmetrical and a little clinical. Adding one `conic-gradient()` layer underneath introduces asymmetry that reads as more organic:

CSS
1
2
3
4
5
6
7
8
9
10
11
12
13
14
.mesh-background::before {
content: "";
position: absolute;
inset: -20%;
background: conic-gradient(
from 45deg at 40% 60%,
var(--mesh-color-1),
var(--mesh-color-2),
var(--mesh-color-3),
var(--mesh-color-1)
);
opacity: 0.35;
mix-blend-mode: soft-light;
}

Note the `inset: -20%` — mesh gradients almost always need to overflow their container slightly. Blurring an element close to its own edges creates a visible, ugly ring where the blur has nowhere to spread. Oversizing the source layer and clipping with `overflow: hidden` on the parent solves this cleanly.

Common Mistake: Applying `filter: blur()` directly to the same element that has `overflow: hidden` and a border-radius. Blur filters ignore border-radius clipping in some browsers, causing the glow to bleed outside rounded corners. Put the blur on an absolutely-positioned pseudo-element or child, and clip on the parent instead.

Animating Mesh Gradients Without Wrecking Frame Rate

This is where most implementations fall apart. The intuitive approach — animating `background-position` on each gradient layer — works, but it's expensive. Every change to `background-position` forces the browser to repaint the affected layer on the CPU, because gradients are recalculated per-frame rather than composited like a transform.

The @property Approach

Modern CSS gives you a better tool: `@property`. It lets you register a custom property with a defined syntax (like `` or ``), which means the browser can *interpolate* that property smoothly across an animation, including inside a gradient function.

CSS
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@property --mesh-x-1 {
syntax: "<;percentage>;";
inherits: false;
initial-value: 20%;
}
 
@property --mesh-y-1 {
syntax: "<;percentage>;";
inherits: false;
initial-value: 30%;
}
 
.mesh-background {
background-image:
radial-gradient(circle at var(--mesh-x-1) var(--mesh-y-1), var(--mesh-color-1) 0%, transparent 45%),
radial-gradient(circle at 80% 20%, var(--mesh-color-2) 0%, transparent 50%);
animation: drift-1 18s ease-in-out infinite alternate;
}
 
@keyframes drift-1 {
0% { --mesh-x-1: 20%; --mesh-y-1: 30%; }
50% { --mesh-x-1: 40%; --mesh-y-1: 65%; }
100% { --mesh-x-1: 15%; --mesh-y-1: 45%; }
}

This still triggers paint (gradients always will — there's no way around that), but the browser handles the interpolation natively instead of you calculating intermediate values in JavaScript, and the resulting motion is smoother because it's not tied to `requestAnimationFrame` timing jitter.

🚀 Performance Tip: Register every animated custom property with `@property` and an explicit `syntax`. Without registration, the browser treats custom properties as opaque strings and can't interpolate them at all — your "animation" will just snap between values with no easing.

Where GPU Acceleration Actually Helps

You can't move `background-position` onto the GPU compositor — but you *can* move the whole element. A common, much cheaper pattern is to keep the gradient static and animate a `transform` on a wrapping layer instead:

CSS
1
2
3
4
5
6
7
8
9
10
11
12
13
14
.mesh-layer {
position: absolute;
inset: -30%;
background-image: radial-gradient(circle at 30% 40%, var(--mesh-color-1), transparent 50%);
filter: blur(50px);
animation: float 22s ease-in-out infinite;
will-change: transform;
}
 
@keyframes float {
0% { transform: translate(0, 0) scale(1); }
50% { transform: translate(6%, -8%) scale(1.08); }
100% { transform: translate(-4%, 5%) scale(1); }
}

`transform` and `opacity` are the only two CSS properties the browser can animate purely on the compositor thread, skipping layout and paint entirely. Combining a static gradient with an animated transform gets you 90% of the visual effect of animating the gradient itself, at a fraction of the CPU cost. This is the single highest-leverage optimization in this entire article — if you only take one thing away, take this.

Advertisement
Sponsor Advertisement
Flexible Native | In-Article

Native In-Article Stream

Slot ID: ca-pub-blog-heading-ad-4

Google AdSense Placeholder

Building a Reusable Component

A mesh gradient background is only useful in production if it's themeable and composable. Here's a pattern that keeps all tunable values as CSS custom properties, so a single component can power dozens of visual variants.

HTML Structure

HTML
1
2
3
4
5
6
7
8
<div class="mesh-wrapper" style="--mesh-a: #ff6ec7; --mesh-b: #6e6eff; --mesh-c: #6effb0;">
<div class="mesh-layer mesh-layer--a"></div>
<div class="mesh-layer mesh-layer--b"></div>
<div class="mesh-layer mesh-layer--c"></div>
<div class="mesh-content">
<slot></slot>
</div>
</div>
CSS
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
.mesh-wrapper {
position: relative;
overflow: hidden;
background: #0b0b0f;
isolation: isolate;
}
 
.mesh-layer {
position: absolute;
inset: -25%;
filter: blur(55px) saturate(140%);
mix-blend-mode: screen;
pointer-events: none;
}
 
.mesh-layer--a { background: radial-gradient(circle at 25% 30%, var(--mesh-a), transparent 50%); animation: float 20s ease-in-out infinite; }
.mesh-layer--b { background: radial-gradient(circle at 75% 25%, var(--mesh-b), transparent 55%); animation: float 26s ease-in-out infinite reverse; }
.mesh-layer--c { background: radial-gradient(circle at 50% 80%, var(--mesh-c), transparent 55%); animation: float 32s ease-in-out infinite; }

Notice `isolation: isolate` on the wrapper — without it, `mix-blend-mode: screen` on the layers can bleed into and blend with elements *outside* the component, not just with each other, producing unpredictable visual bugs on real pages with other stacked content.

React Component

CSS
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function MeshBackground({ colors = ["#ff6ec7", "#6e6eff", "#6effb0"], children }) {
const style = {
"--mesh-a": colors[0],
"--mesh-b": colors[1],
"--mesh-c": colors[2],
};
 
return (
<;div className="mesh-wrapper" style={style}>;
<;div className="mesh-layer mesh-layer--a" />;
<;div className="mesh-layer mesh-layer--b" />;
<;div className="mesh-layer mesh-layer--c" />;
<;div className="mesh-content">;{children}<;/div>;
<;/div>;
);
}

Next.js Considerations

In Next.js, the main gotcha isn't the component itself — it's where the CSS lives. If you're using the App Router with CSS Modules, keep the `@property` declarations in a global stylesheet rather than a scoped module file. `@property` is a top-level at-rule and some CSS Module processors will strip or mangle at-rules that don't look like standard selectors. A safe pattern:

CSS
1
2
3
4
app/
globals.css // @property declarations + @keyframes live here
components/
MeshBackground.module.css // layout + color usage only

Tailwind Integration

If your project is Tailwind-based, you don't need to abandon utility classes — just handle the gradient and blur as arbitrary values, and let Tailwind manage everything else:

HTML
1
2
3
4
<div class="relative overflow-hidden isolate bg-[#0b0b0f]">
<div class="absolute -inset-1/4 blur-[55px] saturate-150 mix-blend-screen animate-[float_20s_ease-in-out_infinite]
bg-[radial-gradient(circle_at_25%_30%,var(--mesh-a),transparent_50%)]"></div>
</div>

Define `--mesh-a` and the `float` keyframes in your Tailwind config or a small companion stylesheet, since arbitrary gradient values with CSS variables inside `bg-[...]` require the variable to already exist in scope.

Common Mistakes to Avoid

Common Mistake: Blurring every layer at the same radius. Real depth comes from varying blur amounts — a closer, sharper blob and a farther, softer one — not just varying color.

Common Mistake: Forgetting `will-change: transform` and then wondering why the animation stutters on scroll. Without it, the browser may not promote the layer to its own compositor layer in advance, causing a visible hitch the first time the animation starts.

Common Mistake: Using `background-attachment: fixed` to create a parallax feel behind a mesh gradient. On mobile Safari this property is notoriously unreliable and can cause the entire background to disappear on scroll. Use a `transform`-based parallax technique instead.

Common Mistake: Stacking five or more animated gradient layers "for richness." Past three or four layers, the visual return diminishes fast while GPU memory and paint cost keep climbing. Three layers, well-tuned, almost always beats six mediocre ones.

Accessibility Considerations

Respecting Motion Preferences

Ambient background motion is exactly the kind of animation `prefers-reduced-motion` exists for. It's decorative, not functional, so pausing it costs you nothing in usability:

CSS
1
2
3
4
5
@media (prefers-reduced-motion: reduce) {
.mesh-layer {
animation: none;
}
}

Accessibility: Don't just slow the animation down for reduced-motion users — stop it. Slow ambient motion can still trigger discomfort for people with vestibular disorders; the safe default is a static frame, not a gentler version of the same motion.

Contrast Behind Text

Mesh gradients are frequently used as hero backgrounds with headline text on top, and the "screen" blend mode that makes the effect glow also makes it unpredictable in brightness at different scroll positions or viewport sizes. Always test contrast at the brightest point the gradient can reach, not just its average appearance, and consider a semi-opaque scrim:

CSS
1
2
3
4
5
.mesh-content {
position: relative;
z-index: 1;
background: linear-gradient(to bottom, rgba(0,0,0,0.35), rgba(0,0,0,0.55));
}

Run the final text color through a contrast checker against the *lightest* moment of the animation, not a static screenshot — animated backgrounds have a moving worst-case, and that's the case that matters for WCAG compliance.

Browser Support and Fallbacks

  • Layered `radial-gradient()` / `conic-gradient()` / `background-blend-mode`: supported in all evergreen browsers (Chrome, Firefox, Safari, Edge) for several years — safe to use without fallbacks.
  • `@property`: supported in Chromium browsers and Safari 16.4+; Firefox added support more recently, so check current coverage before relying on it as your only animation mechanism. Where it's unsupported, the custom property simply won't animate smoothly — the gradient will still render, just static or step-changed, which is a graceful-enough degradation for a decorative background.
  • `mix-blend-mode` / `filter: blur()`: broadly supported, but blur is expensive on low-end Android devices in particular. Consider a lighter blur radius or fewer layers behind a `prefers-reduced-data` or connection-aware check for those users.

📱 Mobile Optimization: On mobile, cut your blur radius roughly in half and drop to two gradient layers instead of three. Mobile GPUs handle large blur radii far worse than desktop, and the visual difference at phone viewing distance is minimal.

Advertisement
Sponsor Advertisement
Flexible Native | In-Article

Native In-Article Stream

Slot ID: ca-pub-blog-heading-ad-8

Google AdSense Placeholder

Performance Deep Dive

Open DevTools' Performance panel and record a few seconds of your mesh gradient animating. You're looking for two things: whether frames are being generated at a steady interval, and which phase — Paint, Composite, or Layout — is eating the most time per frame.

If you see heavy Paint activity every frame, you're animating something that forces gradient recalculation (like `background-position` directly). If you see mostly Composite activity with a thin Paint sliver only at animation start, you've successfully offloaded the motion to `transform`, which is the target state described above.

A quick sanity check: temporarily set `animation: none` on every mesh layer and watch your Cumulative Layout Shift and general scroll smoothness. If scrolling feels noticeably better with the animation off, the current implementation is too heavy for the pages it's shipping on, and it's worth revisiting the layer count or blur radius before shipping.

When Mesh Gradients Are (and Aren't) the Right Call

🎨 Design Inspiration: Mesh gradients shine in hero sections, empty states, loading screens, and auth pages — anywhere you want ambient atmosphere without competing for attention with real content. They tend to work poorly behind dense text, data tables, or anywhere contrast needs to stay perfectly stable, since the whole point of the effect is gentle, continuous change.

A good rule of thumb: if the background needs to be readable and unchanging for someone to do their job (a dashboard, a form, a code editor), skip the mesh gradient. If the background exists to set a mood before the real content loads, it's a strong fit.

From Prototype to Production

Everything above is buildable by hand, but tuning three layered gradients, three blur radii, three animation durations, and a color palette until it actually looks intentional takes real iteration time — usually more than developers budget for it. This is exactly the gap tools like MotionCanvas CSS are built to close: you get a library of pre-tuned animated backgrounds, including mesh-style effects, with a live panel to adjust colors and timing and see the result immediately, then export clean, dependency-free HTML, CSS, and JS when you're happy with it. It won't replace understanding the mechanics — but it will save you the hours of trial and error in getting the blur radius and blend mode combination to actually look right.

Frequently Asked Questions

Is a CSS mesh gradient the same as a true mesh gradient from Figma or Photoshop?

No. Design tools interpolate color across a genuine 2D grid of points. CSS fakes the same visual result using several overlapping radial and conic gradients with blur and blend modes — the output looks nearly identical but the underlying math is completely different.

Can I animate a mesh gradient without JavaScript?

Yes, entirely with CSS `@keyframes` and `@property`. JavaScript is only necessary if you want interactive controls, like letting a user pick colors at runtime.

Why does my mesh gradient look pixelated or banded?

Banding usually comes from a large blur radius combined with a limited color range, especially in dark themes. Adding slight `saturate()` in your `filter` and using colors with more tonal variation both help.

Do mesh gradients hurt Core Web Vitals?

Not inherently, but a poorly optimized one can hurt your Interaction to Next Paint (INP) score if it's causing continuous paint work on the main thread. Following the transform-based animation pattern above avoids this in almost all cases.

How many gradient layers should I use?

Three is the sweet spot for most designs. Two can look thin; five or more rarely adds proportional visual value and increases GPU load significantly.

Can I use mesh gradients as a full-page background instead of just a hero section?

Technically yes, but be cautious — a full-page fixed background with continuous animation running behind scrollable content is one of the more battery-intensive patterns you can ship, especially on laptops.

Will `mix-blend-mode: screen` work correctly on a dark background only, or does it need specific colors?

`screen` lightens as it blends, so it's most effective on dark backgrounds where there's room to get brighter. On a white or light background, `screen` will mostly wash everything out — use `multiply` or `overlay` instead for light themes.

Do I need a canvas or WebGL for a mesh gradient to look good?

No. Canvas and WebGL give you more precision and true point-based interpolation, but for the vast majority of hero-section use cases, layered CSS gradients are visually convincing and dramatically cheaper to implement and maintain.

How do I make the mesh gradient respond to the current color theme (light/dark mode)?

Store the palette as CSS custom properties scoped to `:root`, then override them inside your `[data-theme="dark"]` or `.dark` selector. Because the gradients reference the variables rather than hardcoded colors, the whole effect re-themes automatically.

Is it safe to put form inputs or buttons on top of an animated mesh gradient?

Yes, as long as there's a solid or near-solid scrim between the gradient and the interactive elements, both for contrast and so the constantly shifting background doesn't distract from focus states and hit targets.

Advertisement
Sponsor Advertisement
Flexible Native | In-Article

Native In-Article Stream

Slot ID: ca-pub-blog-heading-ad-12

Google AdSense Placeholder

Key Takeaways

  • A CSS mesh gradient is an illusion built from several overlapping, blurred `radial-gradient()` and `conic-gradient()` layers — not a native mesh primitive.
  • `background-blend-mode: screen` and `isolation: isolate` are what make the layered colors glow together convincingly instead of looking muddy or bleeding into surrounding elements.
  • Animate `transform` on the gradient layers rather than `background-position` whenever possible — it's the biggest performance lever in this entire technique.
  • Use `@property` with an explicit `syntax` if you do need to animate gradient values directly, or the browser won't interpolate them at all.
  • Always add a `prefers-reduced-motion` override that stops the animation entirely, and check text contrast against the brightest point the gradient reaches.
  • Three well-tuned gradient layers almost always outperform five mediocre ones, visually and computationally.

Conclusion

Mesh gradients are a good example of a design trend that looks intimidating until you see the CSS underneath it — at which point it's clearly just gradients, blend modes, and patience. The real skill isn't knowing the syntax; it's knowing where the performance costs hide (paint vs. composite), how to keep the effect accessible for people who don't want ambient motion, and how to stop tuning once three layers already look good.

If you'd rather start from a well-tuned base than build every layer from scratch, that's exactly what MotionCanvas CSS's animated background library is for — browse the mesh and gradient-based options, adjust the palette and timing live, and export the result the moment it fits your design.

Pro Code Snippet Workbench

8 Frameworks Integrated
:root {
--color-bg: #09090b;
--color-1: #7c5cff;
--color-2: #18c5ff;
--color-3: #f43f5e;
--color-4: #eab308;
--blur-amount: 80px;
--speed: 20s;
}
.mesh-gradient-container {
position: relative;
width: 100%;
height: 100%;
background: var(--color-bg);
overflow: hidden;
z-index: 1;
}
.mesh-ball {
position: absolute;
border-radius: 50%;
filter: blur(var(--blur-amount));
opacity: 0.6;
mix-blend-mode: screen;
}
.mesh-ball-1 {
width: 50%;
height: 50%;
background: var(--color-1);
top: 10%;
left: 10%;
animation: mesh-drift-1 var(--speed) infinite ease-in-out alternate;
}
.mesh-ball-2 {
width: 60%;
height: 60%;
background: var(--color-2);
bottom: 10%;
right: 10%;
animation: mesh-drift-2 var(--speed) infinite ease-in-out alternate;
}
.mesh-ball-3 {
width: 45%;
height: 45%;
background: var(--color-3);
top: 40%;
right: 20%;
animation: mesh-drift-3 var(--speed) infinite ease-in-out alternate;
}
.mesh-ball-4 {
width: 55%;
height: 55%;
background: var(--color-4);
bottom: 20%;
left: 20%;
animation: mesh-drift-4 var(--speed) infinite ease-in-out alternate;
}
@keyframes mesh-drift-1 {
0% { transform: translate(0, 0) scale(1); }
50% { transform: translate(20%, 15%) scale(1.1); }
100% { transform: translate(-10%, -5%) scale(0.9); }
}
@keyframes mesh-drift-2 {
0% { transform: translate(0, 0) scale(1); }
50% { transform: translate(-15%, -20%) scale(0.85); }
100% { transform: translate(10%, 10%) scale(1.15); }
}
@keyframes mesh-drift-3 {
0% { transform: translate(0, 0) scale(0.9); }
50% { transform: translate(-25%, 10%) scale(1.1); }
100% { transform: translate(15%, -15%) scale(1); }
}
@keyframes mesh-drift-4 {
0% { transform: translate(0, 0) scale(1.1); }
50% { transform: translate(10%, -25%) scale(0.9); }
100% { transform: translate(-15%, 15%) scale(1.05); }
}

Frequently Asked Questions

Advertisement
Sponsor Advertisement
728 × 90 | Responsive Banner

Responsive Horizontal Leaderboard

Slot ID: ca-pub-blog-post-bottom

Google AdSense Placeholder
MotionCanvas Designer Studio

Design stunning responsive backgrounds.

Join thousands of creative developers. Modify canvas properties, experience particle vectors, and export pristine production-ready Tailwind/CSS code frameworks natively.

M

Marc Sterling

TECHNICAL WRITER & CORE CONTRIBUTOR

Marc Sterling is a senior creative technologist and layout designer who advocates for hardware-accelerated user experiences. Currently leading web-core shaders research at MotionCanvas CSS.

Developer Comments (2)

Offline Sandbox Mode
Alex River2 hours ago

Incredible performance on mobile! Just integrated the mesh balls into our SaaS platform and CPU usage is completely unnoticeable. Thanks!

Sienna ChenYesterday

This is the cleanest explanation of GPU layout promotion I have seen online. Love the interactive customization dock!

GPU Performance Insights

GPU LAYER COMPOSITE98% Stable
CPU WEIGHT (MAIN THREAD)<0.8% load
A11Y CONTRAST INDEX100/100 AA Compliant
RENDER ENGINE:GPU CSS Only
MOBILE RESPONSIVE: FULLY COMPATIBLE
REFLOW LATENCY:0ms (Zero Thrash)

Explore Core Canvas Shaders

Aurora Flow

Gradient

Launch Studio

Sunset Gradient

Gradient

Launch Studio

Ocean Gradient

Gradient

Launch Studio

Rainbow Flow

Gradient

Launch Studio

Candy Gradient

Gradient

Launch Studio

Fire Gradient

Gradient

Launch Studio
Advertisement
Sponsor Advertisement
300 × 250 | Rectangle

Medium Rectangle Block

Slot ID: ca-pub-blog-post-sidebar

Google AdSense Placeholder

Interactive Developer Digest

Get custom shaders, optimization tips, and pure-CSS animation snippets monthly.

Related Coding Guides

Animated Mesh Gradient Backgrounds in CSS: The Complete Developer's Guide - MotionCanvas CSS