How to create a gradient mesh hero background グラデーションメッシュ(FV背景)の作り方
Five blurred radial-gradient orbs float on CSS keyframes, blending into a vivid mesh — a WebGL-free hero background. 5つのぼかしオーブが CSS keyframes で浮遊し、WebGLなしで生成感のあるメッシュグラデーション背景を実現。
ライブデモ Live Demo
Build something beautiful
Pure CSS hero background — no WebGL, no canvas,
just blurred radial gradients in motion.
概要・用途・特徴Overview, Usage & Features
何ができるかWhat it does
Five blurred radial-gradient orbs float on CSS keyframes, blending into a vivid mesh — a WebGL-free hero background.
5つのぼかしオーブが CSS keyframes で浮遊し、WebGLなしで生成感のあるメッシュグラデーション背景を実現。
どこで使うかWhere to use
web application, marketing page
ヒーローセクション、フルスクリーン背景、プロダクトランディングページ、ポートフォリオ
特徴Key features
CSS-only gradient mesh background using multiple layered radial-gradient() and mesh-gradient() values. Animated via @keyframes hue-rotate or background-position shifts. Zero JavaScript. Highly performant as a CSS paint operation.
複数のradial-gradient()とmesh-gradient()値を重ねたCSSオンリーのグラデーションメッシュ背景。@keyframesのhue-rotateまたはbackground-positionシフトでアニメーション。JavaScript不要。CSSペイント操作として高パフォーマンス。
調整可能パラメータ Adjustable Parameters
| Parameter | Default | Description |
|---|---|---|
--mesh-blur | — | `filter: blur()` value (40–140px). Larger = softer spread; smaller = distinct glow centers |
animation-duration | — | Base durations (12s, 9s, 11s, 14s, 8s) divided by the speed multiplier. Default 1.0× |
--c1 〜 --c5 | — | Colors for the five orbs; swapped in bulk via theme class (Aurora / Sunset / Forest) |
orb size / position | — | Adjust `width`, `height`, and position props on each `.mesh-orb-N` to change overlap and gradient distribution |
opacity | — | Lower `.mesh-orb` opacity (default 0.85) for a muted look; raise it for more vivid gradients |
prefers-reduced-motion | — | Stops all orb animations, rendering the gradients as a still background |
実装コード Implementation Code
// react/M-015.jsx
import "./M-015.css";
const THEMES = {
aurora: {
bg: "#080814",
colors: ["#7c3aed", "#db2777", "#2563eb", "#6d28d9", "#0e7490"],
},
sunset: {
bg: "#140a04",
colors: ["#ea580c", "#db2777", "#d97706", "#dc2626", "#9333ea"],
},
forest: {
bg: "#040f08",
colors: ["#059669", "#0d9488", "#65a30d", "#16a34a", "#0284c7"],
},
};
const BASE_DURATIONS = [12, 9, 11, 14, 8];
const ORB_POSITIONS = [
{ top: "-25%", left: "-10%" },
{ top: "-15%", right: "-10%" },
{ bottom: "-20%", left: "15%" },
{ top: "25%", right: "5%" },
{ bottom: "-10%", right: "-5%" },
];
const ORB_SIZES = [
{ width: "60%", height: "75%" },
{ width: "55%", height: "65%" },
{ width: "50%", height: "60%" },
{ width: "42%", height: "55%" },
{ width: "38%", height: "50%" },
];
const ORB_DELAYS = ["-3s", "-5s", "-7s", "-2s", "-4s"];
export default function GradientMeshHero({
theme = "aurora",
blur = 80,
speed = 1,
badge = "Gradient Mesh",
title = "Build something beautiful",
subtitle = "Pure CSS hero background — no WebGL, no canvas.",
children,
}) {
const themeData = THEMES[theme] ?? THEMES.aurora;
return (
<div
className="mesh-hero"
style={{ background: themeData.bg, "--mesh-blur": blur + "px" }}
>
<div className="mesh-bg">
{themeData.colors.map((color, i) => (
<div
key={i}
className={`mesh-orb mesh-orb-${i + 1}`}
style={{
...ORB_SIZES[i],
...ORB_POSITIONS[i],
background: `radial-gradient(circle at center, ${color} 0%, transparent 70%)`,
animationDuration: BASE_DURATIONS[i] / speed + "s",
animationDelay: ORB_DELAYS[i],
}}
/>
))}
</div>
<div className="mesh-card">
{badge && <span className="mesh-badge">{badge}</span>}
{title && <h2 className="mesh-title">{title}</h2>}
{subtitle && <p className="mesh-sub">{subtitle}</p>}
{children}
</div>
</div>
);
}
/* react/M-015.css */
.mesh-hero {
position: relative;
overflow: hidden;
border-radius: 20px;
height: clamp(280px, 45vw, 380px);
--mesh-blur: 80px;
}
.mesh-bg {
position: absolute;
inset: 0;
pointer-events: none;
}
.mesh-orb {
position: absolute;
border-radius: 50%;
filter: blur(var(--mesh-blur));
opacity: 0.85;
will-change: transform;
}
.mesh-orb-1 { animation: mesh-float-1 12s ease-in-out infinite; }
.mesh-orb-2 { animation: mesh-float-2 9s ease-in-out infinite; }
.mesh-orb-3 { animation: mesh-float-3 11s ease-in-out infinite; }
.mesh-orb-4 { animation: mesh-float-4 14s ease-in-out infinite; }
.mesh-orb-5 { animation: mesh-float-5 8s ease-in-out infinite; }
@keyframes mesh-float-1 {
0%, 100% { transform: translate(0%, 0%) scale(1); }
50% { transform: translate(18%, 22%) scale(1.08); }
}
@keyframes mesh-float-2 {
0%, 100% { transform: translate(0%, 0%) scale(1); }
33% { transform: translate(-22%, 18%) scale(1.05); }
66% { transform: translate(8%, -12%) scale(0.95); }
}
@keyframes mesh-float-3 {
0%, 100% { transform: translate(0%, 0%) scale(1); }
50% { transform: translate(-18%, -22%) scale(1.1); }
}
@keyframes mesh-float-4 {
0%, 100% { transform: translate(0%, 0%) scale(1); }
40% { transform: translate(22%, 12%) scale(1.06); }
80% { transform: translate(-12%, -18%) scale(0.94); }
}
@keyframes mesh-float-5 {
0%, 100% { transform: translate(0%, 0%) scale(1); }
50% { transform: translate(-28%, 18%) scale(1.12); }
}
@media (prefers-reduced-motion: reduce) {
.mesh-orb { animation: none; }
}
.mesh-card {
position: absolute;
inset: 0;
display: flex;
flex-direction: column;
align-items: flex-start;
justify-content: center;
padding: clamp(24px, 5vw, 44px);
pointer-events: none;
}
.mesh-badge {
display: inline-flex;
align-items: center;
gap: 7px;
border-radius: 999px;
padding: 6px 14px;
font-size: 11px;
font-weight: 700;
letter-spacing: 0.1em;
text-transform: uppercase;
color: rgba(255, 255, 255, 0.92);
background: rgba(255, 255, 255, 0.1);
border: 1px solid rgba(255, 255, 255, 0.22);
backdrop-filter: blur(8px);
-webkit-backdrop-filter: blur(8px);
margin-bottom: 16px;
}
.mesh-title {
margin: 0 0 10px;
font-size: clamp(26px, 5vw, 44px);
line-height: 1.1;
font-weight: 700;
color: #ffffff;
text-shadow: 0 2px 24px rgba(0, 0, 0, 0.45);
}
.mesh-sub {
margin: 0;
max-width: 38ch;
font-size: clamp(13px, 2vw, 15px);
line-height: 1.65;
color: rgba(255, 255, 255, 0.7);
}
import "./M-015.css";
const THEMES = {
aurora: {
bg: "#080814",
colors: ["#7c3aed", "#db2777", "#2563eb", "#6d28d9", "#0e7490"],
},
sunset: {
bg: "#140a04",
colors: ["#ea580c", "#db2777", "#d97706", "#dc2626", "#9333ea"],
},
forest: {
bg: "#040f08",
colors: ["#059669", "#0d9488", "#65a30d", "#16a34a", "#0284c7"],
},
};
const BASE_DURATIONS = [12, 9, 11, 14, 8];
const ORB_POSITIONS = [
{ top: "-25%", left: "-10%" },
{ top: "-15%", right: "-10%" },
{ bottom: "-20%", left: "15%" },
{ top: "25%", right: "5%" },
{ bottom: "-10%", right: "-5%" },
];
const ORB_SIZES = [
{ width: "60%", height: "75%" },
{ width: "55%", height: "65%" },
{ width: "50%", height: "60%" },
{ width: "42%", height: "55%" },
{ width: "38%", height: "50%" },
];
const ORB_DELAYS = ["-3s", "-5s", "-7s", "-2s", "-4s"];
export default function GradientMeshHero({
theme = "aurora",
blur = 80,
speed = 1,
badge = "Gradient Mesh",
title = "Build something beautiful",
subtitle = "Pure CSS hero background — no WebGL, no canvas.",
children,
}) {
const themeData = THEMES[theme] ?? THEMES.aurora;
return (
<div
className="mesh-hero"
style={{ background: themeData.bg, "--mesh-blur": blur + "px" }}
>
<div className="mesh-bg">
{themeData.colors.map((color, i) => (
<div
key={i}
className={`mesh-orb mesh-orb-${i + 1}`}
style={{
...ORB_SIZES[i],
...ORB_POSITIONS[i],
background: `radial-gradient(circle at center, ${color} 0%, transparent 70%)`,
animationDuration: BASE_DURATIONS[i] / speed + "s",
animationDelay: ORB_DELAYS[i],
}}
/>
))}
</div>
<div className="mesh-card">
{badge && <span className="mesh-badge">{badge}</span>}
{title && <h2 className="mesh-title">{title}</h2>}
{subtitle && <p className="mesh-sub">{subtitle}</p>}
{children}
</div>
</div>
);
}
.mesh-hero {
position: relative;
overflow: hidden;
border-radius: 20px;
height: clamp(280px, 45vw, 380px);
--mesh-blur: 80px;
}
.mesh-bg {
position: absolute;
inset: 0;
pointer-events: none;
}
.mesh-orb {
position: absolute;
border-radius: 50%;
filter: blur(var(--mesh-blur));
opacity: 0.85;
will-change: transform;
}
.mesh-orb-1 { animation: mesh-float-1 12s ease-in-out infinite; }
.mesh-orb-2 { animation: mesh-float-2 9s ease-in-out infinite; }
.mesh-orb-3 { animation: mesh-float-3 11s ease-in-out infinite; }
.mesh-orb-4 { animation: mesh-float-4 14s ease-in-out infinite; }
.mesh-orb-5 { animation: mesh-float-5 8s ease-in-out infinite; }
@keyframes mesh-float-1 {
0%, 100% { transform: translate(0%, 0%) scale(1); }
50% { transform: translate(18%, 22%) scale(1.08); }
}
@keyframes mesh-float-2 {
0%, 100% { transform: translate(0%, 0%) scale(1); }
33% { transform: translate(-22%, 18%) scale(1.05); }
66% { transform: translate(8%, -12%) scale(0.95); }
}
@keyframes mesh-float-3 {
0%, 100% { transform: translate(0%, 0%) scale(1); }
50% { transform: translate(-18%, -22%) scale(1.1); }
}
@keyframes mesh-float-4 {
0%, 100% { transform: translate(0%, 0%) scale(1); }
40% { transform: translate(22%, 12%) scale(1.06); }
80% { transform: translate(-12%, -18%) scale(0.94); }
}
@keyframes mesh-float-5 {
0%, 100% { transform: translate(0%, 0%) scale(1); }
50% { transform: translate(-28%, 18%) scale(1.12); }
}
@media (prefers-reduced-motion: reduce) {
.mesh-orb { animation: none; }
}
.mesh-card {
position: absolute;
inset: 0;
display: flex;
flex-direction: column;
align-items: flex-start;
justify-content: center;
padding: clamp(24px, 5vw, 44px);
pointer-events: none;
}
.mesh-badge {
display: inline-flex;
align-items: center;
gap: 7px;
border-radius: 999px;
padding: 6px 14px;
font-size: 11px;
font-weight: 700;
letter-spacing: 0.1em;
text-transform: uppercase;
color: rgba(255, 255, 255, 0.92);
background: rgba(255, 255, 255, 0.1);
border: 1px solid rgba(255, 255, 255, 0.22);
backdrop-filter: blur(8px);
-webkit-backdrop-filter: blur(8px);
margin-bottom: 16px;
}
.mesh-title {
margin: 0 0 10px;
font-size: clamp(26px, 5vw, 44px);
line-height: 1.1;
font-weight: 700;
color: #ffffff;
text-shadow: 0 2px 24px rgba(0, 0, 0, 0.45);
}
.mesh-sub {
margin: 0;
max-width: 38ch;
font-size: clamp(13px, 2vw, 15px);
line-height: 1.65;
color: rgba(255, 255, 255, 0.7);
}
仕組みとカスタマイズHow It Works & Customization
仕組みHow it works
Multiple radial-gradient layers are stacked via the background shorthand property, each with different color stops, sizes, and positions. A CSS animation shifts the background-position of each layer at different speeds and directions, creating a flowing, organic mesh appearance. The layers blend using the default source-over compositing mode.
backgroundプロパティで複数のradial-gradient層を重ね、各層が異なる色・サイズ・位置を持ちます。CSSアニメーションが各層のbackground-positionを異なる速度・方向でシフトし、流れるオーガニックなメッシュ外観を作成。層はデフォルトのsource-overコンポジットモードでブレンドされます。
カスタマイズ方法Customization
Change the radial-gradient color stops to shift the entire palette. Adjust background-size percentages to scale the mesh blob sizes. Increase animation-duration for a slow, meditative flow; decrease for active energy. Add animation-direction: alternate for a back-and-forth oscillation.
radial-gradientのカラーストップを変更してパレット全体をシフト。background-sizeのパーセンテージでメッシュブロブのサイズを調整。animation-durationを増やして瞑想的なゆっくりしたフロー、減らして活発なエネルギーに。animation-direction:alternateで往復振動を追加。
注意点Caveats
Complex multi-layer gradients are repainted every frame during animation, which can be expensive on Safari/mobile. Use will-change: background-position to hint the browser. For best performance, prefer animating transform or opacity over background-position when possible.
複雑な多層グラデーションはアニメーション中に毎フレーム再ペイントされ、Safari/モバイルで重くなる可能性があります。will-change:background-positionでブラウザにヒントを与えてください。可能な場合はbackground-positionよりtransformやopacityのアニメーションを優先するとパフォーマンスが向上します。
よくある質問 Frequently Asked Questions
How to customize the gradient mesh hero background? Gradient Mesh Hero Backgroundをカスタマイズするには?
Modify the CSS custom properties and class styles defined in the code section. Key adjustable values include colors, sizes, durations, and spacing. See the Adjustable Parameters section for specific variables.
コードセクションで定義されているCSSカスタムプロパティとクラススタイルを変更してください。色、サイズ、時間、間隔が主な調整可能値です。具体的な変数は調整可能パラメータセクションを参照してください。
How to use the gradient mesh hero background in React? ReactでGradient Mesh Hero Backgroundを使うには?
Import the provided React component and its CSS file. The component accepts props for customization. Check the React code section for the full implementation and available props.
提供されているReactコンポーネントとCSSファイルをインポートしてください。コンポーネントのpropsでカスタマイズできます。完全な実装と利用可能なpropsはReactコードセクションを参照してください。
What are the performance implications of gradient mesh hero background? Gradient Mesh Hero Backgroundのパフォーマンスへの影響は?
This implementation uses CSS transforms and opacity for animations, which are GPU-accelerated. It's lightweight and doesn't cause layout thrashing. Consider using prefers-reduced-motion for accessibility.
この実装はCSSのtransformとopacityを使用しており、GPUアクセラレーションされます。軽量でレイアウトスラッシングを引き起こしません。アクセシビリティのためにprefers-reduced-motionの使用を検討してください。
AIへの指示テンプレート AI Prompt Template
以下をAIに貼り付けると実装を依頼できます。 Paste the following into your AI assistant to request implementation.