better-color-tools
Color parser and better color manipulation through the power of science! 🧪 Uses Oklab/Oklch for better color operations.
The JS version of this libray is fast (~200k
ops/s), lightweight (5 kB
gzip), and dependency-free. The Sass version… is Sass (which has no runtime).
👉 Playground: https://better-color-tools.pages.dev/
Usage
npm install better-color-tools
JavaScript
Works in the browser (ESM) and Node (14+).
Importing
import better from 'better-color-tools';
Parse
better.from('#b3f6e6'); // hex string
better.from(0xb3f6e6); // hex integer (note: only mode that doesn’t support transparency)
better.from('rebeccapurple'); // CSS keyword
better.from('rgb(136, 48, 62)'); // CSS RGB
better.from('hsl(210, 85%, 37%)'); // CSS HSL
better.from('oklab(48.56949% -0.03971 -0.14459)'); // CSS Oklab
better.from('oklch(83.11253% 0.22612 147.35276)'); // CSS Oklch
This library understands any CSS-valid color, including CSS Color Module 4 (but if some aspect isn’t implemented yet, please request it!).
Convert
This library converts to most web-compatible formatsÂą, with an emphasis on usefulness over completeness:
- sRGB (hex):
better.from('…').hex
/better.from('…').hexVal
- sRGB (RGB):
better.from('…').rgb
/better.from('–').rgbVal
- Oklab:
better.from('…').oklab
/better.from('…').oklabVal
- Oklch:
better.from('…').oklch
/better.from('…').oklchVal
- XYZ:
better.from('…').xyz
/better.from('…').xyzVal
¹The following formats aren’t supported as outputs:
- HSL isn’t supported because you shouldn’t use it
- HWB isn’t supported because it’s another form of HSL
- HSV is a great colorspace, but on no standards track for the web currently
- CIE L*a*/CIE L*C*h aren’t supported because Oklab/Oklch are superior
For a comprehensive color conversion library, see culori.
Mix
better.mix('red', 'lime', 0.35); // Mix `red` and `lime` 35%, i.e. more red
better.mix('blue', 'magenta', 0.5, 'srgb-linear'); // Mix `blue` and `magenta` 50% using srgb-linear colorspace
This uses Oklab (best) by default, but also supports oklch
, lms
, sRGB
, and linearRGB
colorspaces for mixing.
Lighten / Darken
better.lighten('red', 0.5); // Lighten color by 50%
better.darken('red', 0.5); // Darken color by 50%
This takes hue and human perception into account for visually-accurate results. Also, fun fact: both functions accept negative values.
Lightness
Get the human-perceived lightness of any color (identical to the first value of .oklabVal
)
better.lightness('#fc7030'); // 0.7063999
Manipulation
import better, { colorFn } from 'better-color-tools';
let [L, C, h] = better.from('#5a00a6').oklchVal;
h += 5; // rotate hue by 5°
C += 0.01; // increase Chroma by 1%
better.from(colorFn('oklch', [L, C, h])).hex; // #6f00ca
Manipulation is best done in a space like Oklch which is optimized for manual tweaking.
Sass
Works with any version of Dart Sass (the current version).
Importing
@use 'better-color-tools' as better;
Mix
.foo {
color: better.mix('red', 'lime', 0.35);
}
Uses Oklab for best results (which yields much better results than Sass’ mix).
Lighten / Darken
.foo:hover {
color: better.lighten('blue', 0.2);
border-color: better.darken('blue', 0.15);
}
Lightens (or darkens) color via Oklab for human-perceived lightness value (which yields much better results than Sass’ lighten/darken:
P3
.foo {
color: better.p3(#f00); // color(display-p3 1 0 0)
}
Convert any Sass-readable color to P3.
Fallback
.foo {
@include better.fallback('color', better.p3(#f00), #f00);
// color: #f00;
// color: color(display-p3 1 0 0);
}
Mixin for adding CSS fallbacks. Can take infinite arguments. Specify desired format first, followed by fallbacks.
Oklab
$oklab: better.rgbToOklab(#f00); // (l: 0.6279554, a: 0.22486, b: 0.12585)
$rgb: better.oklabToRGB($oklab); // #f00
Converts any Sass-readable color to an Oklab map of (l: …, a: …, b: –)
. The Sass map can either be used to make a CSS string:
@use 'sass:map';
.foo {
color: oklab(#{map.get($oklab, 'l')} #{map.get($oklab, 'a')} #{map.get($oklab, 'b')});
color: better.oklabToRGB($oklab); // fallback
}
Or for color manipulation:
$oklab-lighter: map.set($oklab, 'l', 0.8);
Lightness
Get the human-perceived lightness of any color (identical to the first value of .oklabVal
):
$lightness: better.lightness(#f00);
Project summary
This project is meant to provide the best possible method for common color operations such as mixing, lightening/darkening, and conversion. This library is not comprehensive, and doesn’t support any colorspaces that don’t serve a practical purpose (limiting colorspaces helps this library optimize for performance over completeness, not to mention ease-of-use). If you are well-versed in color science and need a comprehensive library, consider Culori or Color.js instead.
To learn more, see Project Goals