# `Expresso.Color`
[🔗](https://github.com/rellen/expresso/blob/main/lib/expresso/color.ex#L1)

Calculates the contrast of two colors, and moves the lightness of a color

A color is a `#rrggbb` string of sRGB. `contrast/2` returns the contrast ratio
of WCAG 2.2, from 1 to 21. `lightness_contrast/2` returns the lightness
contrast `Lc` of APCA, from 0 to about 108. `blend/3` returns the color of a
foreground with an opacity on a background, as a browser paints it.
`adjust/4` makes a foreground lighter or darker until it has a contrast ratio
and a lightness contrast with a background. It changes only the lightness of
the color in OKLab, so the hue stays the same. `Expresso.Palette` uses these
functions for the themes.

# `t`

```elixir
@type t() :: String.t()
```

A color as `#rrggbb`

# `adjust`

```elixir
@spec adjust(t(), t(), number(), number()) :: {:ok, t(), float()} | :error
```

Make a foreground lighter or darker until its contrast with the background is
at least `minimum`, and its lightness contrast is at least `lc`

`minimum` is a contrast ratio of WCAG, and `lc` is an absolute value of APCA.
The default `lc` of 0 asks only for the contrast ratio.

The function returns the color and the change of its lightness in OKLab, from
0 to 1. A color that already has the contrast comes back with the change 0.
The foreground becomes lighter on a dark background and darker on a light
background, in steps of 0.001. The function reduces the chroma only where a
color with the new lightness is outside sRGB. It returns `:error` when no
lightness gives the contrast.

    iex> Expresso.Color.adjust("#ffffff", "#000000", 4.5)
    {:ok, "#ffffff", 0.0}

# `blend`

```elixir
@spec blend(t(), t(), float()) :: t()
```

Return the color of a foreground with an opacity from 0 to 1 on a background

Each channel is `opacity * foreground + (1 - opacity) * background`, on the
encoded values of sRGB. A browser composites an element with a filter in
this way.

    iex> Expresso.Color.blend("#000000", "#ffffff", 0.5)
    "#808080"

# `contrast`

```elixir
@spec contrast(t(), t()) :: float()
```

Return the contrast ratio of two colors, as WCAG 2.2 defines it

The ratio is `(L1 + 0.05) / (L2 + 0.05)`, where `L1` is the relative
luminance of the lighter color and `L2` the luminance of the darker color.
The order of the arguments is not important.

    iex> Expresso.Color.contrast("#000000", "#ffffff")
    21.0

    iex> Float.round(Expresso.Color.contrast("#777777", "#ffffff"), 2)
    4.48

# `lightness_contrast`

```elixir
@spec lightness_contrast(t(), t()) :: float()
```

Return the lightness contrast `Lc` of a text on a background, as APCA defines it

The function uses the constants of APCA-W3 version 0.0.98G-4g. APCA gives a
negative value for light text on a dark background. This function returns
the absolute value, so a larger value is always more contrast. The order of
the arguments is important: the first color is the text.

APCA raises each luminance to a different power for the text and for the
background, and the powers depend on which color is lighter. Thus the
same two colors give a different value when they change places, and a dark
background gives less contrast than the contrast ratio of WCAG says.
`docs/architecture.md` gives the formula.

    iex> Float.round(Expresso.Color.lightness_contrast("#000000", "#ffffff"), 1)
    106.0

    iex> Float.round(Expresso.Color.lightness_contrast("#ffffff", "#000000"), 1)
    107.9

    iex> Float.round(Expresso.Color.lightness_contrast("#888888", "#ffffff"), 1)
    63.1

# `luminance`

```elixir
@spec luminance(t()) :: float()
```

Return the relative luminance of a color, from 0 for black to 1 for white

---

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