The Old Way: Hardcoded Hex Colors
I used to hardcode every color variant:
Issues & The New Approach
Previously, theming relied on manual hex calculations and HSL adjustments that weren’t perceptually uniform, leading to inconsistent brightness and contrast across components. Changing one color often required manually updating multiple variants, and dark mode had to duplicate logic with separate color sets. To solve this, the new approach combines three modern CSS features — OKLCH for perceptually uniform color definitions, color-mix() for intuitive color blending, and relative colors for generating context-aware variations (like borders, hovers, and shadows). Together, these enable dynamic, scalable theming with minimal code and perfect visual harmony across light and dark modes.
Why OKLCH?
OKLCH is perceptually uniform—equal lightness steps look equally different:
OKLCH Syntax
The OKLCH color model defines colors based on human perception rather than raw RGB values, resulting in more natural and consistent contrast across themes. Its syntax follows the structure oklch(lightness chroma hue), where Lightness ranges from 0% (black) to 100% (white), Chroma controls saturation from 0 (gray) to around 0.4+ (highly vivid), and Hue represents the position on the color wheel in degrees (0–360). This model makes it easier to adjust brightness or saturation while maintaining visual harmony, which is especially useful for generating theme variations like backgrounds, borders, and hover states.
My New Theme System
Step 1: Define Base Colors in OKLCH
Step 2: Use Relative Colors for Component Adjustments
Relative colors let you adjust individual components:
Breaking it down:
from var(--color-primary) — source color
l, c, h — lightness, chroma, hue from the source
calc(l - 0.1) — adjust lightness by 10%
Step 3: Use color-mix() for Tinting and Shading
color-mix() blends two colors:
Syntax: color-mix(in color-space, color1 percentage, color2 percentage)Why in oklch? Mixing in OKLCH keeps results perceptually uniform.
Step 4: Combine Both Techniques
The Magic: Dark Theme
Override only the base colors:
When to Use Each Technique
Use Relative Colors When:
You need precise component adjustments
You want to maintain hue/chroma relationships
You need lightness-only changes
Use color-mix() When:
You want to tint (mix with white)
You want to shade (mix with black)
You want to blend two colors
Benefits
Using OKLCH and CSS relative colors brings a series of powerful improvements to theming. First, it’s perceptually uniform, meaning OKLCH preserves consistent lightness and contrast across hues. It also results in less code, reducing the need for dozens of hardcoded color tokens down to just a few base colors with automatically derived variants. Maintenance becomes easier, since updating a single base color cascades through all related shades. Dark mode support is better and cleaner—you only override the base colors, and everything else adapts naturally. The system is also more flexible, allowing independent control over lightness, chroma, and hue to fine-tune appearance. Finally, it requires no JavaScript, keeping theming fast, lightweight, and entirely handled by CSS.
What I Learned
Working with OKLCH, color-mix(), and relative colors completely changed how I think about theming in CSS. I learned that OKLCH is absolutely worth adopting for achieving consistent color perception across hues and lightness levels. color-mix() made tinting and shading effortless compared to manual hex or HSL adjustments, while relative colors offered precise, context-aware control over component styling. Combining these techniques covers a wide range of use cases—from subtle hover states to full theme palettes. The syntax can look intimidating at first, but once you understand expressions like oklch(from var(--color) calc(l - 0.1) c h), it becomes surprisingly intuitive.
The Result
The new theme system is cleaner (less code, clearer intent), more maintainable (update one base color and all variants adjust automatically), more flexible (fine-tune relationships between shades), more consistent (thanks to perceptually uniform color math), and future-proof, leveraging modern CSS standards that are here to stay. This approach scales elegantly as designs evolve — making it both practical and powerful for modern front-end development.
Have you tried OKLCH or color-mix() in your own projects? I’d love to hear your thoughts and experiences with these new CSS color functions!

