Create a gist now

Instantly share code, notes, and snippets.

A Friendlier Approach for CSS Color Manipulation

By Chris Eppstein and Michael Parenteau

These ideas build on ones proposed by Tab Atkins but expand the concepts to apply to any color value, not just named colors.

They provide the full power of Sass's color system while preserving a more human-readable system when multiple transformations are applied because the arguments are closer to the operations.

Scaling vs Adjusting

In color manipulation there are two basic classes of operations:

  1. Adjustment: adds or subtracts an absolute amount and stops when it gets to the end point.
  2. Scaling: percent change from the current value towards the end point.

The convention used here is to use a past-tense verb for adjustment and an active tense verb for scaling.

Almost all of these operations take place in the HSL color domain (the exception being inverted which is RGB based.)

These operations can be composed in any order however, in some cases different ordering may result in a different resulting color.

Sass Implementation

While it's a bit tricky, this system can be implemented in Sass to elicit early feedback from users.

Hue modification

For named colors only, you can use an adjacent color name to transform the hue. Such operations are nonsensical for arbitrary colors.

In sass, we cannot distinguish a named color from an arbitrary color, so we'd probably just enforce this by saying that the hue of the color modifier cannot be more than 30deg away from the primary color's hue. This might make sense in CSS as well.

color(green blue) // 50% between green and blue
color(greenish blue) // 25% towards green from blue
color(blueish green) // 25% towards blue from green
color(blueish(33%) green) // 33% towards blue from green

It is handy to be able to find the compliment and inverse of a color.

color(compliment $color) // compliment color
color(inverted $color)   // inverted color

Other hue manipulations make colors warmer or cooler. We believe that generic degree manipulation of an arbitrary color is non-sensical from a design persepective.

Note: we're not sure what is the "hottest" color because there are two primary colors considered "hot": red and yellow. Yellow is the opposite hue of blue on the wheel but orange is the opposite hue of blue in terms of pigments. This will make a good bikeshed (every proposal needs one).

color(warmer $foo)        // rotate 50% percent towards orange(or yellow?) (scaling)
color(cooler $foo)        // rotate 50% percent towards blue (scaling)
color(warmer(25%) $foo)   // rotate 25% percent towards orange (scaling)
color(cooler(25%) $foo)   // rotate 25% percent towards blue (scaling)
color(warmed(30deg) $foo) // rotate 30deg percent towards orange (adjustment)
color(cooled(30deg) $foo) // rotate 30deg percent towards blue (adjustment)

Lightness modification

lightened and darkened will adjust the lightness of a color.

color(lightened $color)      // +50% lightness adjustment
color(lightened(33%) $color) // +33% lightness adjustment
color(darkened $color)       // -50% lightness adjustment
color(darkened(33%) $color)  // -33% lightness adjustment

lighter and darker will scale the lightness of a color.

color(lighter $color)      // +50% lightness scaling
color(lighter(33%) $color) // +33% lightness scaling
color(darker $color)       // -50% lightness scaling
color(darker(33%) $color)  // -33% lightness scaling

Saturation modification

saturated and desaturated will adjust the saturation of a color.

color(desaturated $color)      // -50% saturation adjustment
color(desaturated(33%) $color) // -33% saturation adjustment
color(saturated $color)        // +50% saturation adjustment
color(saturated(33%) $color)   // +33% saturation adjustment

saturate and desaturate will scale the saturation of a color.

color(desaturate $color)      // 50% saturation scaled
color(desaturate(33%) $color) // 33% saturation scaled
color(saturate $color)        // 50% saturation scaled
color(saturate(33%) $color)   // 33% saturation scaled
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment