Interpolating between themes in CSS
color-mix(), var(), calc(), pow(), min()… some pretty cool possibilities arise.
Draft: started • Tagged /css, /meta=also
Another thing that came up while I
After writing most of A few ways of specifying per-theme colours in CSS, I found I wanted to play with the color-mix(…, … var(--dark)) technique, to experiment with interpolating.
Here are some results of
Why stick with only “light mode” and “dark mode”?
Various forms of easing interpolation Linear interpolation Sine Quadratic in Quadratic out Quadratic Cubic Quartic Quadratic light, quartic dark Quartic light, linear dark Linear light, quadratic out dark For quadratic easing, we need a piecewise function. From 0 to 0.5: pow(var(--v)*2,2)/2. From 0.5 to 1: 1 - pow(var(--v)*2 - 2,2)/2. A few solutions for achieving a piecewise function: if(). Currently only implemented in the Chromium family, since mid-2025 (too risky for my liking). - Some combination of
min(), max(), abs() and sign(). Implemented in the Chromium family since the release after if(), and in Firefox and Safari since 2023 or earlier (acceptable for most purposes). - In this case, because of the nature of the function, we can use
calc(min(pow(var(--v)*2,2)/2,.5)-max(.5-pow(var(--v)*2 - 2,2)/2,0)) How do we do the “only from 0.5 to 1” thing? There are a few ways; I think the easiest uses sign(), but that only landed in the Chromium family in mid-2025. So instead, I’ll do a more convoluted thing with abs() and pow(). The easiest way is to use max(). abs(). x - abs(x - 0.5) Subtract 0.5, max( ((var(--v) - 0.5)*2)²