Images are not your only option for rich backgrounds. With a single background property, you can stack multiple gradients to paint skies, rays, textures, borders, and shine. In this tutorial you will learn how to combine linear, radial, repeating, and conic gradients into one layered background that powers a poster-style hero and a glossy button, no extra DOM wrappers, no images.
Why Combining Multiple CSS Gradients in One Background Matters
Layering gradients inside one background reduces markup and removes image dependencies. The result renders crisply at any resolution, themes instantly with custom properties, and ships fewer bytes. Gradients are vector math, so they scale without artifacts and avoid the network requests and color banding that come with raster images. You also gain precise control over stacking order, placement, and sizing for each layer from one place in your stylesheet.
Prerequisites
You do not need a graphics tool or a component library. You only need comfort with CSS syntax and a willingness to treat backgrounds like a tiny painting API.
- Basic HTML
- CSS custom properties
- CSS pseudo-elements (::before / ::after)
Step 1: The HTML Structure
The project has a single hero section and one button. Keep the markup small; all the decor will come from the background layers.
<section class="hero animate">
<h1>Layered Gradients, Zero Images</h1>
<p class="tagline">A hero banner built from six gradient layers.</p>
</section>
<button class="cta" type="button">Start Building</button>
Step 2: The Basic CSS & Styling
Set up a theme with CSS variables and apply baseline layout. The hero gets a roomy canvas, rounded corners, and readable type. The button uses native semantics; visual chrome will come from gradient layers in later steps.
/* CSS */
:root{
--bg: #0a0f1f;
--sky1: #2b6cf5;
--sky2: #7fd7ff;
--sun: #ffd56b;
--ray: rgba(255, 213, 107, 0.22);
--vignette: rgba(10, 15, 31, 0);
--vignetteEdge: rgba(10, 15, 31, 0.9);
--text: #eaf2ff;
--accent1: #8e75ff;
--accent2: #00e1c6;
}
*{ box-sizing: border-box; }
html,body{
height: 100%;
}
body{
margin: 0;
display: grid;
place-items: center;
gap: 2.5rem;
background: radial-gradient(120% 100% at 50% -20%, #10172a, var(--bg) 60%);
color: var(--text);
font: 500 16px/1.55 system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial, Apple Color Emoji, Segoe UI Emoji;
padding: 4vmin;
}
.hero{
min-width: min(92vw, 960px);
min-height: 320px;
border-radius: 16px;
padding: 4rem 2rem;
display: grid;
place-items: center;
gap: .5rem;
text-align: center;
}
.hero h1{
margin: 0;
font-size: clamp(1.6rem, 4vw, 2.6rem);
letter-spacing: .01em;
}
.hero .tagline{
margin: 0;
opacity: .9;
}
.cta{
appearance: none;
border: 2px solid transparent;
border-radius: 999px;
padding: .9rem 1.25rem;
font: 700 1rem/1.1 system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial;
color: #fff;
cursor: pointer;
letter-spacing: .02em;
}
Advanced Tip: Put colors, angles, and positions into CSS variables. You can swap a theme or animate a single custom property and affect several layers at once. This cuts duplication and keeps large gradient stacks readable.
Step 3: Building the Hero Gradient Stack
Now paint the hero background with six gradient layers. We will add sky, sun, rays, texture, a top highlight, and a vignette, all in one background pipeline.
/* CSS */
.hero{
/* The background is layered from top to bottom: first is topmost */
background-image:
/* 1) Edge vignette to frame the content */
radial-gradient(180% 120% at 50% 120%, var(--vignetteEdge), var(--vignette) 60%),
/* 2) Soft top highlight */
linear-gradient(to bottom, rgba(255,255,255,.18), rgba(255,255,255,0) 40%),
/* 3) A subtle diagonal texture */
repeating-linear-gradient(135deg, rgba(255,255,255,.08) 0 2px, rgba(0,0,0,0) 2px 8px),
/* 4) Sun rays using a conic gradient */
conic-gradient(from var(--spin, 220deg) at 75% 30%, var(--ray) 0 20deg, transparent 20deg 360deg),
/* 5) The sun (a radial gradient circle) */
radial-gradient(circle at 75% 30%, var(--sun) 0 20%, rgba(255,213,107,0) 21%),
/* 6) The sky base */
linear-gradient(to bottom, var(--sky2), var(--sky1) 60%);
background-position:
center,
top center,
center,
75% 30%,
75% 30%,
center;
background-size:
cover,
auto,
auto,
140% 140%,
300px 300px,
cover;
background-repeat:
no-repeat,
no-repeat,
repeat,
no-repeat,
no-repeat,
no-repeat;
box-shadow:
0 20px 50px -20px rgba(0,0,0,.6),
inset 0 0 0 1px rgba(255,255,255,.04);
}
How This Works (Code Breakdown)
CSS draws multiple backgrounds in order. The first gradient is on top; the last gradient sits at the bottom. That rule alone gives you predictable composition. In the hero, the sky is the last item, so everything else appears above it.
The sky uses a simple linear-gradient that blends var(–sky2) into var(–sky1). The sun sits on top of that using a radial-gradient positioned at 75% 30%. Radial gradients are a clean way to draw circles without extra elements. If your layout calls for a hard-edged circle shape elsewhere, review how to make a circle with CSS.
Rays come from a conic-gradient. Conic gradients sweep around a center point, so they are perfect for starbursts and pie segments. Here we start the sweep from var(–spin, 220deg) at 75% 30% (the same place as the sun) and fill the first 20 degrees with a semi-transparent yellow, leaving the rest transparent. That creates one spoke. The layer does not repeat, but the conic sweep makes it feel like a radial burst. If you want spiky outlines rather than soft color, look at how to make a starburst with CSS and adapt the stop pattern to conic-gradient.
The diagonal texture is a repeating-linear-gradient laid above the sky and sun. It creates fine stripes that break flat color without overwhelming text. The top highlight is a short linear-gradient that fades out early, which gives a soft gloss near the top edge of the hero.
Finally, the vignette is a large radial-gradient placed below the content area, fading from a near-opaque edge to transparent. That pulls your eye toward the center and improves text legibility. The background-position, background-size, and background-repeat each accept a comma-separated list, which lets you tune every layer precisely. Keeping the sun and ray layers aligned by position ensures they move together if you later animate their angle.
You can also carve corner cuts or accent triangles purely with gradients. A linear-gradient that transitions from transparent to a color at 50% will render a triangular cutoff if you size and position it to a corner. If you prefer a structural approach for consistent arrowheads, you can make a triangle right with CSS and combine it with gradient backgrounds.
Step 4: Building the Glossy Gradient Button
This button uses four background layers: a border ring, the main fill, a soft rim glow, and a moving shine. The key trick is different background-clip values per layer. Clipping the top three to the padding-box keeps them inside the border; clipping the last to the border-box paints the gradient inside the border area only, which creates a gradient border without extra wrappers.
/* CSS */
.cta{
--shine-y: -20%;
background:
/* 1) Moving shine */
linear-gradient(180deg, rgba(255,255,255,.50), rgba(255,255,255,0) 60%) padding-box,
/* 2) Top rim glow */
radial-gradient(150% 220% at 50% var(--shine-y), rgba(255,255,255,.35), rgba(255,255,255,0) 60%) padding-box,
/* 3) Main fill */
linear-gradient(160deg, var(--accent2), var(--accent1)) padding-box,
/* 4) Gradient border ring */
conic-gradient(from 0turn, var(--accent1), var(--accent2), var(--accent1)) border-box;
background-clip:
padding-box,
padding-box,
padding-box,
border-box;
background-position:
50% -20%,
50% -30%,
50% 50%,
50% 50%;
background-size:
100% 180%,
100% 180%,
100% 100%,
200% 200%;
background-repeat:
no-repeat,
no-repeat,
no-repeat,
no-repeat;
box-shadow:
0 8px 24px -8px rgba(0,0,0,.5),
inset 0 1px 0 rgba(255,255,255,.25);
transition: background-position .6s ease, transform .06s ease, filter .2s ease;
}
.cta:hover{
/* Slide the shine down across the cap */
background-position:
50% 120%,
50% 110%,
50% 50%,
50% 50%;
filter: saturate(1.1);
}
.cta:active{
transform: translateY(1px);
}
How This Works (Code Breakdown)
All four gradients live in the same background declaration and are clipped differently. The border trick relies on a transparent border with a gradient painted in the border-box area. Since the top three layers are clipped to the padding-box, they never overlap the border ring.
The main fill uses a linear-gradient between two accent colors for depth. The rim glow is a radial-gradient anchored above the button (negative Y focus) to give a soft light roll-off that reads like a physically lit edge. The moving shine is another linear-gradient with a tall background-size; by transitioning the background-position, it travels across the button on hover without any pseudo-elements.
Conic gradients make lively borders because hue transitions can wrap without visible seams. If you need a geometric badge or an emblem behind the button, circle or polygon shapes can be layered below these gradients as separate elements; the gradient technique stays the same either way.
Advanced Techniques: Adding Animations & Hover Effects
For the hero, animate the conic ray angle with a typed custom property. Modern browsers can transition or keyframe custom properties when you define them with @property. Provide a media query for motion preferences so motion-sensitive users are not forced to watch background animation.
/* CSS */
@property --spin {
syntax: "<angle>";
inherits: false;
initial-value: 220deg;
}
@keyframes raysSpin {
to { --spin: 580deg; } /* 220deg + 360deg */
}
/* Only the angle changes; all other layers stay still */
.hero.animate{
animation: raysSpin 20s linear infinite;
}
/* Respect user preferences */
@media (prefers-reduced-motion: reduce){
.hero.animate{ animation: none; }
.cta{ transition: none; }
}
If you prefer a subtler hero, animate the opacity of the texture layer by switching to a variable inside the repeating-linear-gradient color, then keyframe that variable. That gives a gentle shimmer without moving geometry. On the button, background-position transitions are cheap and read clearly. Keep transforms tiny (a 1px press is enough) so you avoid layout shifts.
Accessibility & Performance
Accessibility
Gradients are visual sugar, so do not let them hurt readability. Check contrast between text and the brightest part of the background. If your hero uses light rays near text, increase text shadow or adjust the highlight stop so the bright zone sits behind empty space. All artifacts here are decorative; no ARIA is required. For motion, tie any continuous animation to prefers-reduced-motion and offer a non-animated class as a simple off switch.
Performance
Browsers paint gradient layers fast, but every extra layer is more work. Keep counts reasonable: six to eight layers for a large hero is fine on modern devices, while dozens on a scrolling page can add up. Avoid animating large background-size values across the viewport. Animating custom properties that only affect color stops or angles is usually cheaper than animating positions of massive repeating patterns. Reserve will-change for true hotspots and remove it after transitions finish to avoid long-lived memory overhead.
Carry Gradient Power Into Any Component
You built a poster-style hero and a glossy button using nothing but layered gradients in one background. You controlled stacking order, positioning, clipping, and even animation, all from a single declaration. Use the same approach to texture cards, frame avatars, or build badges, and mix it with shape techniques like how to make a circle with CSS or even burst motifs like how to make a starburst with CSS. Now you have a foundation for rich, scalable backgrounds that ship fast and stay flexible.