Browse the docs

silk.color.color.

Colors in the CSS Color 4 color spaces, with conversion, gamut mapping, mixing, adjustment, and contrast measurement.

When to use#

Use Color whenever a color is more than four channels to copy: to convert between sRGB, Display P3, Oklch, Lab, HSL, and the other ColorSpace values, to interpolate gradient stops, to derive hover and pressed shades of a theme color, or to check that text is readable on its background. Use to to convert, toGamut or toRgba to get displayable channels, mix to interpolate, lighten, darken, saturate, and rotateHue to adjust, and contrastRatio to measure legibility.

Details#

A color is a ColorSpace, three components, and an alpha, all public and in f64. Components use the CSS Color 4 reference ranges, except that percentages are fractions in [0, 1]:

  • RGB spaces (Srgb, SrgbLinear, DisplayP3, A98Rgb, ProphotoRgb, Rec2020): red, green, and blue in [0, 1] inside the gamut.

  • XyzD65 and XyzD50: X, Y, and Z, with Y 1 for the reference white.

  • Lab: lightness in [0, 100], then a and b, roughly in [-125, 125]. Lch: lightness, chroma from 0, then hue in degrees.

  • Oklab: lightness in [0, 1], then a and b, roughly in [-0.4, 0.4]. Oklch: lightness, chroma from 0, then hue in degrees.

  • Hsl: hue in degrees, saturation and lightness in [0, 1]. Hwb: hue in degrees, whiteness and blackness in [0, 1].

A NaN component or alpha is a missing component, which CSS writes as none. Conversion reads a missing component as zero. mix instead takes it from the other color, as CSS Color 4 interpolation requires. Conversion into a polar space marks the hue of an achromatic color, such as white or gray, as missing, because no hue describes it.

Conversion goes through CIE XYZ with the D65 white point, using the matrices and transfer functions of the CSS Color 4 sample code. Lab and ProPhoto use a D50 white and a Bradford adaptation. Conversion never clips: a color outside the gamut of the target space gets components outside [0, 1]. toGamut and toRgba map it into the gamut with the CSS Color 4 algorithm, which lowers Oklch chroma until the color fits and keeps lightness and hue.

Gotchas#

Missing components are NaN, so == on two components or a direct arithmetic step can give NaN. Read a hue through isMissing first, or use approxEquals, which treats two missing components as equal.

Examples#

Derive theme shades and check text contrast#

silk
import silk.color.color { Color, ColorSpace, Interpolation }

pub fn main() -> i32 {
  let brand = Color.fromHex(0x3366cc)
  let hover = brand.lighten(0.08)
  let border = brand.mix(Color.white(), 0.5, Interpolation.new(ColorSpace.Oklab))
  if hover.space != ColorSpace.Srgb || border.space != ColorSpace.Oklab {
    return 1
  }
  if Color.white().contrastRatio(brand) < 4.5 {
    return 2
  }
  let channels = brand.to(ColorSpace.Oklch).toRgba()
  if channels.b < 0.79 || channels.b > 0.81 {
    return 3
  }
  return 0
}

See also#

Use silk.color.rgba for plain straight or premultiplied channels, and silk.color.srgb for the sRGB transfer function alone.

Import as Color with import silk.color.color { Color }.

Public declarations: 4.

ColorSpace#

silk
pub enum ColorSpace

A color space from CSS Color 4: the meaning and range of the three components of a Color.

Details#

Each value names the space that CSS writes in color(), a color function, or an interpolation method. Percentages are fractions here, so HSL saturation 50% is 0.5.

Srgb#

silk
Srgb

Gamma-encoded sRGB: red, green, and blue in [0, 1]. The space of CSS hex colors and rgb().

SrgbLinear#

silk
SrgbLinear

sRGB primaries with linear-light channels in [0, 1], for physically correct blending.

DisplayP3#

silk
DisplayP3

Display P3: the wider gamut of modern displays, with the sRGB transfer function.

A98Rgb#

silk
A98Rgb

Adobe RGB (1998), the a98-rgb space of CSS.

ProphotoRgb#

silk
ProphotoRgb

ProPhoto RGB, a very wide gamut with a D50 white point.

Rec2020#

silk
Rec2020

ITU-R BT.2020 primaries with a 2.4 gamma, the rec2020 space of CSS.

XyzD50#

silk
XyzD50

CIE XYZ with the D50 white point.

XyzD65#

silk
XyzD65

CIE XYZ with the D65 white point, the hub of every conversion.

Lab#

silk
Lab

CIE Lab (D50): lightness in [0, 100], then the a (green to red) and b (blue to yellow) axes.

Lch#

silk
Lch

CIE LCh (D50): lightness in [0, 100], chroma from 0, and hue in degrees.

Oklab#

silk
Oklab

Oklab: perceptual lightness in [0, 1], then the a and b axes, roughly in [-0.4, 0.4].

Oklch#

silk
Oklch

Oklch: Oklab lightness in [0, 1], chroma from 0, and hue in degrees.

Hsl#

silk
Hsl

HSL over sRGB: hue in degrees, saturation and lightness in [0, 1].

Hwb#

silk
Hwb

HWB over sRGB: hue in degrees, whiteness and blackness in [0, 1].

HueInterpolation#

silk
pub enum HueInterpolation

The way mix interpolates hue in a polar space: the arc it takes around the hue circle.

Details#

The values match the hue interpolation methods of CSS Color 4. They have no effect when the interpolation space has no hue.

Shorter#

silk
Shorter

Takes the arc of at most 180 degrees, the CSS default.

Longer#

silk
Longer

Takes the arc of at least 180 degrees, the long way around.

Increasing#

silk
Increasing

Moves toward increasing hue angles, wrapping from 360 to 0.

Decreasing#

silk
Decreasing

Moves toward decreasing hue angles, wrapping from 0 to 360.

Interpolation#

silk
pub struct Interpolation

The color space and hue method in which mix interpolates two colors.

When to use#

Use Interpolation.new(ColorSpace.Oklab) for even gradients without hue shifts, which is the CSS default. Use ColorSpace.Oklch to keep colors saturated through the middle of a gradient, and ColorSpace.SrgbLinear to match physical light mixing.

Details#

The fields are public. A hue method only affects polar spaces: Lch, Oklch, Hsl, and Hwb.

Field space#

silk
pub space: ColorSpace

The color space in which components are interpolated, and the space of the result.

Field hue#

silk
pub hue: HueInterpolation

The arc taken around the hue circle in a polar space.

Implementation Copy for Interpolation#

silk
impl Copy for Interpolation

Implementation Interpolation#

silk
impl Interpolation

Associated function new#

silk
pub fn new(space: ColorSpace) -> Interpolation

Returns the interpolation in space with the shorter hue arc, the CSS default.

Associated function withHue#

silk
pub fn withHue(space: ColorSpace, hue: HueInterpolation) -> Interpolation

Returns the interpolation in space with the hue arc hue.

Color#

silk
pub struct Color

A color: three components in a ColorSpace and an alpha.

When to use#

Use Color to convert between color spaces, map wide-gamut colors to a display, interpolate gradient stops, derive shades, and measure contrast. Use silk.color.rgba.Rgba for channels that only need to be stored or uploaded.

Details#

The fields are public. Component ranges depend on space: RGB spaces use [0, 1], Lab and Lch lightness use [0, 100], Oklab and Oklch lightness use [0, 1], hues are in degrees, and HSL and HWB percentages are fractions in [0, 1]. Alpha is in [0, 1] and straight, not premultiplied.

A NaN component or alpha is missing, as CSS none: conversion reads it as zero and mix takes the value from the other color. Conversion into a polar space marks the hue of an achromatic color as missing.

Gotchas#

Two missing components are NaN and never compare equal with ==. Compare colors with approxEquals.

Field space#

silk
pub space: ColorSpace

The color space that gives components their meaning.

Field components#

silk
pub components: [f64; 3]

The three components in the order CSS writes them for space. NaN marks a missing component.

Field alpha#

silk
pub alpha: f64

The opacity in [0, 1], straight rather than premultiplied. NaN marks a missing alpha.

Implementation Copy for Color#

silk
impl Copy for Color

Implementation Color#

silk
impl Color

Associated function new#

silk
pub fn new(space: ColorSpace, components: [f64; 3], alpha: f64) -> Color

Returns the color with components in space and opacity alpha.

Details#

The values are stored as given. Pass f64.NAN for a component that CSS would write as none.

Associated function srgb#

silk
pub fn srgb(r: f64, g: f64, b: f64, alpha: f64) -> Color

Returns the gamma-encoded sRGB color with red r, green g, blue b, and opacity alpha, each in [0, 1].

Associated function srgbLinear#

silk
pub fn srgbLinear(r: f64, g: f64, b: f64, alpha: f64) -> Color

Returns the linear-light sRGB color with red r, green g, blue b, and opacity alpha, each in [0, 1].

Associated function displayP3#

silk
pub fn displayP3(r: f64, g: f64, b: f64, alpha: f64) -> Color

Returns the Display P3 color with red r, green g, blue b, and opacity alpha, each in [0, 1].

Associated function hsl#

silk
pub fn hsl(h: f64, s: f64, l: f64, alpha: f64) -> Color

Returns the HSL color with hue h in degrees, saturation s and lightness l in [0, 1], and opacity alpha.

Gotchas#

Saturation and lightness are fractions: CSS hsl(210 50% 40%) is Color.hsl(210.0, 0.5, 0.4, 1.0).

Associated function hwb#

silk
pub fn hwb(h: f64, w: f64, b: f64, alpha: f64) -> Color

Returns the HWB color with hue h in degrees, whiteness w and blackness b in [0, 1], and opacity alpha.

Details#

When w + b is at least 1, the color is the gray w / (w + b) and the hue has no effect.

Associated function lab#

silk
pub fn lab(l: f64, a: f64, b: f64, alpha: f64) -> Color

Returns the CIE Lab color with lightness l in [0, 100], axes a and b, and opacity alpha.

Associated function lch#

silk
pub fn lch(l: f64, c: f64, h: f64, alpha: f64) -> Color

Returns the CIE LCh color with lightness l in [0, 100], chroma c, hue h in degrees, and opacity alpha.

Associated function oklab#

silk
pub fn oklab(l: f64, a: f64, b: f64, alpha: f64) -> Color

Returns the Oklab color with lightness l in [0, 1], axes a and b, and opacity alpha.

Associated function oklch#

silk
pub fn oklch(l: f64, c: f64, h: f64, alpha: f64) -> Color

Returns the Oklch color with lightness l in [0, 1], chroma c, hue h in degrees, and opacity alpha.

When to use#

Use Oklch to author palettes: equal steps in lightness look equally spaced, and changing hue keeps perceived lightness.

Associated function fromHex#

silk
pub fn fromHex(value: u32) -> Color

Returns the opaque sRGB color written in hex as 0xRRGGBB.

When to use#

Use fromHex for colors copied from a design tool, such as Color.fromHex(0x3366cc).

Gotchas#

Bits above the low 24 are ignored, so an 0xRRGGBBAA value gives the wrong color. Use fromHexAlpha when the value has an alpha byte.

Associated function fromHexAlpha#

silk
pub fn fromHexAlpha(value: u32) -> Color

Returns the sRGB color written in hex as 0xRRGGBBAA, whose low byte is the opacity.

Associated function parseHex#

silk
pub fn parseHex(text: string) -> Option<Color>

Returns the sRGB color of a CSS hex color, or None when text is not one.

Details#

Accepts three, four, six, or eight hex digits after an optional #, in either case: #rgb, #rgba, #rrggbb, and #rrggbbaa. A short digit is repeated, so #f80 is #ff8800.

Associated function fromRgba#

silk
pub fn fromRgba(rgba: Rgba<f64>) -> Color

Returns the gamma-encoded sRGB color with the straight-alpha channels of rgba.

Associated function fromLinearRgba#

silk
pub fn fromLinearRgba(rgba: Rgba<f64>) -> Color

Returns the linear-light sRGB color with the straight-alpha channels of rgba.

Associated function black#

silk
pub fn black() -> Color

Returns opaque sRGB black.

Associated function white#

silk
pub fn white() -> Color

Returns opaque sRGB white.

Associated function transparent#

silk
pub fn transparent() -> Color

Returns fully transparent sRGB black, the CSS transparent keyword.

Method isMissing#

silk
pub fn isMissing(self: Self, index: usize) -> bool

Returns true when component index, from 0 to 2, is missing (NaN).

Details#

A missing component is the CSS none value. Conversion into a polar space also marks the hue of an achromatic color as missing.

Method withAlpha#

silk
pub fn withAlpha(self: Self, alpha: f64) -> Color

Returns the color with the same space and components and opacity alpha.

Method to#

silk
pub fn to(self: Self, space: ColorSpace) -> Color

Returns the color converted to space, without gamut mapping.

Details#

Missing components read as zero, and alpha is copied, including a missing alpha. A conversion to the same space returns the color unchanged. A conversion into Lch, Oklch, Hsl, or Hwb marks the hue missing when the color is achromatic. The result can lie outside the gamut of space; use toGamut to bring it inside.

Conversion among Srgb, SrgbLinear, Hsl, and Hwb, between Lab and Lch, and between Oklab and Oklch uses the direct formulas. Every other conversion goes through CIE XYZ (D65).

Method inGamut#

silk
pub fn inGamut(self: Self, space: ColorSpace) -> bool

Returns true when the color lies inside the gamut of space, within 1e-9 per channel.

Details#

For an RGB space, every channel must be in [0, 1]. Hsl and Hwb use the sRGB gamut. Lab, Lch, Oklab, Oklch, XyzD50, and XyzD65 hold every color, so the result is true.

Method toGamut#

silk
pub fn toGamut(self: Self, space: ColorSpace) -> Color

Returns the color converted to space and mapped into its gamut with the CSS Color 4 algorithm.

When to use#

Use toGamut before displaying a color from a wider space, such as an Oklch value with high chroma or a Display P3 color on an sRGB screen.

Details#

A color already inside the gamut is converted exactly. Otherwise the algorithm keeps Oklch lightness and hue, and searches for the largest chroma whose clipped color is within a just noticeable difference (deltaEOK of 0.02) of the unclipped one. Lightness of 1 or more maps to white and 0 or less to black. Hsl and Hwb map into the sRGB gamut. Spaces without a gamut (Lab, Lch, Oklab, Oklch, XyzD50, XyzD65) return the plain conversion. Alpha is copied unchanged.

Method toRgba#

silk
pub fn toRgba(self: Self) -> Rgba<f64>

Returns the straight-alpha gamma-encoded sRGB channels of the color, mapped into the sRGB gamut.

When to use#

Use toRgba to hand a color to a CSS-style renderer or to pack it into bytes. Use toLinearRgba for linear-light blending and GPU pipelines.

Details#

The color is mapped with the CSS Color 4 gamut-mapping algorithm, so every channel is in [0, 1]. A missing alpha becomes 1, and alpha is clamped to [0, 1].

Method toLinearRgba#

silk
pub fn toLinearRgba(self: Self) -> Rgba<f64>

Returns the straight-alpha linear-light sRGB channels of the color, mapped into the sRGB gamut.

When to use#

Use toLinearRgba for physically based blending and for GPU pipelines that render to an sRGB surface format. Premultiply the result before compositing.

Details#

The color is mapped with the CSS Color 4 gamut-mapping algorithm, so every channel is in [0, 1]. A missing alpha becomes 1, and alpha is clamped to [0, 1].

Method mix#

silk
pub fn mix(self: Self, other: Color, t: f64, interpolation: Interpolation) -> Color

Returns the color t of the way from self to other, interpolated as CSS Color 4 specifies.

When to use#

Use mix for gradient stops, transitions, and blends between theme colors. t = 0.5 with Interpolation.new(ColorSpace.Oklab) is CSS color-mix(in oklab, self, other).

Details#

The result is in interpolation.space. Both colors are converted to that space. A component missing in one color takes the other's value, including a missing component carried over from an analogous component of the original space, such as a missing hue or lightness. Components are premultiplied by alpha (except hue), interpolated linearly, and divided by the interpolated alpha. Hues follow interpolation.hue. t outside [0, 1] extrapolates.

Gotchas#

The result is not gamut mapped. Call toGamut or toRgba before display, because an interpolation in Oklch or Lab can leave the sRGB gamut.

Method lighten#

silk
pub fn lighten(self: Self, amount: f64) -> Color

Returns the color with Oklch lightness raised by amount, in the color's own space.

When to use#

Use lighten for hover states and lighter palette steps. Because Oklch lightness is perceptual, the same amount looks like the same step for every hue.

Details#

The color is converted to Oklch, lightness becomes l + amount clamped to [0, 1], and the result is converted back to the original space. Chroma and hue are unchanged, so a light, saturated result can leave the gamut of an RGB space; call toGamut before display.

Method darken#

silk
pub fn darken(self: Self, amount: f64) -> Color

Returns the color with Oklch lightness lowered by amount, in the color's own space.

When to use#

Use darken for pressed states and darker palette steps.

Details#

The color is converted to Oklch, lightness becomes l - amount clamped to [0, 1], and the result is converted back to the original space. Chroma and hue are unchanged; call toGamut before display.

Method saturate#

silk
pub fn saturate(self: Self, amount: f64) -> Color

Returns the color with Oklch chroma raised by amount, in the color's own space.

Details#

The color is converted to Oklch, chroma becomes c + amount with a floor of zero, and the result is converted back. Oklch chroma of saturated sRGB colors is about 0.1 to 0.32, so useful amounts are small, such as 0.02. An achromatic color has no hue, so it gains chroma toward a hue of zero (pink). The result can leave the gamut of an RGB space; call toGamut before display.

Method desaturate#

silk
pub fn desaturate(self: Self, amount: f64) -> Color

Returns the color with Oklch chroma lowered by amount, with a floor of zero, in the color's own space.

Details#

The color is converted to Oklch, chroma becomes max(c - amount, 0), and the result is converted back. Lightness and hue are unchanged.

Method rotateHue#

silk
pub fn rotateHue(self: Self, degrees: f64) -> Color

Returns the color with its Oklch hue turned by degrees, in the color's own space.

Details#

The color is converted to Oklch, the hue becomes h + degrees wrapped into [0, 360), and the result is converted back. An achromatic color is returned unchanged in value. Rotating by 180 gives the complementary color at the same lightness and chroma, which can leave the gamut of an RGB space.

Method grayscale#

silk
pub fn grayscale(self: Self) -> Color

Returns the gray with the same Oklch lightness, in the color's own space.

Details#

Oklch chroma becomes zero, so the result has the perceived lightness of the original. In a polar space the hue of the result is missing.

Method invert#

silk
pub fn invert(self: Self) -> Color

Returns the sRGB negative of the color, in the color's own space.

Details#

The color is mapped into the sRGB gamut, each gamma-encoded channel becomes 1 - channel, and the result is converted back. Alpha is unchanged. This matches the CSS invert(1) filter.

Method relativeLuminance#

silk
pub fn relativeLuminance(self: Self) -> f64

Returns the WCAG 2 relative luminance of the color, from 0 for black to 1 for white.

Details#

The color is mapped into the sRGB gamut, decoded to linear light, and weighted by 0.2126 R + 0.7152 G + 0.0722 B. Alpha is ignored; composite a translucent color over its background first.

Method contrastRatio#

silk
pub fn contrastRatio(self: Self, other: Color) -> f64

Returns the WCAG 2 contrast ratio between the two colors, from 1 for equal luminance to 21 for black on white.

When to use#

Use contrastRatio to check text legibility. WCAG AA asks for at least 4.5 for body text and 3 for large text and interface components; AAA asks for 7 and 4.5.

Details#

The ratio is (lighter + 0.05) / (darker + 0.05) of the two relative luminances, so the order of the colors does not matter. Alpha is ignored; composite translucent colors first.

Method deltaEOK#

silk
pub fn deltaEOK(self: Self, other: Color) -> f64

Returns the CSS Color 4 deltaEOK difference: the Euclidean distance between the two colors in Oklab.

When to use#

Use deltaEOK to ask whether two colors look the same. A value below 0.02 is about one just noticeable difference.

Details#

Missing components read as zero. Alpha is ignored.

Method approxEquals#

silk
pub fn approxEquals(self: Self, other: Color, tolerance: f64) -> bool

Returns true when both colors are in the same space and every component and alpha differ by at most tolerance.

Details#

Two missing components compare equal, and a missing component never equals a present one. Hues compare around the circle, so 359.9 and 0.1 differ by 0.2. Colors in different spaces are never equal; convert one with to first.

Category: Color.

Profiles: aarch64-apple-darwin, aarch64-unknown-linux-gnu, aarch64-unknown-linux-gnu-no-libc, x86_64-unknown-linux-gnu, x86_64-unknown-linux-gnu-no-libc, wasm32-unknown-unknown, wasm32-wasip1, wasm32-wasip2, x86_64-pc-windows-msvc, wasm64-unknown-unknown.

View the source of this page