# 如何使用JavaScript处理CSS颜色

The mathematical formula for lightness match

Depending on the hue prime value, the `r`, `g`, and `b` values will map to `C`, `X`, and `0`:

The mathematical formula for RGB values without accounting for lightness

Lastly, we need to map each value to adjust for lightness:

The mathematical formula to account for lightness with RGB

Putting all of this together into a JavaScript function:

``````const hslToRgb = (h,s,l) => {
const C = (1 - Math.abs(2 * l - 1)) * s;
const hPrime = h / 60;
const X = C * (1 - Math.abs(hPrime % 2 - 1));
const m = l - C/2;
const withLight = (r,g,b) => [r+m, g+m, b+m];

``````

### Creating a color object

For ease of access when manipulating their attributes, we will be dealing with a JavaScript object. This can be created by wrapping the previously written functions:

``````const rgbToObject = (red,green,blue) => {
const [hue, saturation, lightness] = rgbToHsl(red, green, blue);
return {red, green, blue, hue, saturation, lightness};
}

``````

### Example

I highly encourage you to spend some time playing with this example. Seeing how each of the attributes interacts when you adjust the others can give you a deeper understanding of how the two color models fit together.

## Color manipulation

Now that we have the ability to convert between color models, let’s look at how we can manipulate these colors!

### Update attributes

Each of the color attributes we have covered can be manipulated individually, returning a new color object. For example, we can write a function that rotates the hue angle:

``````const rotateHue = rotation => ({hue, ...rest}) => {
const modulo = (x, n) => (x % n + n) % n;
const newHue = modulo(hue + rotation, 360);

``````

The `rotateHue` function accepts a `rotation` parameter and returns a new function, which accepts and returns a color object. This allows for the easy creation of new “rotation” functions:

``````const rotate30 = rotateHue(30);
const getComplementary = rotateHue(180);

``````

Along the same lines, you can write functions to `saturate` or `lighten` a color  —  or, inversely, `desaturate` or `darken`.

``````const saturate = x => ({saturation, ...rest}) => ({
...rest,
saturation: Math.min(1, saturation + x),
});

``````

### Color predicates

In addition to color manipulation, you can write “predicates”  —  that is, functions that return a Boolean value.

``````const isGrayscale = ({saturation}) => saturation === 0;
const isDark = ({lightness}) => lightness < .5;

``````

## Dealing with color arrays

### Filters

The JavaScript `[].filter` method accepts a predicate and returns a new array with all the elements that “pass.” The predicates we wrote in the previous section can be used here:

``````const colors = [/* ... an array of color objects ... */];
const isLight = ({lightness}) => lightness > .5;
const lightColors = colors.filter(isLight);

``````

### Sorting

To sort an array of colors, you first need to write a “comparator” function. This function takes two elements of an array and returns a number to denote the “winner.” A positive number indicates that the first element should be sorted first, and a negative indicates the second should be sorted first. A zero value indicates a tie.

For example, here is a function for comparing the lightness of two colors:

``````const compareLightness = (a,b) => a.lightness - b.lightness;

``````

Here is a function that compares saturation:

``````const compareSaturation = (a,b) => a.saturation - b.saturation;

``````

In an effort to prevent duplication in our code, we can write a higher-order function to return a comparison function to compare any attribute:

``````const compareAttribute = attribute =>
(a,b) => a[attribute] - b[attribute];

``````

### Averaging attributes

You can average the specific attributes of an array of colors by composing various JavaScript array methods. First, you can calculate the average of an attribute by summing with reduce and dividing by the array length:

``````const colors = [/* ... an array of color objects ... */];
const toSum = (a,b) => a + b;
const toAttribute = attribute => element => element[attribute];
const averageOfAttribute = attribute => array =>
array.map(toAttribute(attribute)).reduce(toSum) / array.length;

``````

You can use this to “normalize” an array of colors:

``````/* ... continuing */

``````
``````const normalizeAttribute = attribute => array => {
const averageValue = averageOfAttribute(attribute)(array);
const normalize = overwriteAttribute(attribute)(averageValue);
return normalize(array);
}

``````

## Conclusion

Colors are an integral part of the web. Breaking down colors into their attributes allows for the smart manipulation of colors and opens the door to all sorts of possibilities.

## Plug: LogRocket, a DVR for web apps

[

](https://logrocket.com/signup/)

https://logrocket.com/signup/

LogRocket is a frontend logging tool that lets you replay problems as if they happened in your own browser. Instead of guessing why errors happen, or asking users for screenshots and log dumps, LogRocket lets you replay the session to quickly understand what went wrong. It works perfectly with any app, regardless of framework, and has plugins to log additional context from Redux, Vuex, and @ngrx/store.

In addition to logging Redux actions and state, LogRocket records console logs, JavaScript errors, stacktraces, network requests/responses with headers + bodies, browser metadata, and custom logs. It also instruments the DOM to record the HTML and CSS on the page, recreating pixel-perfect videos of even the most complex single-page apps.