<input type="color">
or its successor (see Open UI)Color
objectset()
to set multiple coords at once, or set using a functionset()
and get()
to get/set coords in other color spaces Web developers with varying levels of Color Science knowledge. Usable without error by those with little, powerful for those with much.
@color-profile
or by directly providing conversion code to and from a supported color space.This set covers the union of spaces from CSS Color 4, CSS Color HDR and Canvas HDR. All RGB spaces are defined over the extended range.
srgb
(Web legacy compatibility)srgb-linear
(as used in Canvas HDR, some GPU operations, native APIs)display-p3
(new Web)a98-rgb
(?? needed, nowadays?)prophoto-rgb
(from raw digital photos)rec2020
(streaming and broadcast)rec2020-linear
(canvas uses as connection space)
xyz-d50
(relative, D50) (for linear-light calculations)xyz-d65
(relative, D65) (for linear-light calculations)lab
(D50) (perceptual calculations)lch
(D50) (perceptual, chroma-preserving)oklab
(D65) (perceptual calculations)oklch
(D65) (perceptual, chroma-preserving)rec2100-pq
(Netflix, Canvas HDR, CSS Color HDR)rec2100-hlg
(BBC, Canvas HDR, , CSS Color HDR)rec2100-linear
(Canvas HDR, , CSS Color HDR)Sample WebIDL and algorithms moved to the draft spec.
TypeScript definitions for Level 1
For ease of use and widest applicability, coordinates are plain JavaScript number (for a single coordinate), or an array of numbers (for all coordinates in a given colorspace).
let color = new Color("rebeccapurple");
// Get individual coord in other color space
color.get("lch", "l"); // 32.4
// Get individual coord in current color space
color.get("r"); // 0.4
// Get all coords in another color space
color.to("lch").coords; // [32.4, 61.2, 309]
Converting in place:
let color = new Color("rebeccapurple");
color.colorSpace; // "srgb";
color.coords; // [0.4, 0.2, 0.6]
color = color.to("lch");
color.coords; // [32.4, 61.2, 309]
In Level 1:
color.set("lch", "l", color.get("lch", "l") * 1.2);
In Level 2, we could support more sugar, such as relative manipulations via functions:
color.set("lch", "l", l => l * 1.2);
This is straightforward, but could also be built-in as a contrast method.
let contrast;
let fg = new Color("display-p3" [1, 1, 0]); // P3 yellow
let bg = new Color("sienna"); // sRGB named color
let l1 = fg.get("xyz", "y");
let l2 = bg.get("xyz", "y");
if (l1 > l2) {
[l1, l2] = [l2, l1];
}
contrast = (l2 + 0.05) / (l1 + 0.05);
let cmyk = ColorSpace.fromICCProfile("./cmyk-profile.icc", {
name: "fogra-coated",
coords: {
c: { min: 0, max: 100 },
m: { min: 0, max: 100 },
y: { min: 0, max: 100 },
k: { min: 0, max: 100 },
}
});
let magenta = new Color(cmyk, [0, 100, 0, 0]);
let lightMagenta = magenta.set("oklch", "l", l => l * 1.2);
No, and this is by design. It complicates implementation if color spaces can "stop" being supported. What happens with all existing colors created?
Ths simplifies use of HDR, especially on platforms like WebGPU or WebGL which are not inherently color managed (all operatons happen in a single color space)
An earlier version of this draft had iccProfile
as a property of ColorSpace
objects.
However, that would require the entire API to be async, which significantly complicates use cases.
Therefore, it was deemed better to have an async ColorSpace.fromICCProfile()
method that returns a regular ColorSpace
object.