Colours
Package:
COLOUR_PACKAGE. Registered bycreateEngine(); for a slimmer engine, register it explicitly (see choosing packages).
Colours are values. Write one as a hex literal, an rgb()/hsl() call, or a CSS
name, then lighten it, rotate its hue, mix two together, read a channel out as a
number, or check a contrast ratio against WCAG. Every colour result carries its
channels and a ready CSS string, so an editor can render an inline swatch beside
the answer, as this page does.
Function names are matched case-insensitively, so isDark, ISDARK and isdark
are the same function; the examples here use camelCase for the multi-word ones.
Writing a colour
Section titled “Writing a colour”All four CSS hex forms are literals. #rgb and #rgba expand each nibble the way
a browser does (#f00 is #ff0000), and the four- and eight-digit forms carry an
alpha channel:
#ff0000 // #ff0000#f00 // #ff0000#ff000080 // #ff000080rgb() and hsl() build a colour from channels; their rgba()/hsla() forms
add an alpha of 0 to 1. Saturation and lightness may be written with or without a
%:
rgb(255, 128, 0) // rgb(255, 128, 0)rgba(255, 0, 0, 0.5) // rgba(255, 0, 0, 0.5)hsl(210, 50, 40) // hsl(210, 50%, 40%)Two more colour wheels are available: hsv (also hsb, the value/brightness
wheel most colour pickers show) and hwb (the CSS Color 4 hue, whiteness and
blackness model). A colour built this way is the same as any other and prints as
hex:
hsv(120, 100, 100) // #00ff00hwb(0, 50, 0) // #ff8080Every CSS colour name is available through color("...") (also spelled
colour), including transparent and rebeccapurple:
color("rebeccapurple") // rebeccapurplecolor("transparent") // transparentA bare #ff0000 on its own line is a colour, not a markdown heading: a heading
always has a space after its # (# Total), and a hex colour never does. A #
followed by anything that is not exactly 3, 4, 6 or 8 hex digits (a tag like
#todo, a reference like #42) is left alone.
Reading a colour’s channels
Section titled “Reading a colour’s channels”Pull any channel out as a number. red, green and blue read the 0 to 255
sRGB channels; hue (0 to 360), saturation and lightness (0 to 100) read the
HSL channels; and alpha, given a single argument, reads the alpha rather than
setting it:
red(#3366cc) // 51green(#3366cc) // 102blue(#3366cc) // 204hue(#ff0000) // 0saturation(#ff0000) // 100lightness(#3366cc) // 50alpha(rgba(255, 0, 0, 0.5)) // 0.50Adjusting a colour
Section titled “Adjusting a colour”lighten and darken move a colour along its HSL lightness; saturate and
desaturate (also desat) along its saturation. rotate (also spin,
adjustHue) turns the hue by an angle in degrees, and complement turns it a
half-turn to the colour opposite on the wheel:
lighten(#3366cc, 20%) // #85a3e0darken(#ff0000, 20%) // #990000saturate(#8899aa, 30%) // #6999c9desaturate(#6999c9, 30%) // #8899aarotate(#ff0000, 120) // #00ff00complement(#ff0000) // #00ffffThe amount an adjuster takes reads the same whether written as a fraction, a
percent, or a bare number, so 0.2, 20% and 20 all mean a fifth.
invert (also negate) flips every channel, and grayscale (also greyscale)
drops a colour to grey by its perceived brightness:
invert(#ff0000) // #00ffffgrayscale(#3366cc) // #626262mix blends two colours; a third argument weights the blend toward the second,
defaulting to the midpoint. tint, shade and tone are the common special
cases: mixing toward white, black and mid-grey:
mix(#ff0000, #0000ff) // #800080tint(#ff0000, 50%) // #ff8080shade(#ff0000, 50%) // #800000tone(#ff0000, 50%) // #c04040alpha (also opacity, fade), given two arguments, sets transparency. A hex
colour keeps hex display and shows the alpha as #rrggbbaa:
alpha(#ff0000, 0.5) // #ff000080Contrast and accessibility
Section titled “Contrast and accessibility”contrast returns the WCAG contrast ratio between two colours (1 to 21), and
luminance returns a single colour’s relative luminance (0 to 1):
contrast(#ffffff, #000000) // 21contrast(#ffffff, #767676) // 4.54luminance(#ffffff) // 1isDark and isLight classify a background by which of black or white text
reads better on it, and readable (also contrastColor) returns that better
text colour directly:
isDark(#3366cc) // trueisLight(#ffffff) // truereadable(#3366cc) // #ffffffisContrastCompliant answers whether two colours meet a WCAG contrast bar. With
no third argument it tests the AA rule for normal text (4.5:1); a level name
("AA", "AAA", "AA large", "AAA large") or a plain number overrides that:
isContrastCompliant(#ffffff, #000000) // trueisContrastCompliant(#ffffff, #949494, "AA large") // trueisContrastCompliant(#ffffff, #767676, "AAA") // falsewcagLevel (also wcag) reports the best rating a pair reaches for normal text,
one of AAA (7:1 or better), AA (4.5), AA Large (3, which only meets AA for
large text or UI), or Fail:
wcagLevel(#ffffff, #000000) // AAAwcagLevel(#ffffff, #767676) // AAwcagLevel(#ffffff, #949494) // AA LargewcagLevel(#ffffff, #cccccc) // FailConverting between formats
Section titled “Converting between formats”as rgb, as rgba, as hsl, as hsla and as hex change how a colour prints
without touching its channels:
#ff0000 as hsl // hsl(0, 100%, 50%)#ff0000 as rgb // rgb(255, 0, 0)Two colours are equal when their channels match, regardless of how each was
written, so #ff0000 and rgb(255, 0, 0) are the same colour:
#ff0000 == rgb(255, 0, 0) // true