# `Color.CSS`

CSS Color Module Level 4 / 5 parsing and serialisation.

`parse/1` accepts any of:

* Hex — `#fff`, `#ffffff`, `#ffff` (RGBA), `#ffffffff` (RRGGBBAA).

* Named — `red`, `rebeccapurple`, `"Misty Rose"`, `:transparent`.

* `rgb()` / `rgba()` — `rgb(255 0 0)`, `rgb(255, 0, 0)`,
  `rgb(255 0 0 / 50%)`, `rgba(255 0 0 0.5)`. Both legacy
  comma-separated and modern whitespace forms are accepted.

* `hsl()` / `hsla()` — `hsl(0 100% 50%)`, `hsl(0deg 100% 50% / .5)`.

* `hwb()` — `hwb(0 0% 0%)`.

* `lab()` / `lch()` — `lab(50% 40 30)`, `lch(50% 40 30deg)`.
  The lightness accepts `%` or the raw `L` value; `lab` / `lch`
  use the CIE 1976 `L*a*b*` / `LCHab` definitions with a D50
  reference white as specified by CSS Color 4.

* `oklab()` / `oklch()` — `oklab(63% 0.2 0.1)`, `oklch(63% 0.2 30)`.

* `color()` — `color(srgb 1 0 0)`, `color(display-p3 1 0 0)`,
  `color(rec2020 1 0 0)`, `color(prophoto-rgb 1 0 0)`,
  `color(xyz-d65 0.95 1 1.09)`, `color(xyz-d50 ...)`,
  `color(a98-rgb 1 0 0)`, `color(srgb-linear 1 0 0)`.

* `device-cmyk()` *(CSS Color 5)* — `device-cmyk(0% 100% 100% 0%)`,
  `device-cmyk(0 1 1 0 / 50%)`. Returns a `Color.CMYK` struct.

* `color-mix()` *(CSS Color 5)* —
  `color-mix(in oklch, red 40%, blue)`,
  `color-mix(in lab, red, blue 30%)`. The first argument is
  `in <space>` (any space `Color.Mix.mix/4` understands); the
  remaining two are colors with optional percentages. The mixed
  result is returned in the interpolation space.

* Relative color syntax *(CSS Color 5)* — `rgb(from <color> r g b)`,
  `oklch(from <color> l c calc(h + 30))`, etc. Inside the function
  body the source color's components are bound to identifiers
  (`r`/`g`/`b` for `rgb()`, `h`/`s`/`l` for `hsl()`, `l`/`c`/`h` for
  LCH-style spaces, etc) and `alpha` is always available. Components
  may be referenced bare or wrapped in `calc()`.

* `none` keyword *(CSS Color 4)* — `rgb(none 0 0)`,
  `oklch(0.7 none 30)`. A channel of `none` is treated as the
  space's neutral default (zero in the relevant unit).

* `calc()` — `rgb(calc(255 / 2) 0 0)`,
  `lab(calc(50 + 10) 0 0)`. Inside relative-color syntax, calc()
  expressions can reference the captured component identifiers,
  e.g. `oklch(from teal calc(l + 0.1) c h)`.

`to_css/2` serialises any color struct back to one of these forms.
The default serialiser choice follows the struct type.

# `parse`

```elixir
@spec parse(String.t()) :: {:ok, struct()} | {:error, Exception.t()}
```

Parses a CSS Color 4 / 5 color string.

### Arguments

* `input` is a string.

### Returns

* `{:ok, struct}` on success.

* `{:error, reason}` otherwise.

### Examples

    iex> {:ok, c} = Color.CSS.parse("rgb(255 0 0)")
    iex> {c.r, c.g, c.b}
    {1.0, 0.0, 0.0}

    iex> {:ok, c} = Color.CSS.parse("rgb(255 0 0 / 50%)")
    iex> c.alpha
    0.5

    iex> {:ok, c} = Color.CSS.parse("hsl(120 100% 50%)")
    iex> c.h
    0.3333333333333333

    iex> {:ok, c} = Color.CSS.parse("lab(50% 40 30)")
    iex> {c.l, c.a, c.b}
    {50.0, 40.0, 30.0}

    iex> {:ok, c} = Color.CSS.parse("oklch(63% 0.2 30)")
    iex> {Float.round(c.l, 2), Float.round(c.c, 2), Float.round(c.h, 2)}
    {0.63, 0.2, 30.0}

    iex> {:ok, c} = Color.CSS.parse("color(display-p3 1 0 0)")
    iex> c.working_space
    :P3_D65

    iex> {:ok, c} = Color.CSS.parse("rgb(none 0 0)")
    iex> {c.r, c.g, c.b}
    {0.0, 0.0, 0.0}

    iex> {:ok, c} = Color.CSS.parse("rgb(calc(255 / 2) 0 0)")
    iex> Float.round(c.r, 4)
    0.5

    iex> {:ok, c} = Color.CSS.parse("device-cmyk(0% 100% 100% 0%)")
    iex> {c.c, c.m, c.y, c.k}
    {0.0, 1.0, 1.0, 0.0}

    iex> {:ok, c} = Color.CSS.parse("color-mix(in oklab, red, blue)")
    iex> c.__struct__
    Color.Oklab

    iex> {:ok, c} = Color.CSS.parse("oklch(from red calc(l + 0.1) c h)")
    iex> c.__struct__
    Color.Oklch

# `to_css`

```elixir
@spec to_css(struct(), keyword()) :: String.t()
```

Serialises a color struct as a CSS Color 4 function string.

### Arguments

* `color` is any supported color struct.

* `options` is a keyword list.

### Options

* `:as` — override the default serialiser form. One of `:rgb`,
  `:hex`, `:hsl`, `:lab`, `:lch`, `:oklab`, `:oklch`, `:color`.

### Returns

* A string.

### Examples

    iex> Color.CSS.to_css(%Color.SRGB{r: 1.0, g: 0.0, b: 0.0})
    "rgb(255 0 0)"

    iex> Color.CSS.to_css(%Color.SRGB{r: 1.0, g: 0.0, b: 0.0, alpha: 0.5})
    "rgb(255 0 0 / 0.5)"

    iex> Color.CSS.to_css(%Color.SRGB{r: 1.0, g: 0.0, b: 0.0}, as: :hex)
    "#ff0000"

    iex> Color.CSS.to_css(%Color.Oklch{l: 0.63, c: 0.2, h: 30.0})
    "oklch(63% 0.2 30)"

    iex> Color.CSS.to_css(%Color.Lab{l: 50.0, a: 40.0, b: 30.0})
    "lab(50% 40 30)"

    iex> Color.CSS.to_css(%Color.CMYK{c: 0.0, m: 1.0, y: 1.0, k: 0.0})
    "device-cmyk(0% 100% 100% 0%)"

---

*Consult [api-reference.md](api-reference.md) for complete listing*
