Skip to content

Tailwind CSS v4 Color Palette — CSS Color Function and Dynamic Colors

DodaTech Updated 2026-06-28 5 min read

In this tutorial, you will learn about Tailwind CSS v4 Color Palette. We cover key concepts, practical examples, and best practices to help you master this topic.

Tailwind CSS v4 color system leverages modern CSS color functions like oklch, hsl, and color-mix for dynamic palette generation, improved opacity handling, and accessible color combinations.

What You'll Learn

You will learn how to use CSS color functions in @theme, generate shade scales with oklch, use color-mix for dynamic variants, and create accessible color palettes.

Why It Matters

Modern color functions produce more perceptually uniform palettes. DodaTech's v4 color system uses oklch for consistent lightness across hues, improving Accessibility.

Real-World Use

Durga Antivirus Pro's color palette uses oklch in @theme to generate 10 shades per color with mathematically consistent lightness, replacing hand-picked shade scales.

flowchart LR
    A[Custom Themes] --> B[Color Palette]
    B --> C[OKLCH Colors]
    B --> D[Color Mix]
    B --> E[Shade Generation]
    B --> F[Accessibility]
    style B fill:#38bdf8,stroke:#0284c7,color:#fff
    style C fill:#22c55e,stroke:#16a34a,color:#fff

OKLCH Color Syntax

/* oklch: perceptually uniform color space */
@theme {
  --color-brand-500: oklch(0.5 0.2 270);
  --color-brand-600: oklch(0.45 0.22 270);
  --color-brand-700: oklch(0.4 0.24 270);

  /* With explicit lightness */
  --color-primary: oklch(0.6 0.15 250);
  --color-secondary: oklch(0.55 0.1 200);
  --color-accent: oklch(0.65 0.2 330);
}
<div class="bg-brand-500 text-white p-6 rounded-lg">
  OKLCH brand color (perceptually uniform)
</div>

Expected output: OKLCH colors appear in Tailwind utilities. OKLCH provides better perceptual uniformity than sRGB, meaning equal lightness differences look equal to the human eye.

Dynamic Shade Generation

@theme {
  /* Define a base hue once */
  --hue-brand: 270;

  /* Generate shades with consistent lightness steps */
  --color-brand-50: oklch(0.95 0.05 var(--hue-brand));
  --color-brand-100: oklch(0.9 0.08 var(--hue-brand));
  --color-brand-200: oklch(0.8 0.12 var(--hue-brand));
  --color-brand-300: oklch(0.7 0.15 var(--hue-brand));
  --color-brand-400: oklch(0.6 0.18 var(--hue-brand));
  --color-brand-500: oklch(0.5 0.2 var(--hue-brand));
  --color-brand-600: oklch(0.4 0.2 var(--hue-brand));
  --color-brand-700: oklch(0.3 0.18 var(--hue-brand));
  --color-brand-800: oklch(0.2 0.15 var(--hue-brand));
  --color-brand-900: oklch(0.12 0.1 var(--hue-brand));
  --color-brand-950: oklch(0.08 0.05 var(--hue-brand));
}

Expected output: Changing --hue-brand from 270 (purple) to 200 (blue) regenerates the entire shade palette. Each shade has consistent lightness values.

Color Mix for Variants

/* Dynamic color variants using color-mix */
@theme {
  --color-primary: oklch(0.5 0.2 250);
  --color-primary-hover: color-mix(in oklch, var(--color-primary), black 15%);
  --color-primary-active: color-mix(in oklch, var(--color-primary), black 25%);
  --color-primary-light: color-mix(in oklch, var(--color-primary), white 80%);
  --color-primary-subtle: color-mix(in oklch, var(--color-primary), white 90%);
}
<button class="bg-primary hover:bg-primary-hover active:bg-primary-active text-white px-4 py-2 rounded-lg">
  Dynamic color variants
</button>

Expected output: Button hover and active states are generated from the primary color using color-mix. Changing the primary color automatically updates all states.

Perceptually Accessible Palettes

/* Ensure WCAG AA contrast with OKLCH */
@theme {
  --color-bg: oklch(0.98 0 0);
  --color-text: oklch(0.2 0 0);

  /* Interactive colors with guaranteed contrast */
  --color-action: oklch(0.5 0.2 250);
  --color-action-text: oklch(0.95 0 0);
  --color-action-hover: oklch(0.45 0.22 250);

  /* Feedback colors */
  --color-success-bg: oklch(0.9 0.1 140);
  --color-success-text: oklch(0.3 0.12 140);
  --color-error-bg: oklch(0.9 0.1 25);
  --color-error-text: oklch(0.3 0.15 25);
}

Expected output: OKLCH's perceptual uniformity makes it easier to predict contrast ratios. A lightness difference of 0.5 (50 percent) between text and background guarantees WCAG AA contrast.

HSL Color Alternative

/* HSL is also fully supported */
@theme {
  --color-brand-500: hsl(270, 60%, 50%);
  --color-brand-600: hsl(270, 65%, 45%);
  --color-brand-700: hsl(270, 70%, 40%);

  /* With CSS variables */
  --hue: 270;
  --color-brand-500: hsl(var(--hue), 60%, 50%);
}
<div class="bg-brand-500 text-white p-4 rounded-lg">
  HSL color with hue variable
</div>

Expected output: HSL colors with a shared hue variable. Changing the hue variable shifts the entire palette.

Color Mix for Gradients

@theme {
  --color-brand: oklch(0.5 0.2 270);
  --color-accent: oklch(0.6 0.2 330);
}

/* Gradient using color-mix for intermediate stops */
.gradient-card {
  background: linear-gradient(
    135deg,
    var(--color-brand),
    color-mix(in oklch, var(--color-brand), var(--color-accent) 50%),
    var(--color-accent)
  );
}
<div class="gradient-card text-white p-8 rounded-xl">
  <h3 class="font-bold text-lg">Dynamic Gradient</h3>
  <p class="mt-2 opacity-90">Gradient changes when brand or accent colors change.</p>
</div>

Expected output: Gradients that automatically adapt when theme colors change. The color-mix creates a smooth transition between brand and accent colors.

Common Mistakes

1. Using Outdated sRGB Hex Colors

OKLCH produces more uniform palettes. sRGB hex codes work but miss the perceptual benefits of OKLCH.

2. Not Using Hue Variables

Hardcoding hues in every shade definition makes palette changes tedious. Use CSS variables for hues.

3. Ignoring Lightness Consistency

OKLCH shade scales should have consistent lightness deltas (e.g., 0.05 steps). Inconsistent lightness creates uneven palettes.

4. Over-Mixing Colors

color-mix with large percentages (50%+) of black/white can produce muddy colors. Keep mixing under 30 percent for hover states.

5. Not Testing OKLCH in All Browsers

OKLCH is supported in Chrome, Firefox, and Safari. For legacy browser support, provide fallback hex values.

Practice Questions

  1. What does oklch stand for? A perceptually uniform color space (Oklab Chroma Hue) where equal distance in values equals equal visual difference.

  2. How do you generate shade scales dynamically? Define a hue variable and use oklch with consistent lightness/chroma steps.

  3. What does color-mix do? Mixes two colors in a specified color space: color-mix(in oklch, var(--primary), black 15%).

  4. Why is OKLCH better for accessibility? Its perceptual uniformity makes contrast ratios predictable. Lightness differences directly correspond to visual contrast.

  5. Can OKLCH and HSL coexist in the same project? Yes. Different colors can use different color functions. The CSS color function does not affect other colors.

Challenge

Create a dynamic color system with: 3 brand colors using oklch with hue variables, 10-shade scales per color, color-mix for hover/active states, a color-mix gradient, and HSL alternatives for legacy support.

FAQ

Is OKLCH supported in all modern browsers?

Yes. Chrome 116+, Firefox 113+, Safari 15.4+. For older browsers, provide fallback hex/RGB values.

Can I use OKLCH with opacity?

Yes: oklch(0.5 0.2 270 / 0.5) for 50 percent opacity.

What is the difference between oklch and lab?

OKLCH is the cylindrical representation of OKLAB, similar to how HSL relates to RGB. Both are perceptually uniform.

Does color-mix work in all browsers?

color-mix() is supported in Chrome 111+, Firefox 113+, Safari 16.2+. Check caniuse for the latest support data.

Can I use color-mix with Tailwind utilities?

Not directly in class names. Use color-mix in @theme definitions and reference via custom properties.

Mini Project

Build a complete color system with: oklch-based brand palette (4 colors x 10 shades), hue variables for each brand color, color-mix for interactive states, accessible text/background pairs, and a gradient component that updates with theme changes.

What's Next

Now master Generators and Functions for dynamic design token generation. Then explore Arbitrary Values for flexible utility usage.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro