How to Create CSS Gradients

Summary: CSS gradients are one of the most powerful and performant visual tools in your design arsenal. This guide covers every gradient type โ€” linear, radial, conic, and repeating โ€” with full syntax breakdowns, creative techniques like gradient text and borders, performance considerations, Tailwind CSS integration, and practical examples you can copy directly into your projects.

๐Ÿ“– 26 min readยทUpdated March 2026

1. Linear Gradients

Linear gradients transition between colors along a straight line โ€” top to bottom, left to right, or any angle you specify. They're the most commonly used gradient type and the foundation of most gradient designs on the web.

/* Basic syntax */

/* Top to bottom (default) */
background: linear-gradient(#F59E0B, #EF4444);

/* Left to right */
background: linear-gradient(to right, #3B82F6, #8B5CF6);

/* Diagonal */
background: linear-gradient(135deg, #06B6D4, #8B5CF6, #EC4899);

/* Multiple color stops with positions */
background: linear-gradient(
  90deg,
  #F59E0B 0%,
  #EF4444 33%,
  #8B5CF6 66%,
  #3B82F6 100%
);

The direction keyword (to right, to bottom left) or angle (135deg, 0.5turn) controls the gradient's direction. At 0deg, the gradient goes from bottom to top. At 90deg, it goes from left to right. At 180deg, top to bottom (the default).

You can use as many color stops as you want, though two or three usually produce the cleanest results. Each stop can optionally include a position (percentage or length) to control where that color appears. Without explicit positions, colors are distributed evenly. Try experimenting with Hue's gradient generator to see how different angles and stops interact.

2. Radial Gradients

Radial gradients radiate outward from a center point, creating circular or elliptical color transitions. They're perfect for spotlight effects, glowing backgrounds, and organic-feeling color transitions.

/* Basic circle */
background: radial-gradient(circle, #F59E0B, #0a0a0b);

/* Ellipse at specific position */
background: radial-gradient(
  ellipse at 30% 50%,
  #3B82F6,
  #1E1B4B
);

/* Sized radial gradient */
background: radial-gradient(
  circle 200px at center,
  rgba(245, 158, 11, 0.3),
  transparent
);

/* Multiple radial gradients (layered) */
background:
  radial-gradient(circle at 20% 50%, rgba(59, 130, 246, 0.3), transparent 50%),
  radial-gradient(circle at 80% 50%, rgba(236, 72, 153, 0.3), transparent 50%),
  #0a0a0b;

The shape can be circle or ellipse (default). The size keyword โ€” closest-side, closest-corner, farthest-side, farthest-corner โ€” controls how far the gradient extends. Layering multiple radial gradients creates ambient lighting effects that are impossible with images and far more performant.

As shown in the MDN documentation on CSS radial gradients, you can combine size keywords with specific positions to create precise spotlight effects that draw attention to particular areas of your layout.

3. Conic Gradients

Conic gradients rotate color transitions around a center point, like a color wheel or pie chart. They were the last gradient type to gain browser support and open up design possibilities that linear and radial gradients can't achieve.

/* Basic conic gradient */
background: conic-gradient(#F59E0B, #EF4444, #8B5CF6, #3B82F6, #F59E0B);

/* Color wheel */
background: conic-gradient(
  from 0deg,
  hsl(0, 100%, 50%),
  hsl(60, 100%, 50%),
  hsl(120, 100%, 50%),
  hsl(180, 100%, 50%),
  hsl(240, 100%, 50%),
  hsl(300, 100%, 50%),
  hsl(360, 100%, 50%)
);

/* Pie chart */
background: conic-gradient(
  #3B82F6 0deg 216deg,    /* 60% */
  #F59E0B 216deg 288deg,  /* 20% */
  #EF4444 288deg 360deg   /* 20% */
);

/* Angular spotlight */
background: conic-gradient(
  from 45deg at 50% 50%,
  transparent,
  rgba(245, 158, 11, 0.2),
  transparent
);

The from keyword sets the starting angle, and at positions the center point. For a smooth color wheel, repeat the first color at the end. For pie-chart effects, use hard color stops (two values at the same position) to create sharp transitions instead of smooth blending. Conic gradients now have excellent browser support across all modern browsers.

4. Repeating Gradients

Every gradient type has a repeating variant: repeating-linear-gradient(), repeating-radial-gradient(), and repeating-conic-gradient(). These tile the gradient pattern, creating stripes, concentric rings, and other repeating visual effects.

/* Diagonal stripes */
background: repeating-linear-gradient(
  45deg,
  var(--surface) 0px,
  var(--surface) 10px,
  var(--surface-2) 10px,
  var(--surface-2) 20px
);

/* Concentric circles */
background: repeating-radial-gradient(
  circle at center,
  var(--surface) 0px,
  var(--surface) 8px,
  var(--border) 8px,
  var(--border) 10px
);

/* Subtle scan lines */
background: repeating-linear-gradient(
  0deg,
  transparent,
  transparent 2px,
  rgba(255, 255, 255, 0.02) 2px,
  rgba(255, 255, 255, 0.02) 4px
);

Repeating gradients are especially useful for decorative backgrounds โ€” stripes, grids, scan-line effects, and progress indicators. The key is keeping the repeat unit small and subtle so it reads as texture rather than pattern overload. These are pure CSS, meaning zero HTTP requests for what would otherwise require tiling background images.

5. Color Stops and Angles

Mastering color stops is the difference between generic gradients and polished, intentional ones. A color stop defines where a specific color appears in the gradient, and you have more control than you might think.

Basic Stop Positions

Each color stop accepts an optional position as a percentage or length: linear-gradient(#F59E0B 20%, #EF4444 80%). Without positions, colors distribute evenly. With positions, you control the transition zones precisely.

Hard Stops (No Transition)

/* Sharp boundary between colors */
background: linear-gradient(
  to right,
  #3B82F6 50%,
  #EF4444 50%
);

/* Three-stripe flag */
background: linear-gradient(
  to right,
  #002395 33.33%,
  #ffffff 33.33% 66.66%,
  #ED2939 66.66%
);

When two stops share the same position, there's no transition zone โ€” you get a hard edge. This technique creates striped patterns, color blocks, and flag designs without any images.

Transition Hints

CSS gradients also support transition hints โ€” a percentage between two color stops that shifts the midpoint: linear-gradient(#F59E0B, 25%, #EF4444). The 25% here means the midpoint between the two colors occurs at 25% instead of the default 50%. This creates asymmetric transitions that feel more natural and less mechanical.

Angle Units

Angles accept multiple units: deg (degrees, 0-360), turn (0.25turn = 90deg), rad (radians), and grad (gradians). Degrees are the most common and readable. Remember: 0deg points up, and angles rotate clockwise.

6. Gradient Text Effects

Gradient text is one of the most popular design trends in modern web design. Hue's own heading text uses this technique. The approach works by applying a gradient background and clipping it to the text shape.

/* Gradient text */
.gradient-text {
  background: linear-gradient(135deg, #F59E0B, #FDE68A, #F59E0B);
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  background-clip: text;
}

/* Animated gradient text */
.gradient-text-animated {
  background: linear-gradient(
    270deg, #F59E0B, #EF4444, #8B5CF6, #3B82F6, #F59E0B
  );
  background-size: 300% 300%;
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  background-clip: text;
  animation: gradient-shift 6s ease infinite;
}

@keyframes gradient-shift {
  0% { background-position: 0% 50%; }
  50% { background-position: 100% 50%; }
  100% { background-position: 0% 50%; }
}

Accessibility note: Gradient text can have contrast issues because the color varies across the text. Ensure the lowest contrast point in your gradient still meets WCAG requirements against the background. Check this with Hue's contrast checker using the lightest gradient color.

The -webkit- prefix is still needed for background-clip: text in some browsers. Always include both the prefixed and unprefixed versions.

7. Gradient Borders

CSS doesn't natively support gradient borders through border-color, but there are several reliable techniques to achieve the effect.

/* Method 1: border-image */
.gradient-border {
  border: 2px solid;
  border-image: linear-gradient(135deg, #F59E0B, #EF4444) 1;
}
/* Note: border-image doesn't work with border-radius */

/* Method 2: Background + padding (works with border-radius) */
.gradient-border-rounded {
  position: relative;
  background: linear-gradient(135deg, #F59E0B, #EF4444);
  padding: 2px;
  border-radius: 12px;
}
.gradient-border-rounded > .inner {
  background: var(--bg);
  border-radius: 10px;
  padding: 1rem;
}

/* Method 3: Pseudo-element (most flexible) */
.gradient-border-pseudo {
  position: relative;
}
.gradient-border-pseudo::before {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: 12px;
  padding: 2px;
  background: linear-gradient(135deg, #F59E0B, #EF4444);
  -webkit-mask:
    linear-gradient(#fff 0 0) content-box,
    linear-gradient(#fff 0 0);
  -webkit-mask-composite: xor;
  mask-composite: exclude;
}

Method 2 (background + padding) is the simplest for rounded corners. Method 3 (mask-composite) is the most flexible, supporting any border radius, hover effects, and animation. The mask-based approach is now well-supported, as noted in the CSS-Tricks gradient borders guide.

8. Gradient Overlays on Images

Gradient overlays are essential for placing readable text over images. They darken, lighten, or tint the image while preserving its visual impact.

/* Dark overlay for white text */
.hero {
  background:
    linear-gradient(to bottom, rgba(0,0,0,0.2), rgba(0,0,0,0.8)),
    url('/hero.jpg') center/cover;
}

/* Color tint overlay */
.tinted-hero {
  background:
    linear-gradient(135deg, rgba(59,130,246,0.7), rgba(139,92,246,0.7)),
    url('/hero.jpg') center/cover;
}

/* Fade to background */
.fade-bottom {
  background:
    linear-gradient(to bottom, transparent 60%, var(--bg)),
    url('/hero.jpg') center/cover;
}

/* Vignette effect */
.vignette {
  background:
    radial-gradient(ellipse at center, transparent 50%, rgba(0,0,0,0.7)),
    url('/hero.jpg') center/cover;
}

Layering gradients over images in a single background shorthand is more performant than using a separate pseudo-element, since the browser composites them in a single paint operation. For accessibility, always ensure text over gradient-overlaid images meets WCAG contrast requirements โ€” check your darkest overlay point against your text color using a contrast checker.

9. Tailwind CSS Gradients

Tailwind CSS provides utility classes for gradients, making it fast to prototype gradient designs without writing custom CSS.

<!-- Basic linear gradient -->
<div class="bg-gradient-to-r from-amber-500 to-red-500">

<!-- Three-color gradient -->
<div class="bg-gradient-to-br from-blue-500 via-purple-500 to-pink-500">

<!-- Gradient text -->
<h1 class="bg-gradient-to-r from-amber-500 to-yellow-200
  bg-clip-text text-transparent">

<!-- Gradient with hover -->
<button class="bg-gradient-to-r from-amber-500 to-orange-500
  hover:from-amber-600 hover:to-orange-600">

Tailwind supports gradient direction utilities (to-r, to-br, to-t, etc.), from-/via-/to- color stops, and arbitrary values for custom angles: bg-[linear-gradient(135deg,#F59E0B,#EF4444)]. For radial and conic gradients, use arbitrary values since Tailwind doesn't have built-in utilities for those types.

Choose your gradient colors from a well-designed palette. Try Hue's palette generator to create harmonious color combinations, then map them to Tailwind color names or use arbitrary hex values.

10. Performance Considerations

CSS gradients are rendered by the browser's compositing engine, not downloaded as image files. This gives them significant performance advantages โ€” but there are still things to watch.

Gradients vs Images

A CSS gradient is essentially zero bytes over the network โ€” it's painted by the GPU at render time. A comparable PNG or JPEG gradient image might be 5-50KB plus an HTTP request. For background effects, gradients are almost always the better choice. The browser can also scale gradients perfectly to any resolution, making them naturally responsive and sharp on Retina displays.

Animation Performance

Animating gradient properties directly (changing colors or stops) triggers a repaint on every frame, which can cause jank. Instead, animate the background-position or background-size of an oversized gradient โ€” this is GPU-composited and much smoother. The animated gradient text technique in Section 6 uses this approach.

Layer Count

Stacking many gradient layers (5+) on a single element increases paint complexity. Each layer is composited separately. For complex decorative effects, consider whether a single image or SVG might be simpler. On typical modern hardware, 2-3 gradient layers are negligible. Above 5, profile with DevTools to check paint times.

Frequently Asked Questions

Do CSS gradients work in all browsers?

Linear and radial gradients have universal support. Conic gradients work in all modern browsers (Chrome 69+, Firefox 83+, Safari 12.1+). Repeating variants follow the same support. The only gradients requiring caution are newer features like in oklch interpolation, which needs Chrome 111+ and Safari 16.2+.

How do I animate a gradient smoothly?

Don't animate the gradient colors directly โ€” it causes repaints. Instead, make the gradient larger than its container (e.g., background-size: 300% 300%) and animate background-position. This is GPU-composited and buttery smooth. See the animated gradient text example in Section 6.

Why does my gradient look banded (not smooth)?

Gradient banding occurs when the color difference across a large area is too small for 8-bit color depth. Solutions: add a subtle noise overlay (SVG filter or tiny PNG), use wider color differences between stops, use the oklch() color space for perceptually smoother transitions, or add more color stops in the banding zone.

Can I use gradients with border-radius?

background gradients work perfectly with border-radius. However, border-image gradients do not respect border-radius โ€” use the background+padding or mask-composite technique from Section 7 for rounded gradient borders.

How do I create a gradient that transitions through multiple colors without looking muddy?

Muddy mid-tones happen when complementary colors mix in sRGB space (blue + yellow = gray). Use adjacent colors on the color wheel, increase the number of intermediate stops, or specify in oklch interpolation. Start with a palette generator to pick colors that transition cleanly.

Are gradients accessible?

Gradients themselves don't have WCAG requirements โ€” they're decorative. But text placed over gradients must meet contrast requirements at every point in the gradient. Test the worst-case (lowest contrast) point. If you use gradient text, verify the lightest color in the gradient meets the required ratio against the background.

13. CSS Gradient Performance

CSS gradients are GPU-rendered and avoid network requests, making them inherently performant. But like any rendering feature, they can become a bottleneck if used carelessly. Understanding how the browser processes gradients helps you make informed tradeoffs between visual complexity and frame rate.

GPU Acceleration and Compositing

Gradients applied as background properties are painted during the browser's paint phase. They're rasterized to a bitmap and composited with other layers. On modern GPUs, a simple 2-3 color gradient is negligible in cost โ€” comparable to a solid color fill. The gradient calculation happens once during paint and the result is cached until the element is invalidated (resized, scrolled into view, or its styles change).

The will-change Property

If you plan to animate a gradient element (moving it, fading it, or changing its background-position), adding will-change: transform or will-change: background-position hints to the browser that it should promote the element to its own compositor layer. This avoids repainting the parent layer during animation. However, overusing will-change wastes GPU memory โ€” only apply it to elements that actually animate.

/* Good: promote only when animating */
.gradient-bg {
  background: linear-gradient(135deg, #F59E0B, #EF4444);
  transition: background-position 0.6s ease;
}
.gradient-bg:hover {
  will-change: background-position;
  background-position: 100% 50%;
}

/* Bad: always promoting wastes GPU memory */
.gradient-bg {
  will-change: background, transform, opacity;  /* too broad */
}

Gradient vs Image Background

For any effect achievable with CSS gradients, prefer them over image files. A 1920ร—1080 gradient background image might be 15-80KB plus a network request plus decode time. The equivalent CSS gradient is zero bytes over the wire, resolution-independent (sharp on any display), and typically faster to render than decoding a JPEG. The only exception is complex photographic textures or illustrations that CSS can't replicate โ€” noise textures, hand-drawn patterns, or photorealistic effects still need images.

Profiling Gradient Performance

If you suspect gradients are causing jank, open Chrome DevTools โ†’ Performance tab โ†’ record a session while scrolling or animating. Look at the "Paint" and "Composite Layers" sections. Long paint times (>16ms per frame) indicate the gradient is too complex for the current hardware. Solutions: reduce gradient layers, simplify color stops, or replace the gradient with a pre-rendered image for that specific element. For broader page performance insights including gradient-heavy pages, tools like Clarity SEO can flag performance bottlenecks alongside their SEO impact.

14. CSS Gradient Animations

Animated gradients add life and movement to hero sections, loading states, and interactive elements. The key is animating efficiently โ€” the right technique produces smooth 60fps animations while the wrong one causes frame drops and battery drain.

The Background-Size Trick

The most performant gradient animation technique: create a gradient much larger than its container, then animate background-position. Since background-position can be GPU-composited in many browsers, this avoids the expensive repaint that animating gradient colors would cause.

/* Smooth animated gradient background */
.animated-gradient {
  background: linear-gradient(
    -45deg,
    #F59E0B, #EF4444, #8B5CF6, #3B82F6
  );
  background-size: 400% 400%;
  animation: gradient-pan 15s ease infinite;
}

@keyframes gradient-pan {
  0% { background-position: 0% 50%; }
  50% { background-position: 100% 50%; }
  100% { background-position: 0% 50%; }
}

/* Gradient shimmer loading effect */
.skeleton-loader {
  background: linear-gradient(
    90deg,
    var(--surface) 25%,
    var(--surface-2) 50%,
    var(--surface) 75%
  );
  background-size: 200% 100%;
  animation: shimmer 1.5s infinite;
}

@keyframes shimmer {
  0% { background-position: 200% 0; }
  100% { background-position: -200% 0; }
}

Hover Transitions

You can't directly transition between two different background-image gradients in CSS โ€” the property isn't animatable. But there are workarounds: layer two gradients on pseudo-elements and fade between them with opacity, or use the background-position trick to shift between color regions on hover. The CSS-Tricks gradient animation guide covers these techniques in depth.

/* Hover: shift gradient position */
.gradient-button {
  background: linear-gradient(135deg, #F59E0B 0%, #EF4444 50%, #8B5CF6 100%);
  background-size: 200% 200%;
  background-position: 0% 50%;
  transition: background-position 0.5s ease;
  color: white;
  padding: 0.75rem 1.5rem;
  border-radius: 0.75rem;
}
.gradient-button:hover {
  background-position: 100% 50%;
}

/* Hover: opacity crossfade between gradients */
.crossfade-button {
  position: relative;
  background: linear-gradient(135deg, #3B82F6, #8B5CF6);
}
.crossfade-button::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(135deg, #F59E0B, #EF4444);
  border-radius: inherit;
  opacity: 0;
  transition: opacity 0.4s ease;
}
.crossfade-button:hover::after {
  opacity: 1;
}

@property for True Color Interpolation

CSS Houdini's @property rule enables true gradient color animation by registering custom properties with a <color> syntax. The browser then knows how to interpolate between color values, making smooth gradient transitions possible for the first time.

@property --gradient-start {
  syntax: '<color>';
  initial-value: #F59E0B;
  inherits: false;
}
@property --gradient-end {
  syntax: '<color>';
  initial-value: #EF4444;
  inherits: false;
}

.houdini-gradient {
  background: linear-gradient(135deg, var(--gradient-start), var(--gradient-end));
  transition: --gradient-start 0.6s ease, --gradient-end 0.6s ease;
}
.houdini-gradient:hover {
  --gradient-start: #3B82F6;
  --gradient-end: #8B5CF6;
}

This is the most elegant solution โ€” no oversized backgrounds, no pseudo-elements. Browser support: Chrome 85+, Edge 85+, Safari 15.4+. Firefox support landed in Firefox 128+ (2024). For broader compatibility, combine @property with a fallback hover technique.

15. Gradients in Popular Frameworks

Every major CSS framework provides gradient utilities. Understanding each framework's approach helps you prototype faster and maintain cleaner code.

Tailwind CSS

Tailwind's gradient system uses three utility types: direction (bg-gradient-to-r, bg-gradient-to-br), start color (from-amber-500), optional mid-point (via-purple-500), and end color (to-pink-500). This covers the vast majority of gradient use cases with zero custom CSS.

<!-- Tailwind: horizontal gradient -->
<div class="bg-gradient-to-r from-amber-500 to-red-500 p-8 rounded-xl">

<!-- Tailwind: diagonal three-color -->
<div class="bg-gradient-to-br from-blue-500 via-purple-500 to-pink-500">

<!-- Tailwind: gradient text -->
<h1 class="bg-gradient-to-r from-amber-400 to-yellow-200
  bg-clip-text text-transparent text-4xl font-bold">
  Gradient Heading
</h1>

<!-- Tailwind: gradient with hover state -->
<button class="bg-gradient-to-r from-amber-500 to-orange-600
  hover:from-amber-600 hover:to-orange-700
  text-white px-6 py-3 rounded-lg transition-all">
  Click Me
</button>

<!-- Tailwind v4: arbitrary gradient values -->
<div class="bg-[radial-gradient(circle_at_top,#F59E0B,transparent)]">

For radial and conic gradients, Tailwind requires arbitrary values: bg-[radial-gradient(...)] or bg-[conic-gradient(...)]. Tailwind v4 (2025+) improves arbitrary value handling significantly. For gradient borders, combine Tailwind's background utilities with the padding/inner-element technique from Section 7.

Bootstrap

Bootstrap's gradient support is minimal compared to Tailwind. Enable gradients globally with $enable-gradients: true in SCSS, which adds subtle gradients to buttons and backgrounds using .bg-gradient. For custom gradients, Bootstrap expects you to write CSS directly โ€” there are no directional or color-stop utility classes. This makes Bootstrap better suited for simple gradient accents rather than complex gradient-heavy designs.

CSS-in-JS (styled-components, Emotion, Vanilla Extract)

CSS-in-JS solutions give you full CSS syntax with the added benefit of JavaScript-computed values. This is particularly powerful for gradients because you can compute gradient colors from a theme object, generate color stops dynamically, or animate gradient properties through state changes.

// styled-components: theme-aware gradient
const GradientCard = styled.div`
  background: linear-gradient(
    135deg,
    ${({ theme }) => theme.colors.primary},
    ${({ theme }) => theme.colors.secondary}
  );
  border-radius: 1rem;
  padding: 2rem;
`;

// Emotion: dynamic gradient from props
const DynamicGradient = styled.div`
  background: linear-gradient(
    ${props => props.angle}deg,
    ${props => props.from},
    ${props => props.to}
  );
`;

16. Gradient Accessibility

Gradients are decorative by nature, but the moment you place text or interactive elements over them, accessibility rules apply. Ensuring readability over gradients requires extra diligence because the background color is literally changing under your content.

Text Readability Over Gradients

When checking contrast for text over a gradient, you must test the worst-case point โ€” the position where the gradient color has the least contrast with the text. For white text over a gradient from dark blue to light blue, the light blue end is your critical test point. If that lightest point passes WCAG AA (4.5:1 for normal text), the entire gradient passes. Use Hue's contrast checker to test the lightest gradient color against your text color.

Fallback Colors

Always declare a solid background-color before your gradient. If the gradient fails to render (old browsers, email clients, high-contrast mode), the fallback ensures text remains readable:

/* Always provide a fallback color */
.hero-section {
  background-color: #1E3A5F; /* Fallback: solid dark blue */
  background-image: linear-gradient(135deg, #1E3A5F, #3B82F6);
}

/* Windows High Contrast Mode */
@media (forced-colors: active) {
  .hero-section {
    background: Canvas;
    color: CanvasText;
    border: 1px solid CanvasText;
  }
}

Reduced Motion Preferences

Animated gradients can trigger vestibular disorders (dizziness, nausea) in sensitive users. Always wrap gradient animations in a prefers-reduced-motion check. When reduced motion is preferred, either pause the animation entirely or replace it with a subtle, non-moving alternative.

@media (prefers-reduced-motion: reduce) {
  .animated-gradient {
    animation: none;
    background-size: 100% 100%; /* Reset to static */
  }
}

Gradient Information and Color Blindness

If you use gradients to encode information โ€” like a gradient scale from green to red showing health/danger โ€” users with red-green color blindness won't perceive the difference. Supplement color with labels, values, or icons. A temperature scale gradient should also include degree labels. A progress indicator should show a percentage number, not just a color change. For more on designing for color blindness, see our guide on color contrast for accessibility.

๐Ÿ“š Continue Reading

๐ŸŽจ Hue Pro coming soon
Brand guide builder, font pairing, mockup generator. Get early access.