better-color-tools
Better color manipulation for Sass and JavaScript/TypeScript.
Installing
npm install better-color-tools
Sass
Sass has built-in color functions, but they aren’t as usable as they could be. Here’s why this library exists as an alternative.
Mix
Let’s compare this library’s mix function to Sass’ (Sass on top; better-color-tools on bottom):
Blend | Comparison |
---|
red–lime | |
red–yellow | |
blue–yellow | |
blue–fuchsia | |
blue–lime | |
It may be hard to tell a difference at first, but upon closer inspection you’ll see better results with the bottom colors in each row:
- better-color-utils produces brighter, more vibrant colors when mixing complementary colors, while Sass results in dark, muddy colors (compare mid tones in all examples)
- better-color-utils gives better spacing between colors while Sass inconsistently clumps certain hues together (compare blues in all examples)
- better-color-utils produces more expected colors than Sass (compare how better-color-tools passes through teal in blue–lime while Sass doesn’t)
Usage
@use 'better-color-tools' as color;
$mix: color.mix(#1a7f37, #cf222e, 0.4);
Lighten / Darken
⚠️ Still in development. It’s important to note that Sass’ new color.scale()
tool is pretty advanced, and is actually good way to lighten / darken colors (previous methods have been lacking). Right now Sass’ color.scale()
produces
better results than this library, and I’m not happy with that 🙂.
@use 'better-color-tools' as color;
$lighter: color.lighten(#cf222e, 0.25);
$darker: color.darken(#cf222e, 0.25);
JavaScript / TypeScript
Mix
View comparison (Sass’ mix function is a generic implementation of mixing you’ll find with other libraries in JavaScript)
import color from 'better-color-tools';
const mix = color.mix('#1a7f37', '#cf222e', 0.4);
Lighten / Darken
⚠️ In development (see note)
import color from 'better-color-tools';
const lighter = color.lighten('#cf222e', 0.5);
const darker = color.darken('#cf222e', 0.5);
Conversion
Color conversion between RGB and hexadecimal is a trivial 1:1 conversion, so this library isn’t better than any other in that regard.
It’s in HSL handling where approaches differ. Because HSL is a smaller color space than RGB, in order to use it, it requires some use of decimals. So any library that rounds out-of-the-box will yield different results.
Compare this library to color-convert, converting from RGB -> HSL -> RGB
const original = [167, 214, 65];
color.from(color.from(original).hsl).rgb;
convert.hsl.rgb(convert.rgb.hsl(...original));
2 things are the cause of the difference:
- JavaScript’s rounding errors. Many implementations are borrowed from other languages that don’t have JavaScript’s “bad math.” This implementation was written with JavaScript in mind and minimizes decimal calculations through
tricks like normalizing to
255
rather than 1.
- No rounding by default. As stated before, HSL requires decimal places to produce the full RGB color space. When a library rounds by default it will always make HSL conversions inaccurate. This is a known limitation, so libraries like
color-convert will allow you to use decimals. But that generates numbers like
hsl(78.9261744966443, 64.50216450216452%, 54.70588235294118%)
. Compare that to better-color-tools: hsl(78.926, 64.5%, 54.7%)
. Why do you have to choose between accuracy
and utility?
Usage
import color from 'better-color-tools';
color.from('rgb(196, 67, 43)').hex;
color.from([196, 67, 43]).hex;
color.from('rgb(196, 67, 43)').hexVal;
color.from('#C4432B').rgb;
color.from(0xc4432b).rgb;
color.from('#C4432B').rgbVal;
color.from('#C4432B').rgba;
color.from(0xc4432b).rgba;
color.from('#C4432B').rgbaVal;
color.from('#C4432B').hsl;
color.from(0xc4432b).hsl;
color.from('#C4432B').hslVal;
color.from('rebeccapurple').hex;