Home / Snippets / Animation & Motion /

Color shift

Smoothly transitions background color on hover across the oklch color space.

Widely Supported
animationno-jscolor

Quick implementation

.color-shift {
  background: oklch(0.52 0.22 265);
  color: oklch(0.98 0.01 260);
  transition: background-color 0.3s ease;
}

.color-shift:hover {
  background: oklch(0.58 0.20 180);
}

@media (prefers-reduced-motion: reduce) {
  .color-shift { transition: none; }
}

Prompt this to your LLM

Includes role, constraints, two framework variants, and edge cases to handle.

You are a senior frontend engineer building a CSS interaction library.

Goal: A color shift hover effect — the background-color of a button or card transitions smoothly to a new oklch hue on hover, with no JavaScript.

Technical constraints:
- Use oklch() for both the default and hover background colors.
- Transition only background-color, not all properties, for precision.
- Use transition-duration of 0.3s with ease timing.
- Ensure contrast ratio meets WCAG AA for the text color against both background states.
- Include @media (prefers-reduced-motion: reduce) to disable the transition.

Framework variant (pick one):
A) Vanilla CSS — utility class applied to any button, link, or card element.
B) React component — accept defaultColor and hoverColor as oklch string props.

Edge cases to handle:
- Text color must remain legible in both color states.
- Transition should also reverse smoothly on mouse-out (no separate :not(:hover) rule needed).
- Provide a variant that shifts hue angle only, keeping lightness and chroma constant.
- Avoid transition: all — it causes unintended transitions on other properties.

Return CSS.

Why this matters in 2026

Color shift is one of the most common hover feedbacks on interactive elements. Using oklch() means the transition travels through perceptually uniform color space — the midpoint always looks like a plausible color rather than the muddy intermediates common with rgb() or hsl() transitions. This is especially visible when shifting across hue quadrants, such as purple to teal.

The logic

The element starts with background: oklch(0.52 0.22 265) — a vivid purple — and transitions to oklch(0.58 0.20 180), a teal, on hover. The browser interpolates all three oklch channels (lightness, chroma, hue) across the 0.3 s duration. Specifying only transition: background-color rather than transition: all prevents accidental transitions on other properties like box-shadow or transform that might be set elsewhere.

Accessibility & performance

@media (prefers-reduced-motion: reduce) removes the transition so the color switches instantly — the state change is still communicated, just without motion. background-color transitions are paint-only operations; they do not trigger layout recalculations. For best accessibility, verify that both the default and hover background colors meet a minimum 4.5:1 contrast ratio against the foreground text color using a tool that understands oklch values.