better-color-tools
Better color manipulation for Sass and JavaScript/TypeScript. Fast (80,000
ops/s) and lightweight (no dependencies, 4.4 kB
gzip).
Supports:
👉 Playground: https://better-color-tools.pages.dev/
Installing
npm install better-color-tools
Mix
Not all mixing algorithms are created equal. A proper color mixer requires gamma correction, something most libraries omit (even including Sass, CSS, and SVG). Compare this library’s gamma-corrected results (top) with most libraries’ default mix
function:
Notice all the bottom gradients have muddy/grayed-out colors in the middle as well as clumping (colors bunch up around certain shades or hues). But fear not! better-color-utils will always give you those beautiful, perfect color transitions you deserve.
@use 'better-color-tools' as better;
$mix: better.mix(#1a7f37, #cf222e, 0);
$mix: better.mix(#1a7f37, #cf222e, 0.25);
$mix: better.mix(#1a7f37, #cf222e, 0.5);
$mix: better.mix(#1a7f37, #cf222e, 0.75);
$mix: better.mix(#1a7f37, #cf222e, 1);
import better from 'better-color-tools';
const mix = better.mix(0x1a7f37, 0xcf222e, 0);
const mix = better.mix(0x1a7f37, 0xcf222e, 0.25);
const mix = better.mix(0x1a7f37, 0xcf222e, 0.5);
const mix = better.mix(0x1a7f37, 0xcf222e, 0.75);
const mix = better.mix(0x1a7f37, 0xcf222e, 1);
Note: 0xcf222e
in JS is just another way of writing '#cf222e'
(replacing the #
with 0x
). Either are valid; use whichever you prefer!
Advanced: gamma adjustment
To change the gamma adjustment, you can pass in an optional 4th parameter. The default gamma is 2.2
, but you may adjust it to achieve different results (if unsure, best to always omit this option).
$gamma: 2.2;
$mix: better.mix(#1a7f37, #cf222e, 0, $gamma);
const gamma = 2.2;
const mix = better.mix(0x1a7f37, 0xcf222e, 0, gamma);
Lighten / Darken
Top: better-color-utils / Bottom: RGB averaging
The lighten and darken methods also use gamma correction for improved results (also better than Sass’ color.lighten()
and color.darken()
). This method is relative, so no matter what color you start with, darken(…, 0.5)
will always be
halfway to black, and lighten(…, 0.5)
will always be halfway to white.
@use 'better-color-tools' as better;
$lighter: better.lighten(#cf222e, 0);
$lighter: better.lighten(#cf222e, 0.25);
$lighter: better.lighten(#cf222e, 1);
$darker: better.darken(#cf222e, 0);
$darker: better.darken(#cf222e, 0.25);
$darker: better.darken(#cf222e, 1);
import better from 'better-color-tools';
better.lighten(0xcf222e, 0);
better.lighten(0xcf222e, 0.25);
better.lighten(0xcf222e, 1);
better.darken(0xcf222e, 0);
better.darken(0xcf222e, 0.25);
better.darken(0xcf222e, 1);
Gradient
⚠️ Temporarily removed
This utility transformed normal, “incorrect” gradients into gamma-corrected gradients in a cross-browser-compatible way (at least, as close as one can without browser support). With the upcoming
RGB colorspace proposal, however, this tool has been temporarily removed so that it can be reworked into a sort of polyfill for that. Look for it in an upcoming
release!
Lightness
Don’t use HSL for lightness; use this!
@use 'better-color-tools' as better;
$background: #174fd2;
$is-dark: better.lightness($background) < 0.5;
.card {
@if $is-dark {
color: white;
} @else {
color: black;
}
}
import better from 'better-color-tools;
const DARK_PURPLE = '#542be9';
// lightness: get human-perceived brightness of a color (blues will appear darker than reds and yellows, e.g.)
better.lightness(DARK_PURPLE); // 0.3635 (~36% lightness)
// luminance: get absolute brightness of a color (this may not be what you want!)
better.luminance(DARK_PURPLE); // 0.0919 (~9% luminance)
// HSL (for comparison)
better.from(DARK_PURPLE).hslVal[3]; // 0.5412 (54%!? there’s no way this dark purple is that bright!)
Other Tools
Sass
P3
The p3()
function can convert any Sass-readable color into P3:
@use 'better-color-tools' as better;
$green: #00ff00;
$blue: #0000ff;
color: better.p3($green);
background: linear-gradient(135deg, better.p3($green), better.p3($blue));
Fallback Mixin
The fallback mixin can be used to easily support advanced color modes:
@use 'better-color-tools' as better;
.button {
@include better.fallback(background, better.p3(#174fd2), #174fd2);
}
JavaScript / TypeScript
better.from()
takes any valid CSS string, hex number, or RGBA array (values normalized to 1
) as an input, and can generate any desired output as a result:
import better from 'better-color-tools';
better.from('rgb(196, 67, 43)').hex;
better.from('rebeccapurple').hsl;
Code | Type | Example |
---|
better.from(…).hex | string | "#ffffff" |
better.from(…).hexVal | number | 0xffffff |
better.from(…).rgb | string | "rgb(255, 255, 255)" |
better.from(…).rgbVal | number[] | [1, 1, 1, 1] |
better.from(…).rgba | string | "rgba(255, 255, 255, 1)" |
better.from(…).hsl | string | "hsl(360, 0%, 100%)" |
better.from(…).hslVal | number[] | [360, 0, 1, 1]" |
better.from(…).p3 | string | "color(display-p3 1 1 1)" |
A note on HSL
HSL is lossy when rounding to integers, so for that reason this library will always preserve decimals in HSL, and there’s no way to disable this.
A note on CSS color names
This library can convert FROM a CSS color name, but can’t convert INTO one (as over 99% of colors have no standardized name). However, you may import better-color-tools/dist/css-names.js
for an easy-to-use map for your purposes.
A note on P3
When converting to or from P3, this library converts “lazily,” meaning the R/G/B channels are converted 1:1. This differs from some conversions which attempt to simulate hardware differences (such as colorjs.io). For the most part, the “lazy” approach
makes P3 much more usable for general purpose and for that reason is the approach recommended by Apple for Safari.
TODO / Roadmap
- Planned: LAB conversion
- Planned: Web Colorspace gradient polyfill (Sass & TS)