diff --git a/files/en-us/web/css/color_value/color/index.md b/files/en-us/web/css/color_value/color/index.md index 682b3409734b3e3..ce9fb3a1216a735 100644 --- a/files/en-us/web/css/color_value/color/index.md +++ b/files/en-us/web/css/color_value/color/index.md @@ -3,38 +3,146 @@ title: color() slug: Web/CSS/color_value/color page-type: css-function browser-compat: css.types.color.color +spec-urls: + - https://drafts.csswg.org/css-color-5/#color-function + - https://drafts.csswg.org/css-color-5/#relative-color-function + - https://drafts.csswg.org/css-color/#color-function --- {{CSSRef}} -The **`color()`** functional notation allows a color to be specified in a particular, specified colorspace rather than the implicit sRGB colorspace that most of the other color functions operate in. +The **`color()`** functional notation allows a color to be specified in a particular, specified {{glossary("color space")}} rather than the implicit sRGB color space that most of the other color functions operate in. -Support for a particular colorspace can be detected with the [`color-gamut`](/en-US/docs/Web/CSS/@media/color-gamut) CSS media feature. +Support for a particular color space can be detected with the [`color-gamut`](/en-US/docs/Web/CSS/@media/color-gamut) CSS media feature. ## Syntax ```css +/* Absolute values */ color(display-p3 1 0.5 0); color(display-p3 1 0.5 0 / .5); + +/* Relative values */ +color(from green srgb r g b / 0.5) +color(from #0000FF xyz calc(x + 0.75) y calc(z - 0.35)) ``` ### Values -Functional notation: `color(colorspace c1 c2 c3[ / A])` +Below are descriptions of the allowed values for both absolute and [relative colors](/en-US/docs/Web/CSS/CSS_colors/Relative_colors). + +#### Absolute value syntax + +```text +color(colorspace c1 c2 c3[ / A]) +``` + +The parameters are as follows: - `colorspace` - - : An {{CSSXref("<ident>")}} denoting one of the predefined color spaces: `srgb`, `srgb-linear`, `display-p3`, `a98-rgb`, `prophoto-rgb`, `rec2020`, `xyz`, `xyz-d50`, and `xyz-d65`. + - : An {{CSSXref("<ident>")}} denoting one of the predefined color spaces: `srgb`, `srgb-linear`, `display-p3`, `a98-rgb`, `prophoto-rgb`, `rec2020`, `xyz`, `xyz-d50`, or `xyz-d65`. - `c1`, `c2`, `c3` - - : {{CSSXref("number")}} between 0 and 1, a {{CSSXref("percentage")}} or the keyword `none`, which provide the component values in the color space. + - : Each value can be written as a {{CSSXref("number")}}, a {{CSSXref("percentage")}}, or the keyword `none` (equivalent to `0` in this case). These values represent the component values for the colorspace. When using a `` value, generally, `0` to `1` represents the bounds of the color space. Values outside of that range are permitted but will be out of {{glossary("gamut")}} for the given color space. When using a percentage value, `100%` represents `1` and `0%` represents `0`. - `A` {{optional_inline}} - - : An {{CSSXref("<alpha-value>")}} or the keyword `none`, where the number `1` corresponds to `100%` (full opacity). + - : An {{CSSXref("<alpha-value>")}} representing the alpha channel value of the color, where the number `0` corresponds to `0%` (fully transparent) and `1` corresponds to `100%` (fully opaque). Additionally, the keyword `none` can be used to explicitly specify no alpha channel. If the `A` channel value is not explicitly specified, it defaults to 100%. If included, the value is preceded by a slash (`/`). + +> **Note:** See [Missing color components](/en-US/docs/Web/CSS/color_value#missing_color_components) for more information on the effect of `none`. + +#### Relative value syntax + +```text +color(from colorspace c1 c2 c3[ / A]) +``` + +The parameters are as follows: + +- `from ` + - : The keyword `from` is always included when defining a relative color, followed by a {{cssxref("<color>")}} value representing the **origin color**. This is the original color that the relative color is based on. The origin color can be _any_ valid {{cssxref("<color>")}} syntax, including another relative color. +- `colorspace` + - : An {{CSSXref("<ident>")}} denoting the {{glossary("color space")}} of the output color, generally one of the predefined color spaces: `srgb`, `srgb-linear`, `display-p3`, `a98-rgb`, `prophoto-rgb`, `rec2020`, `xyz`, `xyz-d50`, or `xyz-d65`. +- `c1`, `c2`, `c3` + - : Each value can be written as a {{CSSXref("number")}}, a {{CSSXref("percentage")}}, or the keyword `none` (equivalent to `0` in this case). These values represent the component values for the output color. When using a `` value, generally `0` to `1` represents the bounds of the color space. Values outside of that range are permitted but will be out of {{glossary("gamut")}} for the given color space. Generally, when using a percentage value, `100%` represents `1` and `0%` represents `0`. +- `A` {{optional_inline}} + - : An {{CSSXref("<alpha-value>")}} representing the alpha channel value of the output color, where the number `0` corresponds to `0%` (fully transparent) and `1` corresponds to `100%` (fully opaque). Additionally, the keyword `none` can be used to explicitly specify no alpha channel. If the `A` channel value is not explicitly specified, it defaults to the alpha channel value of the origin color. If included, the value is preceded by a slash (`/`). + +#### Defining relative color output channel components + +When using relative color syntax inside a `color()` function, the browser converts the origin color into an equivalent color in the specified color space (if it is not already specified as such). The color is defined as three distinct color channel values plus an alpha channel value (`alpha`). These channel values are made available inside the function to be used when defining the output color channel values: + +- The three color channel values of the origin color are resolved to a ``. For predefined color spaces, depending on which is specified, these values will be one of the following: + + - `r`, `g`, and `b`: Color channel values for the RGB-based color spaces `srgb`, `srgb-linear`, `display-p3`, `a98-rgb`, `prophoto-rgb`, and `rec2020`. + - `x`, `y`, and `z`: Color channel values for the CIE XYZ-based color spaces `xyz`, `xyz-d50`, and `xyz-d65`. + + > **Note:** Each of these values is usually between `0` and `1` but, as explained above, they may be outside these bounds. + + > **Note:** Referencing `r`, `g`, and `b` values inside a `color()` function with a XYZ-based colorspace, `x`, `y`, and `z` values inside a `color()` function with an RGB-based colorspace, or any other characters, is invalid. The origin color channel values available inside the function must match the specified type of colorspace. + +- `alpha`: The color's transparency value, resolved to a `` between `0` and `1`, inclusive. + +When defining a relative color, the different channels of the output color can be expressed in several different ways. Below, we'll study some examples to illustrate these. + +In the first two examples below, we are using relative color syntax. However, the first one outputs the same color as the origin color and the second one outputs a color not based on the origin color at all. They don't really create relative colors! You'd be unlikely to ever use these in a real codebase, and would probably just use an absolute color value instead. We included these examples as a starting point for learning about relative `color()` syntax. + +Let's start with an origin color of `hsl(0 100% 50%)` (equivalent to `red`). While you are unlikely to ever write the following functions because they output the same color as the origin color, this demonstrates how to use the origin color channel values as the output channel values: + +```css +color(from hsl(0 100% 50%) srgb r g b) +color(from hsl(0 100% 50%) xyz x y z) +``` + +These functions' output colors are `color(srgb 1 0 0)` and `color(xyz-d65 0.412426 0.212648 0.0193173)`, respectively. + +The next functions use absolute values for the output color channel values, outputting completely different colors not based on the origin color: + +```css +color(from hsl(0 100% 50%) srgb 0.749938 0 0.609579) +/* Computed output color: color(srgb 0.749938 0 0.609579) */ + +color(from hsl(0 100% 50%) xyz 0.75 0.6554 0.1) +/* Computed output color: color(xyz-d65 0.75 0.6554 0.1 */ +``` + +The following functions use two of the origin color channel values for the output color channel values (`r` and `b`, and `x` and `y`, respectively), but use a new value for the other output channel value (`g` and `z`, respectively), creating a relative color based on the origin color in each case: + +```css +color(from hsl(0 100% 50%) srgb r 1 b) +/* Computed output color: color(srgb 1 1 0) */ + +color(from hsl(0 100% 50%) xyz x y 0.5) +/* Computed output color: color(xyz-d65 0.412426 0.212648 0.5) */ +``` + +> **Note:** As mentioned above, if the output color is using a different color model to the origin color, the origin color is converted to the same model as the output color in the background so that it can be represented in a way that is compatible (i.e. using the same channels). For example, the {{cssxref("color_value/hsl", "hsl()")}} color `hsl(0 100% 50%)` is converted to `color(srgb 1 0 0)` in the first case above and `color(xyz 0.412426 0.212648 0.5)` in the second case. + +In the examples we've seen so far in this section, the alpha channels have not been explicitly specified for either the origin or output colors. When the output color alpha channel is not specified, it defaults to the same value as the origin color alpha channel. When the origin color alpha channel is not specified (and it is not a relative color), it defaults to `1`. Therefore, the origin and output alpha channel values are `1` for the above examples. + +Let's look at some examples that specify origin and output alpha channel values. The first one specifies the output alpha channel value as being the same as the origin alpha channel value, whereas the second one specifies a different output alpha channel value, unrelated to the origin alpha channel value. -> **Note:** See [Missing color components](/en-US/docs/Web/CSS/color_value#missing_color_components) for the effect of `none`. +```css +color(from hsl(0 100% 50% / 0.8) srgb r g b / alpha) +/* Computed output color: color(srgb 1 0 0 / 0.8) */ + +color(from hsl(0 100% 50% / 0.8) xyz x y z / 0.5) +/* Computed output color: color(xyz-d65 0.412426 0.212648 0.0193173 / 0.5) */ +``` + +The following examples use {{cssxref("calc")}} functions to calculate new channel values for the output colors that are relative to the origin color channel values: + +```css +color(from hsl(0 100% 50%) srgb calc(r - 0.4) calc(g + 0.1) calc(b + 0.6) / calc(alpha - 0.1)) +/* Computed output color: color(srgb 0.6 0.1 0.6 / 0.9) */ + +color(from hsl(0 100% 50%) xyz calc(x - 0.3) calc(y + 0.3) calc(z + 0.3) / calc(alpha - 0.1)) +/* Computed output color: color(xyz-d65 0.112426 0.512648 0.319317 / 0.9) */ +``` + +> **Note:** Because the origin color channel values are resolved to `` values, you have to add numbers to them when using them in calculations, even in cases where a channel would normally accept ``, ``, or other value types. Adding a `` to a ``, for example, doesn't work. ### Formal syntax @@ -42,7 +150,7 @@ Functional notation: `color(colorspace c1 c2 c3[ / A])` ## Examples -### Using predefined colorspaces with color() +### Using predefined color spaces with color() The following example shows the effect of varying the lightness, a-axis, and b-axis values of the `color()` function. @@ -93,11 +201,11 @@ div { #### Result -{{EmbedLiveSample("using_predefined_colorspaces_with_color")}} +{{EmbedLiveSample("using_predefined_color_spaces_with_color")}} -### Using the xyz colorspace with color() +### Using the xyz color space with color() -The following example shows how to use the `xyz` colorspace to specify a color. +The following example shows how to use the `xyz` color space to specify a color. #### HTML @@ -136,11 +244,11 @@ div { #### Result -{{EmbedLiveSample("using_the_xyz_colorspace_with_color")}} +{{EmbedLiveSample("using_the_xyz_color_space_with_color")}} ### Using color-gamut media queries with color() -This example shows how to use the [`color-gamut`](/en-US/docs/Web/CSS/@media/color-gamut) media query to detect support for a particular colorspace and use that colorspace to specify a color. +This example shows how to use the [`color-gamut`](/en-US/docs/Web/CSS/@media/color-gamut) media query to detect support for a particular color space and use that color space to specify a color. #### HTML @@ -187,6 +295,81 @@ div { {{EmbedLiveSample("using_color-gamut_media_queries_with_color")}} +### Using relative colors with color() + +This example styles three {{htmlelement("div")}} elements with different background colors. The middle one is given the unmodified `--base-color`, while the left and right ones are given lightened and darkened variants of that `--base-color`. + +These variants are defined using relative colors — the `--base-color` [custom property](/en-US/docs/Web/CSS/--*) is passed into a `color()` function, and the output colors have their `g` and `b` channels modified to achieve the desired effect via `calc()` functions. The lightened color has 15% added to those channels, and the darkened color has 15% subtracted from those channels. + +```html hidden +
+
+
+
+
+``` + +#### CSS + +```css hidden +#container { + display: flex; + width: 100vw; + height: 100vh; + box-sizing: border-box; +} + +.item { + flex: 1; + margin: 20px; +} +``` + +```css +:root { + --base-color: orange; +} + +#one { + background-color: color( + from var(--base-color) display-p3 r calc(g + 0.15) calc(b + 0.15) + ); +} + +#two { + background-color: var(--base-color); +} + +#three { + background-color: color( + from var(--base-color) display-p3 r calc(g - 0.15) calc(b - 0.15) + ); +} + +/* Use @supports to add in support old syntax that requires r g b values + to be specified as percentages (with units) in calculations. + This is required for Safari 16.4+ */ +@supports (color: color(from red display-p3 r g calc(b + 30%))) { + #one { + background-color: color( + from var(--base-color) display-p3 r calc(g + 15%) calc(b + 15%) + ); + } + + #three { + background-color: color( + from var(--base-color) display-p3 r calc(g - 15%) calc(b - 15%) + ); + } +} +``` + +#### Result + +The output is as follows: + +{{ EmbedLiveSample("Using relative colors with color()", "100%", "200") }} + ## Specifications {{Specifications}} @@ -198,5 +381,7 @@ div { ## See also - [The `` data type](/en-US/docs/Web/CSS/color_value) for a list of all color notations +- [Using relative colors](/en-US/docs/Web/CSS/CSS_colors/Relative_colors) +- [CSS colors](/en-US/docs/Web/CSS/CSS_colors) module - [`color-gamut`](/en-US/docs/Web/CSS/@media/color-gamut) media feature - [Wide Gamut Color in CSS with Display-p3](https://webkit.org/blog/10042/wide-gamut-color-in-css-with-display-p3/) diff --git a/files/en-us/web/css/color_value/hsl/index.md b/files/en-us/web/css/color_value/hsl/index.md index 60f284917b7459a..f3b394b6a3cc72c 100644 --- a/files/en-us/web/css/color_value/hsl/index.md +++ b/files/en-us/web/css/color_value/hsl/index.md @@ -3,13 +3,14 @@ title: hsl() slug: Web/CSS/color_value/hsl page-type: css-function browser-compat: css.types.color.hsl +spec-urls: + - https://drafts.csswg.org/css-color-5/#relative-HSL + - https://drafts.csswg.org/css-color/#the-hsl-notation --- {{CSSRef}} -The **`hsl()`** functional notation expresses an {{glossary("RGB", "sRGB")}} color according to its _hue_, _saturation_, and _lightness_ components. An optional _alpha_ component represents the color's transparency. - -> **Note:** The legacy `hsla()` syntax is an alias for `hsl()`, accepting the same parameters and behaving in the same way. +The **`hsl()`** functional notation expresses a color in the {{glossary("RGB", "sRGB")}} {{glossary("color space")}} according to its _hue_, _saturation_, and _lightness_ components. An optional _alpha_ component represents the color's transparency. {{EmbedInteractiveExample("pages/css/function-hsl.html")}} @@ -18,28 +19,137 @@ Defining _complementary colors_ with `hsl()` can be done with a single formula, ## Syntax ```css +/* Absolute values */ hsl(120deg 75% 25%) +hsl(120 75 25) /* deg and % units are optional */ hsl(120deg 75% 25% / 60%) +hsl(none 75% 25%) + +/* Relative values */ +hsl(from green h s l / 0.5) +hsl(from #0000FF h s calc(l + 20)) +hsl(from rgb(200 0 0) calc(h + 30) s calc(l + 30)) ``` -The function also accepts a legacy syntax in which all values are separated with commas. +The `hsla()` function can also be used to express sRGB colors. This is an alias for `hsl()` that accepts the same parameters. + +> **Note:** `hsl()`/`hsla()` can also be written in a legacy form in which all values are separated with commas, for example `hsl(120deg, 75%, 25%)`. The `none` value is not permitted in the comma-separated legacy syntax, and the `%` units are required. ### Values -Functional notation: `hsl(H S L[ / A])` +Below are descriptions of the allowed values for both absolute and [relative colors](/en-US/docs/Web/CSS/CSS_colors/Relative_colors). + +#### Absolute value syntax + +```text +hsl(H S L[ / A]) +``` + +The parameters are as follows: + +- `H` + + - : A {{CSSXref("<number>")}}, an {{CSSXref("<angle>")}}, or the keyword `none` (equivalent to `0deg` in this case) representing the color's {{CSSXref("<hue>")}} angle. + + > **Note:** The angles corresponding to particular hues differ across the sRGB (used by `hsl()` and {{CSSXref("color_value/hwb", "hwb()")}}), CIELAB (used by {{CSSXref("color_value/lch", "lch()")}}), and Oklab (used by {{CSSXref("color_value/oklch", "oklch()")}}) color spaces. See the {{CSSXref("<hue>")}} reference page for more detail and examples. +- `S` + - : A {{CSSXref("<percentage>")}} or the keyword `none` (equivalent to `0%` in this case). This value represents the color's saturation. Here `100%` is completely saturated, while `0%` is completely unsaturated (gray). +- `L` + - : A {{CSSXref("<percentage>")}} or the keyword `none` (equivalent to `0%` in this case). This value represents the color's lightness. Here `100%` is white, `0%` is black, and `50%` is "normal". +- `A` {{optional_inline}} + - : An {{CSSXref("<alpha-value>")}} representing the alpha channel value of the color, where the number `0` corresponds to `0%` (fully transparent) and `1` corresponds to `100%` (fully opaque). Additionally, the keyword `none` can be used to explicitly specify no alpha channel. If the `A` channel value is not explicitly specified, it defaults to 100%. If included, the value is preceded by a slash (`/`). + +> **Note:** See [Missing color components](/en-US/docs/Web/CSS/color_value#missing_color_components) for more information on the effect of `none`. + +> **Note:** Absolute `hsl()` colors are serialized to {{CSSXref("color_value/rgb", "rgb()")}} values. The values of the red, green, and blue components may be rounded in serialization. + +#### Relative value syntax + +```text +hsl(from H S L[ / A]) +``` + +The parameters are as follows: + +- `from ` + - : The keyword `from` is always included when defining a relative color, followed by a {{cssxref("<color>")}} value representing the **origin color**. This is the original color that the relative color is based on. The origin color can be _any_ valid {{cssxref("<color>")}} syntax, including another relative color. - `H` - - : A {{CSSXref("<number>")}}, an {{CSSXref("<angle>")}}, or the keyword `none`, which represents the hue angle. More details on this type can be found on the {{CSSXref("<hue>")}} reference. + - : A {{CSSXref("<number>")}}, an {{CSSXref("<angle>")}}, or the keyword `none` (equivalent to `0deg` in this case) representing the output color's {{CSSXref("<hue>")}} angle. - `S` - - : A {{CSSXref("<percentage>")}} or the keyword `none`, which represents saturation. Here `100%` is completely saturated, while `0%` is completely unsaturated (gray). + - : A {{CSSXref("<percentage>")}} or the keyword `none` (equivalent to `0%` in this case). This represents the saturation of the output color. Here `100%` is completely saturated, while `0%` is completely unsaturated (gray). - `L` - - : A {{CSSXref("<percentage>")}} or the keyword `none`, which represents lightness. Here `100%` is white, `0%` is black, and `50%` is "normal". + - : A {{CSSXref("<percentage>")}} or the keyword `none` (equivalent to `0%` in this case). This represents the lightness of the output color. Here `100%` is white, `0%` is black, and `50%` is "normal". - `A` {{optional_inline}} - - : An {{CSSXref("<alpha-value>")}} or the keyword `none`, where the number `1` corresponds to `100%` (full opacity). + - : An {{CSSXref("<alpha-value>")}} representing the alpha channel value of the output color, where the number `0` corresponds to `0%` (fully transparent) and `1` corresponds to `100%` (fully opaque). Additionally, the keyword `none` can be used to explicitly specify no alpha channel. If the `A` channel value is not explicitly specified, it defaults to the alpha channel value of the origin color. If included, the value is preceded by a slash (`/`). + +> **Note:** The `hsla()` alias can also be used to output relative colors, and to specify origin colors. When using `hsla()` to output a relative color, you must use the comma-less modern syntax. + +> **Note:** To fully enable the representation of the full spectrum of visible colors, the output of relative `hsl()` color functions is serialized to `color(srgb)`. That means that querying the output color value via the {{DOMxRef("HTMLElement.style")}} property or the {{DOMxRef("CSSStyleDeclaration.getPropertyValue()")}} method returns the output color as a [`color(srgb ...)`](/en-US/docs/Web/CSS/color_value/color) value. + +#### Defining relative color output channel components + +When using relative color syntax inside an `hsl()` function, the browser converts the origin color into an equivalent HSL color (if it is not already specified as such). The color is defined as three distinct color channel values — `h` (hue), `s` (saturation), and `l` (lightness) — plus an alpha channel value (`alpha`). These channel values are made available inside the function to be used when defining the output color channel values: + +- The `h` value is resolved to a {{cssxref("<number>")}} between `0` and `360`, inclusive, that represents the origin color's {{cssxref("<hue>")}} degree value. +- The `s` and `l` values are each resolved to a `` between `0` and `100`, inclusive, where `100` is equivalent to `100%`. +- The `alpha` value is resolved to a `` between `0` and `1`, inclusive. + +When defining a relative color, the different channels of the output color can be expressed in several different ways. Below, we'll study some examples to illustrate these. + +In the first two examples below, we are using relative color syntax. However, the first one outputs the same color as the origin color and the second one outputs a color not based on the origin color at all. They don't really create relative colors! You'd be unlikely to ever use these in a real codebase, and would probably just use an absolute color value instead. We included these examples as a starting point for learning about relative `hsl()` syntax. + +Let's start with an origin color of `rgb(255 0 0)` (equivalent to `hsl(0 100% 50%)`). The following function outputs the same color as the origin color — it uses the origin color's `h`, `s`, and `l` channel values (`0`, `100%`, and `50%`) as the output channel values: + +```css +hsl(from rgb(255 0 0) h s l) +``` + +This function's output color is the sRGB `color()` equivalent of `hsl(0 100% 50%)`: `color(srgb 1 0 0)`. + +The next function uses absolute values for the output color's channel values, outputting a completely different color not based on the origin color: + +```css +hsl(from rgb(255 0 0) 240 60% 70%) +``` + +In the above case, the output color is the sRGB `color()` equivalent of `hsl(240 60% 70%)`: `color(srgb 0.52 0.52 0.88)`. + +The following function creates a relative color based on the origin color: + +```css +hsl(from rgb(255 0 0) h 30% 60%) +``` + +This example: -> **Note:** This functional notation serializes to sRGB values, and the values of the red, green, blue components may be rounded in serialization. +- Converts the origin color (`rgb(255 0 0)`) into an `hsl()` equivalent (`hsl(0 100% 50%)`). +- Sets the `H` channel value for the output color to those of the origin color `hsl()` equivalent's `H` channel value — `0`. +- Sets the output color's `S` and `L` channel values to new values not based on the origin color: `30%` and `60%`, respectively. -> **Note:** See [Missing color components](/en-US/docs/Web/CSS/color_value#missing_color_components) for the effect of `none`. +The final output color is the equivalent of `hsl(0 30% 60%)` in the sRGB color space — `color(srgb 0.72 0.48 0.48)`. + +> **Note:** As mentioned above, if the output color is using a different color model to the origin color, the origin color is converted to the same model as the output color in the background so that it can be represented in a way that is compatible (i.e. using the same channels). + +In the examples we've seen so far in this section, the alpha channels have not been explicitly specified for either the origin or output colors. When the output color alpha channel is not specified, it defaults to the same value as the origin color alpha channel. When the origin color alpha channel is not specified (and it is not a relative color), it defaults to `1`. Therefore, the origin and output alpha channel values are `1` for the above examples. + +Let's look at some examples that specify origin and output alpha channel values. The first one specifies the output alpha channel value as being the same as the origin alpha channel value, whereas the second one specifies a different output alpha channel value, unrelated to the origin alpha channel value. + +```css +hsl(from rgb(255 0 0 / 0.8) h s l / alpha) +/* Computed output color: color(srgb 1 0 0 / 0.8) */ + +hsl(from rgb(255 0 0 / 0.8) h s l / 0.5) +/* Computed output color: color(srgb 1 0 0 / 0.5) */ +``` + +In the following example, the `rgb()` origin color is again converted into an `hsl()` representation — `hsl(0 100% 50% / 0.8)`. {{cssxref("calc")}} calculations are applied to the `H`, `S`, `L`, and `A` values, and the final output color is the equivalent of `hsl(60 80% 30% / 0.7)` in the sRGB color space: `color(srgb 0.72 0.72 0.08 / 0.7)`. + +```css +hsl(from rgb(255 0 0 / 0.8) calc(h + 60) calc(s - 20) calc(l - 10) / calc(alpha - 0.1)) +``` + +> **Note:** Because the origin color channel values are resolved to `` values, you have to add numbers to them when using them in calculations, even in cases where a channel would normally accept ``, ``, or other value types. Adding a `` to a ``, for example, doesn't work. ### Formal syntax @@ -80,6 +190,77 @@ div { {{EmbedLiveSample("using_hsl_with_conic-gradient", "100%", 140)}} +### Using relative colors with hsl() + +This example styles three {{htmlelement("div")}} elements with different background colors. The middle one is given the unmodified `--base-color`, while the left and right ones are given lightened and darkened variants of that `--base-color`. + +These variants are defined using relative colors — the `--base-color` [custom property](/en-US/docs/Web/CSS/--*) is passed into an `hsl()` function, and the output color has its lightness channel modified to achieve the desired effect via a `calc()` function, while the hue and saturation are left unchanged. The lightened color has 20% added to the lightness channel, and the darkened color has 20% subtracted from it. + +```html hidden +
+
+
+
+
+``` + +#### CSS + +```css hidden +#container { + display: flex; + width: 100vw; + height: 100vh; + box-sizing: border-box; +} + +.item { + flex: 1; + margin: 20px; +} +``` + +```css +:root { + --base-color: orange; +} + +/* As per the spec, s and l values should resolve to a number between 0-100 + However, Chrome 121+ incorrectly resolves them to numbers between 0-1 + hence currently using calculations like l + 0.2 instead of l + 20 */ + +#one { + background-color: hsl(from var(--base-color) h s calc(l + 0.2)); +} + +#two { + background-color: var(--base-color); +} + +#three { + background-color: hsl(from var(--base-color) h s calc(l - 0.2)); +} + +/* Use @supports to add in support for old syntax that requires % units to + be specified in lightness calculations. This is required for + Safari 16.4+ */ +@supports (color: hsl(from red h s calc(l - 20%))) { + #one { + background-color: hsl(from var(--base-color) h s calc(l + 20%)); + } + + #three { + background-color: hsl(from var(--base-color) h s calc(l - 20%)); + } +} +``` + +#### Result + +The output is as follows: + +{{ EmbedLiveSample("Using relative colors with hsl()", "100%", "200") }} + ### Legacy syntax: comma-separated values For legacy reasons, the `hsl()` function accepts a form in which all values are separated using commas. @@ -115,7 +296,7 @@ div.comma-separated { ### Legacy syntax: hsla() -The legacy `hsla()` syntax is an alias for `hsl()`. +The `hsla()` syntax is an alias for `hsl()`. #### HTML @@ -158,5 +339,7 @@ div.hsla { - [List of all color notations](/en-US/docs/Web/CSS/color) - {{CSSXref("<hue>")}} data type +- [Using relative colors](/en-US/docs/Web/CSS/CSS_colors/Relative_colors) +- [CSS colors](/en-US/docs/Web/CSS/CSS_colors) module - [Color picker tool](/en-US/docs/Web/CSS/CSS_colors/Color_picker_tool) on MDN - [Color picker](https://colorjs.io/apps/picker/) by Lea Verou diff --git a/files/en-us/web/css/color_value/hwb/index.md b/files/en-us/web/css/color_value/hwb/index.md index e271bb4b7fa4af6..188c1bcaa8b8ecf 100644 --- a/files/en-us/web/css/color_value/hwb/index.md +++ b/files/en-us/web/css/color_value/hwb/index.md @@ -3,47 +3,229 @@ title: hwb() slug: Web/CSS/color_value/hwb page-type: css-function browser-compat: css.types.color.hwb +spec-urls: + - https://drafts.csswg.org/css-color-5/#relative-HWB + - https://drafts.csswg.org/css-color/#the-hwb-notation --- {{CSSRef}} -The **`hwb()`** functional notation expresses an {{glossary("RGB", "sRGB")}} color according to its hue, whiteness, and blackness. An optional alpha component represents the color's transparency. +The **`hwb()`** functional notation expresses a color in the {{glossary("RGB", "sRGB")}} {{glossary("color space")}} according to its hue, whiteness, and blackness. An optional alpha component represents the color's transparency. {{EmbedInteractiveExample("pages/css/function-hwb.html")}} ## Syntax ```css -hwb(194 0% 0%) /* #00c3ff */ -hwb(194 0% 0% / .5) /* #00c3ff with 50% opacity */ +/* Absolute values */ +hwb(194 0% 0%) +hwb(194 0% 0% / .5) + +/* Relative values */ +hwb(from green h w b / 0.5) +hwb(from #0000FF h calc(w + 30) b) +hwb(from lch(40% 70 240deg) h w calc(b - 30)) ``` ### Values -Functional notation: `hwb(H W B[ / A])` +Below are descriptions of the allowed values for both absolute and [relative colors](/en-US/docs/Web/CSS/CSS_colors/Relative_colors). + +#### Absolute value syntax + +```text +hwb(H W B[ / A]) +``` + +The parameters are as follows: - `H` - - : A {{CSSXref("<number>")}}, an {{CSSXref("<angle>")}}, or the keyword `none`, which represents the hue angle. More details on this type can be found on the {{CSSXref("<hue>")}} reference. + - : A {{CSSXref("<number>")}}, an {{CSSXref("<angle>")}}, or the keyword `none` (equivalent to `0deg` in this case) representing the color's {{CSSXref("<hue>")}} angle. + + > **Note:** The angles corresponding to particular hues differ across the sRGB (used by {{CSSXref("color_value/hsl", "hsl()")}} and `hwb()`, CIELAB (used by {{CSSXref("color_value/lch", "lch()")}}), and Oklab (used by {{CSSXref("color_value/oklch", "oklch()")}}) color spaces. See the {{CSSXref("<hue>")}} reference page for more detail and examples. - `W`, `B` - - : Each as a {{CSSXref("<percentage>")}} or the keyword `none`, which represent whiteness and blackness, respectively. They specify the amount of white and black to mix in, from `0%` (no whiteness or blackness) to `100%` (full whiteness or blackness). + - : Each one is a {{CSSXref("<percentage>")}} or the keyword `none` (equivalent to `0%` in this case). These values represent the color's whiteness and blackness respectively, specifying the amount to mix in. `0%` represents no whiteness or blackness, whereas `100%` represents full whiteness or blackness. - If `W + B = 100%`, it defines some shade of gray. If `W + B > 100%`, `W` and `B` are effectively normalized as `W / (W + B)` and `B / (W + B)`, respectively. + If `W + B = 100%`, it defines a shade of gray. + + If `W + B > 100%`, `W` and `B` are effectively normalized as `W / (W + B)` and `B / (W + B)`, respectively. - `A` {{optional_inline}} - - : An {{CSSXref("<alpha-value>")}} or the keyword `none`, where the number `1` corresponds to `100%` (full opacity). + - : An {{CSSXref("<alpha-value>")}} representing the alpha channel value of the color, where the number `0` corresponds to `0%` (fully transparent) and `1` corresponds to `100%` (fully opaque). Additionally, the keyword `none` can be used to explicitly specify no alpha channel. If the `A` channel value is not explicitly specified, it defaults to 100%. If included, the value is preceded by a slash (`/`). + +> **Note:** See [Missing color components](/en-US/docs/Web/CSS/color_value#missing_color_components) for more information on the effect of `none`. + +> **Note:** Absolute `hwb()` colors are serialized to {{CSSXref("color_value/rgb", "rgb()")}} values. The values of the red, green, and blue components may be rounded in serialization. + +#### Relative value syntax + +```text +hwb(from H W B[ / A]) +``` + +The parameters are as follows: + +- `from ` + - : The keyword `from` is always included when defining a relative color, followed by a {{cssxref("<color>")}} value representing the **origin color**. This is the original color that the relative color is based on. The origin color can be _any_ valid {{cssxref("<color>")}} syntax, including another relative color. +- `H` + - : A {{CSSXref("<number>")}}, an {{CSSXref("<angle>")}}, or the keyword `none` (equivalent to `0deg` in this case) representing the output color's {{CSSXref("<hue>")}} angle. +- `W`, `B` + + - : Each value can be written as a {{CSSXref("<percentage>")}} or the keyword `none` (equivalent to `0%` in this case). These values represent the whiteness and blackness channel values of the output color respectively, specifying the amount to mix in. `0%` represents no whiteness or blackness, whereas `100%` represents full whiteness or blackness. + + If `W + B = 100%`, it defines a shade of gray. + + If `W + B > 100%`, `W` and `B` are effectively normalized as `W / (W + B)` and `B / (W + B)`, respectively. + +- `A` {{optional_inline}} + - : An {{CSSXref("<alpha-value>")}} representing the alpha channel value of the output color, where the number `0` corresponds to `0%` (fully transparent) and `1` corresponds to `100%` (fully opaque). Additionally, the keyword `none` can be used to explicitly specify no alpha channel. If the `A` channel value is not explicitly specified, it defaults to the alpha channel value of the origin color. If included, the value is preceded by a slash (`/`). + +> **Note:** To fully enable the representation of the full spectrum of visible colors, the output of relative `hwb()` color functions is serialized to `color(srgb)`. That means that querying the output color value via the {{DOMxRef("HTMLElement.style")}} property or the {{DOMxRef("CSSStyleDeclaration.getPropertyValue()")}} method returns the output color as a [`color(srgb ...)`](/en-US/docs/Web/CSS/color_value/color) value. + +#### Defining relative color output channel components + +When using relative color syntax inside an `hwb()` function, the browser converts the origin color into an equivalent HWB color (if it is not already specified as such). The color is defined as three distinct color channel values — `h` (hue), `w` (white), and `b` (black) — plus an alpha channel value (`alpha`). These channel values are made available inside the function to be used when defining the output color channel values: + +- The `h` channel value is resolved to a `` between `0` and `360`, inclusive. +- The `w` and `b` channels are each resolved to a `` between `0` and `100`, inclusive. +- The `alpha` channel is resolved to a `` between `0` and `1`, inclusive. + +When defining a relative color, the different channels of the output color can be expressed in several different ways. Below, we'll study some examples to illustrate these. + +In the first two examples below, we are using relative color syntax. However, the first one outputs the same color as the origin color and the second one outputs a color not based on the origin color at all. They don't really create relative colors! You'd be unlikely to ever use these in a real codebase, and would probably just use an absolute color value instead. We included these examples as a starting point for learning about relative `hwb()` syntax. + +Let's start with an origin color of `hsl(0 100% 50%)` (equivalent to `hwb(0 0% 0%)`). The following function outputs the same color as the origin color — it uses the origin color's `h`, `w`, and `b` channel values (`0`, `0%`, and `0%`) as the output channel values: + +```css +hwb(from hsl(0 100% 50%) h w b) +``` + +This function's output color is the sRGB `color()` equivalent of `hwb(0 0% 0%)`: `color(srgb 1 0 0)`. + +The next function uses absolute values for the output color's channel values, outputting a completely different color not based on the origin color: + +```css +hwb(from hsl(0 100% 50%) 240 52% 12%) +``` -> **Note:** This functional notation serializes to sRGB values, and the values of the red, green, blue components may be rounded in serialization. +In the above case, the output color is the sRGB `color()` equivalent of `hwb(240 52% 12%)`: `color(srgb 0.52 0.52 0.88)`. -> **Note:** See [Missing color components](/en-US/docs/Web/CSS/color_value#missing_color_components) for the effect of `none`. +The following function creates a relative color based on the origin color: + +```css +hwb(from hsl(0 100% 50%) h 30% b) +``` + +This example: + +- Converts the origin color (`hsl(0 100% 50%)`) into an `hwb()` equivalent (`hwb(0 0% 0%)`). +- Sets the `H` and `B` channel values for the output color to those of the origin color `hwb()` equivalent's `H` and `B` channel values — those values are `0` and `0%`, respectively. +- Sets the output color's `W` channel value to a new value not based on the origin color: `30%`. + +The final output color is the equivalent of `hwb(0 30% 0%)` in the sRGB color space — `color(srgb 1 0.3 0.3)`. + +> **Note:** As mentioned above, if the output color is using a different color model to the origin color, the origin color is converted to the same model or space as the output color in the background so that it can be represented in a way that is compatible (i.e. using the same channels). + +In the examples we've seen so far in this section, the alpha channels have not been explicitly specified for either the origin or output colors. When the output color alpha channel is not specified, it defaults to the same value as the origin color alpha channel. When the origin color alpha channel is not specified (and it is not a relative color), it defaults to `1`. Therefore, the origin and output alpha channel values are `1` for the above examples. + +Let's look at some examples that specify origin and output alpha channel values. The first one specifies the output alpha channel value as being the same as the origin alpha channel value, whereas the second one specifies a different output alpha channel value, unrelated to the origin alpha channel value. + +```css +hwb(from hsl(0 100% 50% / 0.8) h w b / alpha) +/* Computed output color: color(srgb 1 0 0 / 0.8) */ + +hwb(from hsl(0 100% 50% / 0.8) h w b / 0.5) +/* Computed output color: color(srgb 1 0 0 / 0.5) */ +``` + +In the following example, the `hsl()` origin color is again converted into an `hwb()` representation — `hwb(0 0% 0%)`. {{cssxref("calc")}} calculations are applied to the `H`, `W`, `B`, and `A` values, and the final output color is the equivalent of `hwb(120 25% 10% / 0.9` in the sRGB color space: `color(srgb 0.25 0.9 0.25 / 0.9)`. + +```css +hwb(from hsl(0 100% 50%) calc(h + 120) calc(w + 25) calc(b + 10) / calc(alpha - 0.1)) +``` + +> **Note:** Because the origin color channel values are resolved to `` values, you have to add numbers to them when using them in calculations, even in cases where a channel would normally accept ``, ``, or other value types. Adding a `` to a ``, for example, doesn't work. ### Formal syntax {{csssyntax}} +## Examples + +### Using relative colors with hwb() + +This example styles three {{htmlelement("div")}} elements with different background colors. The middle one is given the unmodified `--base-color`, while the left and right ones are given lightened and darkened variants of that `--base-color`. + +These variants are defined using relative colors — the `--base-color` [custom property](/en-US/docs/Web/CSS/--*) is passed into an `hwb()` function, and the output colors have their white and black channels modified to achieve the desired effect via a `calc()` function. The lightened color has 30% added to the white channel, and the darkened color has 30% added to the black channel. + +```html hidden +
+
+
+
+
+``` + +#### CSS + +```css hidden +#container { + display: flex; + width: 100vw; + height: 100vh; + box-sizing: border-box; +} + +.item { + flex: 1; + margin: 20px; +} +``` + +```css +:root { + --base-color: orange; +} + +/* As per the spec, w and b values should resolve to a number between 0-100 + However, Chrome 121+ incorrectly resolves them to numbers between 0-1 + hence currently using calculations like w + 0.3 instead of w + 30 */ + +#one { + background-color: hwb(from var(--base-color) h calc(w + 0.3) b); +} + +#two { + background-color: var(--base-color); +} + +#three { + background-color: hwb(from var(--base-color) h w calc(b + 0.3)); +} + +/* Use @supports to add in support for old syntax that requires % units to + be specified in w and b calculations. This is required for Safari 16.4+. */ +@supports (color: hwb(from red h w calc(b + 30%))) { + #one { + background-color: hwb(from var(--base-color) h calc(w + 30%) b); + } + + #three { + background-color: hwb(from var(--base-color) h w calc(b + 30%)); + } +} +``` + +#### Result + +The output is as follows: + +{{ EmbedLiveSample("Using relative colors with hwb()", "100%", "200") }} + ## Specifications {{Specifications}} @@ -55,4 +237,6 @@ Functional notation: `hwb(H W B[ / A])` ## See also - {{CSSXref("<color>")}}: For a list of all color notations +- [Using relative colors](/en-US/docs/Web/CSS/CSS_colors/Relative_colors) +- [CSS colors](/en-US/docs/Web/CSS/CSS_colors) module - {{CSSXref("<hue>")}}: the data type representing a hue angle of a color diff --git a/files/en-us/web/css/color_value/index.md b/files/en-us/web/css/color_value/index.md index b539e1dab473925..117896e1510a861 100644 --- a/files/en-us/web/css/color_value/index.md +++ b/files/en-us/web/css/color_value/index.md @@ -51,6 +51,14 @@ oklab(59% 0.1 0.1 / 0.5) oklch(60% 0.15 50) oklch(60% 0.15 50 / 0.5) +/* Relative CSS colors */ +/* HSL hue change */ +hsl(from red 240deg s l) +/* HWB alpha channel change */ +hwb(from green h w b / 0.5) +/* LCH lightness change */ +lch(from blue calc(l + 20) c h) + /* light-dark */ light-dark(white, black) light-dark(rgb(255 255 255), rgb(0 0 0)) @@ -60,11 +68,12 @@ A `` value can be specified using one of the methods listed below: - By keywords: {{CSSXref("<named-color>")}} (such as `blue` or `pink`), {{CSSXref("<system-color>")}}, and [`currentcolor`](#currentcolor_keyword). - By hexadecimal notations: {{CSSXref("<hex-color>")}} (such as `#ff0000`). -- By ``, with parameters in a color space using functional notations: +- By ``, with parameters in a {{glossary("color space")}} using functional notations: - [sRGB](https://en.wikipedia.org/wiki/SRGB) color space: {{CSSXref("color_value/hsl", "hsl()")}}, {{CSSXref("color_value/hwb", "hwb()")}}, {{CSSXref("color_value/rgb", "rgb()")}}; - [CIELAB](https://en.wikipedia.org/wiki/CIELAB_color_space) color space: {{CSSXref("color_value/lab", "lab()")}}, {{CSSXref("color_value/lch", "lch()")}}; - [Oklab](https://bottosson.github.io/posts/oklab/) color space: {{CSSXref("color_value/oklab", "oklab()")}}, {{CSSXref("color_value/oklch", "oklch()")}}; - Other color spaces: {{CSSXref("color_value/color", "color()")}}. +- By using [relative color]((/en-US/docs/Web/CSS/CSS_colors/Relative_colors) syntax to output a new color based on an existing color. Any of the above color functions can take an **origin color** preceded by the `from` keyword and followed by definitions of the channel values for the new **output color**. - By mixing two colors: {{CSSXref("color_value/color-mix", "color-mix()")}}. - By specifying two colors, the first used for light color-schemes and the second used for dark color-schemes: {{CSSXref("color_value/light-dark", "light-dark()")}}. @@ -438,4 +447,5 @@ div:nth-child(6) { - {{CSSXref("<hue>")}}: the data type representing the hue angle of a color - {{CSSXref("color")}}, {{CSSXref("background-color")}}, {{CSSXref("border-color")}}, {{CSSXref("box-shadow")}}, {{CSSXref("outline-color")}}, {{CSSXref("text-shadow")}}: common properties that use `` - [Applying color to HTML elements using CSS](/en-US/docs/Web/CSS/CSS_colors/Applying_color) +- [Using relative colors](/en-US/docs/Web/CSS/CSS_colors/Relative_colors) - [New functions, gradients, and hues in CSS colors (Level 4)](/en-US/blog/css-color-module-level-4/) on MDN blog (2023) diff --git a/files/en-us/web/css/color_value/lab/index.md b/files/en-us/web/css/color_value/lab/index.md index da96f4e63dd22d2..c207ebeaa43ef3b 100644 --- a/files/en-us/web/css/color_value/lab/index.md +++ b/files/en-us/web/css/color_value/lab/index.md @@ -3,37 +3,138 @@ title: lab() slug: Web/CSS/color_value/lab page-type: css-function browser-compat: css.types.color.lab +spec-urls: + - https://drafts.csswg.org/css-color-5/#relative-Lab + - https://drafts.csswg.org/css-color/#lab-colors --- {{CSSRef}} -The **`lab()`** functional notation expresses a given color in the CIE L\*a\*b\* color space. Lab represents the entire range of color that humans can see. +The **`lab()`** functional notation expresses a given color in the CIE L\*a\*b\* {{glossary("color space")}}. + +Lab represents the entire range of colors that humans can see by specifying the color's lightness, a red/green axis value, a blue/yellow axis value, and an optional alpha transparency value. ## Syntax ```css +/* Absolute values */ lab(29.2345% 39.3825 20.0664); lab(52.2345% 40.1645 59.9971); lab(52.2345% 40.1645 59.9971 / .5); + +/* Relative values */ +lab(from green l a b / 0.5) +lab(from #0000FF calc(l + 10) a b) +lab(from hsl(180 100% 50%) calc(l - 10) a b) ``` ### Values -Functional notation: `lab(L a b[ / A])` +Below are descriptions of the allowed values for both absolute and [relative colors](/en-US/docs/Web/CSS/CSS_colors/Relative_colors). + +#### Absolute value syntax + +```text +lab(L a b[ / A]) +``` + +The parameters are as follows: + +- `L` + - : A {{CSSXref("<number>")}} between `0` and `100`, a {{CSSXref("<percentage>")}} between `0%` and `100%`, or the keyword `none` (equivalent to `0%` in this case). This value specifies the color's lightness. Here the number `0` corresponds to `0%` (black) and the number `100` corresponds to `100%` (white). +- `a` + - : A {{CSSXref("<number>")}} between `-125` and `125`, a {{CSSXref("<percentage>")}} between `-100%` and `100%`, or the keyword `none` (equivalent to `0%` in this case). This value specifies the color's distance along the `a` axis, which defines how green (moving towards `-125`) or red (moving towards `+125`) the color is. Note that these values are signed (allowing both positive and negative values) and theoretically unbounded, meaning that you can set values outside the `±125` (`±100%`) limits. In practice, values cannot exceed `±160`. +- `b` + - : A {{CSSXref("<number>")}} between `-125` and `125`, a {{CSSXref("<percentage>")}} between `-100%` and `100%`, or the keyword `none` (equivalent to `0%` in this case). This value specifies the color's distance along the `b` axis, which defines how blue (moving towards `-125`) or yellow ( moving towards `+125`) the color is. Note that these values are signed (allowing both positive and negative values) and theoretically unbounded, meaning that you can set values outside the `±125` (`±100%`) limits. In practice, values cannot exceed `±160`. +- `A` {{optional_inline}} + - : An {{CSSXref("<alpha-value>")}} representing the alpha channel value of the color, where the number `0` corresponds to `0%` (fully transparent) and `1` corresponds to `100%` (fully opaque). Additionally, the keyword `none` can be used to explicitly specify no alpha channel. If the `A` channel value is not explicitly specified, it defaults to 100%. If included, the value is preceded by a slash (`/`). + +> **Note:** See [Missing color components](/en-US/docs/Web/CSS/color_value#missing_color_components) for more information on the effect of `none`. + +#### Relative value syntax + +```text +lab(from L a b[ / A]) +``` + +The parameters are as follows: +- `from ` + - : The keyword `from` is always included when defining a relative color, followed by a {{cssxref("<color>")}} value representing the **origin color**. This is the original color that the relative color is based on. The origin color can be _any_ valid {{cssxref("<color>")}} syntax, including another relative color. - `L` - - : A {{CSSXref("<number>")}} between `0` and `100`, a {{CSSXref("<percentage>")}} between `0%` and `100%`, or the keyword `none`, which specifies the CIE Lightness. Here the number `0` corresponds to `0%` (black) and the number `100` corresponds to `100%` (white). + - : A {{CSSXref("<number>")}} between `0` and `100`, a {{CSSXref("<percentage>")}} between `0%` and `100%`, or the keyword `none` (equivalent to `0%` in this case) This value represents the lightness of the output color. Here the number `0` corresponds to `0%` (black) and the number `100` corresponds to `100%` (white). - `a` - - : A {{CSSXref("<number>")}} between `-125` and `125`, a {{CSSXref("<percentage>")}} between `-100%` and `100%`, or the keyword `none`, which specifies the distance along the `a` axis in the CIELAB colorspace, that is how green/red the color is. + - : A {{CSSXref("<number>")}} between `-125` and `125`, a {{CSSXref("<percentage>")}} between `-100%` and `100%`, or the keyword `none` (equivalent to `0%` in this case). This value represents the output color's distance along the `a` axis, which defines how green (moving towards `-125`) or red (moving towards `+125`) the color is. Note that these values are signed (allowing both positive and negative values) and theoretically unbounded, meaning that you can set values outside the `±125` (`±100%`) limits. In practice, values cannot exceed `±160`. - `b` - - : A {{CSSXref("<number>")}} between `-125` and `125`, a {{CSSXref("<percentage>")}} between `-100%` and `100%`, or the keyword `none`, which specifies the distance along the `b` axis in the CIELAB colorspace, that is how blue/yellow the color is. + - : A {{CSSXref("<number>")}} between `-125` and `125`, a {{CSSXref("<percentage>")}} between `-100%` and `100%`, or the keyword `none` (equivalent to `0%` in this case). This value represents the output color's distance along the `b` axis, which defines how blue (moving towards `-125`) or yellow (moving towards `+125`) the color is. Note that these values are signed (allowing both positive and negative values) and theoretically unbounded, meaning that you can set values outside the `±125` (`±100%`) limits. In practice, values cannot exceed `±160`. - `A` {{optional_inline}} - - : An {{CSSXref("<alpha-value>")}} or the keyword `none`, where the number `1` corresponds to `100%` (full opacity). + - : An {{CSSXref("<alpha-value>")}} representing the alpha channel value of the output color, where the number `0` corresponds to `0%` (fully transparent) and `1` corresponds to `100%` (fully opaque). Additionally, the keyword `none` can be used to explicitly specify no alpha channel. If the `A` channel value is not explicitly specified, it defaults to the alpha channel value of the origin color. If included, the value is preceded by a slash (`/`). + +**Note:** Usually when percentage values have a numeric equivalent in CSS, `100%` is equal to the number `1`. This is not always the case for LAB's lightness and `a` and `b` axes, as mentioned above. With `L`, the range is from 0 to 100, with `100%` equal to `100`. The `a` and `b` values support both negative and positive values, with `100%` being equal to `125` and `-100%` being equal to `-125`. + +#### Defining relative color output channel components + +When using relative color syntax inside a `lab()` function, the browser converts the origin color into an equivalent Lab color (if it is not already specified as such). The color is defined as three distinct color channel values — `l` (lightness), `a` (green/red axis), and `b` (blue/yellow axis) — plus an alpha channel value (`alpha`). These channel values are made available inside the function to be used when defining the output color channel values: + +- The `l` channel value is resolved to a `` between `0` and `100`, inclusive. +- The `a` and `b` channels are each resolved to a `` between `-125` and `125`, inclusive. +- The `alpha` channel is resolved to a `` between `0` and `1`, inclusive. + +When defining a relative color, the different channels of the output color can be expressed in several different ways. Below, we'll study some examples to illustrate these. + +In the first two examples below, we are using relative color syntax. However, the first one outputs the same color as the origin color and the second one outputs a color not based on the origin color at all. They don't really create relative colors! You'd be unlikely to ever use these in a real codebase, and would probably just use an absolute color value instead. We included these examples as a starting point for learning about relative `lab()` syntax. + +Let's start with an origin color of `hsl(0 100% 50%)` (equivalent to `red`). The following function outputs the same color as the origin color — it uses the origin color's `l`, `a`, and `b` channel values (`54.29`, `80.8198`, and `69.8997`) as the output channel values: + +```css +lab(from hsl(0 100% 50%) l a b) +``` + +This function's output color is `lab(54.29 80.8198 69.8997)`. + +The next function uses absolute values for the output color's channel values, outputting a completely different color not based on the origin color: + +```css +lab(from hsl(0 100% 50%) 29.692% 44.89% -29.034%) +``` + +In the above case, the output color is `lab(29.692 56.1125 -36.2925)`. + +The following function creates a relative color based on the origin color: + +```css +lab(from hsl(0 100% 50%) l -100 b) +``` + +This example: + +- Converts the `hsl()` origin color to an equivalent `lab()` color — `lab(54.29 80.8198 69.8997)`. +- Sets the `l` and `b` channel values for the output color to those of the origin `lab()` equivalent's `L` and `b` channel values — those values are `54.29` and `69.8997`, respectively. +- Sets the output color's `a` channel value to a new value not based on the origin color: `-100`. + +The final output color is `lab(54.29 -100 69.8997)`. -> **Note:** Usually when percentage values have a numeric equivalent in CSS, `100%` is equal to the number `1`. -> This case is notable where `100%` is equal to the number `100` for the `L` value and `125` for the `a` and `b` values. +> **Note:** As mentioned above, if the output color is using a different color model to the origin color, the origin color is converted to the same model as the output color in the background so that it can be represented in a way that is compatible (i.e. using the same channels). -> **Note:** See [Missing color components](/en-US/docs/Web/CSS/color_value#missing_color_components) for the effect of `none`. +In the examples we've seen so far in this section, the alpha channels have not been explicitly specified for either the origin or output colors. When the output color alpha channel is not specified, it defaults to the same value as the origin color alpha channel. When the origin color alpha channel is not specified (and it is not a relative color), it defaults to `1`. Therefore, the origin and output alpha channel values are `1` for the above examples. + +Let's look at some examples that specify origin and output alpha channel values. The first one specifies the output alpha channel value as being the same as the origin alpha channel value, whereas the second one specifies a different output alpha channel value, unrelated to the origin alpha channel value. + +```css +lab(from hsl(0 100% 50% / 0.8) l a b / alpha) +/* Computed output color: lab(54.29 80.8198 69.8997 / 0.8) */ + +lab(from hsl(0 100% 50% / 0.8) l a b / 0.5) +/* Computed output color: lab(54.29 80.8198 69.8997 / 0.5) */ +``` + +In the following example, the `hsl()` origin color is again converted to the `lab()` equivalent — `lab(54.29 80.8198 69.8997)`. {{cssxref("calc")}} calculations are applied to the `L`, `a`, `b`, and `A` values, resulting in an output color of `lab(74.29 60.8198 29.8997 / 0.9)`: + +```css +lab(from hsl(0 100% 50%) calc(l + 20) calc(a - 20) calc(b - 40) / calc(alpha - 0.1)) +``` + +> **Note:** Because the origin color channel values are resolved to `` values, you have to add numbers to them when using them in calculations, even in cases where a channel would normally accept ``, ``, or other value types. Adding a `` to a ``, for example, doesn't work. ### Formal syntax @@ -144,6 +245,60 @@ div { {{EmbedLiveSample('Adjusting_opacity_with_lab')}} +### Using relative colors with lab() + +This example styles three {{htmlelement("div")}} elements with different background colors. The middle one is given the unmodified `--base-color`, while the left and right ones are given lightened and darkened variants of that `--base-color`. + +These variants are defined using relative colors — the `--base-color` [custom property](/en-US/docs/Web/CSS/--*) is passed into a `lab()` function, and the output colors have their lightness channel modified to achieve the desired effect via a `calc()` function. The lightened color has 15% added to the lightness channel, and the darkened color has 15% subtracted from the lightness channel. + +```html hidden +
+
+
+
+
+``` + +#### CSS + +```css hidden +#container { + display: flex; + width: 100vw; + height: 100vh; + box-sizing: border-box; +} + +.item { + flex: 1; + margin: 20px; +} +``` + +```css +:root { + --base-color: orange; +} + +#one { + background-color: lab(from var(--base-color) calc(l + 15) a b); +} + +#two { + background-color: var(--base-color); +} + +#three { + background-color: lab(from var(--base-color) calc(l - 15) a b); +} +``` + +#### Result + +The output is as follows: + +{{ EmbedLiveSample("Using relative colors with lab()", "100%", "200") }} + ## Specifications {{Specifications}} @@ -155,5 +310,7 @@ div { ## See also - The [`` data type](/en-US/docs/Web/CSS/color_value) for a list of all color notations +- [Using relative colors](/en-US/docs/Web/CSS/CSS_colors/Relative_colors) +- [CSS colors](/en-US/docs/Web/CSS/CSS_colors) module - [LCH colors in CSS: what, why, and how?](https://lea.verou.me/2020/04/lch-colors-in-css-what-why-and-how/) - [Safari Technology Preview 122 release notes](https://webkit.org/blog/11577/release-notes-for-safari-technology-preview-122/): includes `lab()` and {{cssxref("color_value/lch",'lch()')}} colors diff --git a/files/en-us/web/css/color_value/lch/index.md b/files/en-us/web/css/color_value/lch/index.md index ddda2e87e21c270..99845e4647a4f03 100644 --- a/files/en-us/web/css/color_value/lch/index.md +++ b/files/en-us/web/css/color_value/lch/index.md @@ -3,37 +3,142 @@ title: lch() slug: Web/CSS/color_value/lch page-type: css-function browser-compat: css.types.color.lch +spec-urls: + - https://drafts.csswg.org/css-color-5/#relative-LCH + - https://drafts.csswg.org/css-color/#lab-colors --- {{CSSRef}} -The **`lch()`** functional notation expresses a given color in the LCH color space. It has the same L axis as {{cssxref("color_value/lab","lab()")}}, but uses polar coordinates C (Chroma) and H (Hue). +The **`lch()`** functional notation expresses a given color in the LCH {{glossary("color space")}}. It has the same L axis as {{cssxref("color_value/lab","lab()")}}, but uses polar coordinates C (Chroma) and H (Hue). ## Syntax ```css +/* Absolute values */ lch(29.2345% 44.2 27); lch(52.2345% 72.2 56.2); lch(52.2345% 72.2 56.2 / .5); + +/* Relative values */ +lch(from green l c h / 0.5) +lch(from #0000FF calc(l + 10) c h) +lch(from hsl(180 100% 50%) calc(l - 10) c h) ``` ### Values -Functional notation: `lch(L C H[ / A])` +Below are descriptions of the allowed values for both absolute and [relative colors](/en-US/docs/Web/CSS/CSS_colors/Relative_colors). + +> **Note:** Usually when percentage values have a numeric equivalent in CSS, `100%` is equal to the number `1`. +> This is not the case for `lch()`. Here `100%` is equal to the number `100` for the `L` value and `150` for the `C` value. + +#### Absolute value syntax + +```text +lch(L C H[ / A]) +``` + +The parameters are as follows: - `L` - - : A {{CSSXref("<number>")}} between `0` and `100`, a {{CSSXref("<percentage>")}} between `0%` and `100%`, or the keyword `none`, which specifies the CIE Lightness. Here the number `0` corresponds to `0%` (black) and the number `100` corresponds to `100%` (white). + - : A {{CSSXref("<number>")}} between `0` and `100`, a {{CSSXref("<percentage>")}} between `0%` and `100%`, or the keyword `none` (equivalent to `0%` in this case). This value specifies the color's lightness. Here the number `0` corresponds to `0%` (black) and the number `100` corresponds to `100%` (white). - `C` - - : A {{CSSXref("<number>")}}, a {{CSSXref("<percentage>")}}, or the keyword `none`, where `0%` is `0` and `100%` is the number `150`. It is a measure of the chroma (roughly representing the "amount of color"). Its minimum useful value is `0`, while its maximum is theoretically unbounded (but in practice does not exceed `230`). + - : A {{CSSXref("<number>")}}, a {{CSSXref("<percentage>")}}, or the keyword `none` (equivalent to `0%` in this case). This value is a measure of the color's chroma (roughly representing the "amount of color"). Its minimum useful value is `0%`, or `0`, while its maximum is theoretically unbounded (but in practice does not exceed `230`), with `100%` being equivalent to `150`. - `H` - - : A {{CSSXref("<number>")}}, an {{CSSXref("<angle>")}}, or the keyword `none`, which represents the hue angle. More details on this type can be found on the {{CSSXref("<hue>")}} reference. + + - : A {{CSSXref("<number>")}}, an {{CSSXref("<angle>")}}, or the keyword `none` (equivalent to `0deg` in this case) representing the color's {{CSSXref("<hue>")}} angle. + + > **Note:** The angles corresponding to particular hues differ across the sRGB (used by {{CSSXref("color_value/hsl", "hsl()")}} and {{CSSXref("color_value/hwb", "hwb()")}}), CIELAB (used by `lch()`), and Oklab (used by {{CSSXref("color_value/oklch", "oklch()")}}) color spaces. See the {{CSSXref("<hue>")}} reference page for more detail and examples. + - `A` {{optional_inline}} - - : An {{CSSXref("<alpha-value>")}} or the keyword `none`, where the number `1` corresponds to `100%` (full opacity). + - : An {{CSSXref("<alpha-value>")}} representing the alpha channel value of the color, where the number `0` corresponds to `0%` (fully transparent) and `1` corresponds to `100%` (fully opaque). Additionally, the keyword `none` can be used to explicitly specify no alpha channel. If the `A` channel value is not explicitly specified, it defaults to 100%. If included, the value is preceded by a slash (`/`). -> **Note:** Usually when percentage values have a numeric equivalent in CSS, `100%` is equal to the number `1`. -> This case is notable where `100%` is equal to the number `100` for the `L` value and `150` for the `C` value. +> **Note:** See [Missing color components](/en-US/docs/Web/CSS/color_value#missing_color_components) for more information on the effect of `none`. + +#### Relative value syntax + +```text +lch(from L C H[ / A]) +``` + +The parameters are as follows: + +- `from ` + - : The keyword `from` is always included when defining a relative color, followed by a {{cssxref("<color>")}} value representing the **origin color**. This is the original color that the relative color is based on. The origin color can be _any_ valid {{cssxref("<color>")}} syntax, including another relative color. +- `L` + - : A {{CSSXref("<number>")}} between `0` and `100`, a {{CSSXref("<percentage>")}} between `0%` and `100%`, or the keyword `none` (equivalent to `0%` in this case). This value represents the lightness value of the output color. Here the number `0` corresponds to `0%` (black) and the number `100` corresponds to `100%` (white). +- `C` + - : A {{CSSXref("<number>")}}, a {{CSSXref("<percentage>")}}, or the keyword `none` (equivalent to `0%` in this case). This value represents the output color's chroma value (roughly representing the "amount of color"). Its minimum useful value is `0%`, or `0`, while its maximum is theoretically unbounded (but in practice does not exceed `230`), with `100%` being equivalent to `150`. +- `H` + - : A {{CSSXref("<number>")}}, an {{CSSXref("<angle>")}}, or the keyword `none` representing the output color's {{CSSXref("<hue>")}} angle. +- `A` {{optional_inline}} + - : An {{CSSXref("<alpha-value>")}} representing the alpha channel value of the output color, where the number `0` corresponds to `0%` (fully transparent) and `1` corresponds to `100%` (fully opaque). Additionally, the keyword `none` can be used to explicitly specify no alpha channel. If the `A` channel value is not explicitly specified, it defaults to the alpha channel value of the origin color. If included, the value is preceded by a slash (`/`). + +#### Defining relative color output channel components + +When using relative color syntax inside an `lch()` function, the browser converts the origin color into an equivalent Lch color (if it is not already specified as such) The color is defined as three distinct color channel values — `l` (lightness), `c` (chroma), and `h` (hue) — plus an alpha channel value (`alpha`). These channel values are made available inside the function to be used when defining the output color channel values: + +- The `l` channel value is resolved to a `` between `0` and `100`, inclusive. +- The `c` channel value is resolved to a `` between `0` and `150`, inclusive. +- The `h` channel value is resolved to a `` between `0` and `360`, inclusive. +- The `alpha` channel is resolved to a `` between `0` and `1`, inclusive. + +When defining a relative color, the different channels of the output color can be expressed in several different ways. Below, we'll study some examples to illustrate these. + +In the first two examples below, we are using relative color syntax. However, the first one outputs the same color as the origin color and the second one outputs a color not based on the origin color at all. They don't really create relative colors! You'd be unlikely to ever use these in a real codebase, and would probably just use an absolute color value instead. We included these examples as a starting point for learning about relative `lch()` syntax. + +Let's start with an origin color of `hsl(0 100% 50%)` (equivalent to `red`). The following function outputs the same color as the origin color — it uses the origin color's `l`, `c`, and `h` channel values (`54.29`, `106.854`, and `40.856`) as the output channel values: + +```css +lch(from hsl(0 100% 50%) l c h) +``` + +This function's output color is `lch(54.29 106.854 40.856)`. + +The next function uses absolute values for the output color's channel values, outputting a completely different color not based on the origin color: + +```css +lch(from hsl(0 100% 50%) 29.6871% 66.83 327.109) +``` + +In the above case, the output color is `lch(29.6871 66.83 327.109)`. + +The following function creates a relative color based on the origin color: + +```css +lch(from hsl(0 100% 50%) 70 150 h) +``` + +This example: + +- Converts the `hsl()` origin color to an equivalent `lch()` color — `lch(54.29 106.854 40.856)`. +- Sets the `H` channel value for the output color to that of the origin `lch()` equivalent's `H` channel value — `40.856`. +- Sets the output color's `L` and `C` channel values to new values not based on the origin color: `70` and `150` respectively. -> **Note:** See [Missing color components](/en-US/docs/Web/CSS/color_value#missing_color_components) for the effect of `none`. +The final output color is `lch(70 150 40.856)`. + +> **Note:** As mentioned above, if the output color is using a different color model to the origin color, the origin color is converted to the same model as the output color in the background so that it can be represented in a way that is compatible (i.e. using the same channels). + +In the examples we've seen so far in this section, the alpha channels have not been explicitly specified for either the origin or output colors. When the output color alpha channel is not specified, it defaults to the same value as the origin color alpha channel. When the origin color alpha channel is not specified (and it is not a relative color), it defaults to `1`. Therefore, the origin and output alpha channel values are `1` for the above examples. + +Let's look at some examples that specify origin and output alpha channel values. The first one specifies the output alpha channel value as being the same as the origin alpha channel value, whereas the second one specifies a different output alpha channel value, unrelated to the origin alpha channel value. + +```css +lch(from hsl(0 100% 50% / 0.8) l c h / alpha) +/* Computed output color: lch(54.29 106.854 40.856 / 0.8) */ + +lch(from hsl(0 100% 50% / 0.8) l c h / 0.5) +/* Computed output color: lch(54.29 106.854 40.856 / 0.5) */ +``` + +In the following example, the `hsl()` origin color is again converted to the `lch()` equivalent — `lch(54.29 106.854 40.856)`. {{cssxref("calc")}} calculations are applied to the `L`, `C`, `H`, and `A` values, resulting in an output color of `lch(74.29 86.8541 0.856018 / 0.9)`: + +```css +lch(from hsl(0 100% 50%) calc(l + 20) calc(c - 20) calc(h - 40) / calc(alpha - 0.1)) +``` + +> **Note:** Because the origin color channel values are resolved to `` values, you have to add numbers to them when using them in calculations, even in cases where a channel would normally accept ``, ``, or other value types. Adding a `` to a ``, for example, doesn't work. ### Formal syntax @@ -144,6 +249,60 @@ div { {{EmbedLiveSample("adjusting_opacity_with_lch")}} +### Using relative colors with lch() + +This example styles three {{htmlelement("div")}} elements with different background colors. The middle one is given the unmodified `--base-color`, while the left and right ones are given lightened and darkened variants of that `--base-color`. + +These variants are defined using relative colors — the `--base-color` [custom property](/en-US/docs/Web/CSS/--*) is passed into an `lch()` function, and the output colors have their lightness channel modified to achieve the desired effect via a `calc()` function. The lightened color has 15% added to the lightness channel, and the darkened color has 15% subtracted from the lightness channel. + +```html hidden +
+
+
+
+
+``` + +#### CSS + +```css hidden +#container { + display: flex; + width: 100vw; + height: 100vh; + box-sizing: border-box; +} + +.item { + flex: 1; + margin: 20px; +} +``` + +```css +:root { + --base-color: orange; +} + +#one { + background-color: lch(from var(--base-color) calc(l + 15) c h); +} + +#two { + background-color: var(--base-color); +} + +#three { + background-color: lch(from var(--base-color) calc(l - 15) c h); +} +``` + +#### Result + +The output is as follows: + +{{ EmbedLiveSample("Using relative colors with lch()", "100%", "200") }} + ## Specifications {{Specifications}} @@ -155,5 +314,7 @@ div { ## See also - [List of all color notations](/en-US/docs/Web/CSS/color_value) +- [Using relative colors](/en-US/docs/Web/CSS/CSS_colors/Relative_colors) +- [CSS colors](/en-US/docs/Web/CSS/CSS_colors) module - {{CSSXref("<hue>")}} data type - [LCH colors in CSS: what, why, and how?](https://lea.verou.me/2020/04/lch-colors-in-css-what-why-and-how/) diff --git a/files/en-us/web/css/color_value/oklab/index.md b/files/en-us/web/css/color_value/oklab/index.md index 42db6d3a7403591..903ea049677fe1b 100644 --- a/files/en-us/web/css/color_value/oklab/index.md +++ b/files/en-us/web/css/color_value/oklab/index.md @@ -3,11 +3,14 @@ title: oklab() slug: Web/CSS/color_value/oklab page-type: css-function browser-compat: css.types.color.oklab +spec-urls: + - https://drafts.csswg.org/css-color-5/#relative-Oklab + - https://drafts.csswg.org/css-color/#ok-lab --- {{CSSRef}} -The **`oklab()`** functional notation expresses a given color in the Oklab color space, which attempts to mimic how color is perceived by the human eye. The `oklab()` works with a Cartesian coordinate system on the Oklab color space, the a- and b-axes. If you want a polar color system, chroma and hue, use {{cssxref("color_value/oklch", "oklch()")}}. +The **`oklab()`** functional notation expresses a given color in the Oklab {{glossary("color space")}}, which attempts to mimic how color is perceived by the human eye. The `oklab()` works with a Cartesian coordinate system on the Oklab color space, the a- and b-axes. If you want a polar color system, chroma and hue, use {{cssxref("color_value/oklch", "oklch()")}}. Oklab is a perceptual color space and is useful to: @@ -20,25 +23,122 @@ The function `oklab()` can represent any color from the Oklab color space that i ## Syntax ```css +/* Absolute values */ oklab(40.1% 0.1143 0.045); oklab(59.69% 0.1007 0.1191); oklab(59.69% 0.1007 0.1191 / 0.5); + +/* Relative values */ +oklab(from green l a b / 0.5) +oklab(from #0000FF calc(l + 0.1) a b) +oklab(from hsl(180 100% 50%) calc(l - 0.1) a b) ``` ### Values -Functional notation: `oklab(L a b[ / A])` +Below are descriptions of the allowed values for both absolute and [relative colors](/en-US/docs/Web/CSS/CSS_colors/Relative_colors). + +#### Absolute value syntax + +```text +oklab(L a b[ / A]) +``` + +The parameters are as follows: - `L` - - : A {{CSSXref("<number>")}} between `0` and `1`, a {{CSSXref("<percentage>")}} between `0%` and `100%`, or the keyword `none`, where the number `0` corresponds to `0%` (black) and the number `1` corresponds to `100%` (white). `L` specifies the perceived lightness. + - : A {{CSSXref("<number>")}} between `0` and `1`, a {{CSSXref("<percentage>")}} between `0%` and `100%`, or the keyword `none` (equivalent to `0%` in this case). This value specifies the color's perceived lightness. The number `0` corresponds to `0%` (black) and the number `1` corresponds to `100%` (white). - `a` - - : A {{CSSXref("<number>")}} between `-0.4` and `0.4`, a {{CSSXref("<percentage>")}} between `-100%` and `100%`, or the keyword `none`. It specifies the distance along the `a` axis in the Oklab colorspace, that is, how green or red the color is. + - : A {{CSSXref("<number>")}} between `-0.4` and `0.4`, a {{CSSXref("<percentage>")}} between `-100%` and `100%`, or the keyword `none` (equivalent to `0%` in this case). This value specifies the color's distance along the `a` axis in the Oklab color space, which defines how green (moving towards `-0.4`) or red (moving towards `+0.4`) the color is. Note that these values are signed (allowing both positive and negative values) and theoretically unbounded, meaning that you can set values outside the `±0.4` (`±100%`) limits. In practice, values cannot exceed `±0.5`. - `b` - - : A {{CSSXref("<number>")}} between `-0.4` and `0.4`, a {{CSSXref("<percentage>")}} between `-100%` and `100%`, or the keyword `none`. It specifies the distance along the `b` axis in the Oklab colorspace, that is, how blue or yellow the color is. + - : A {{CSSXref("<number>")}} between `-0.4` and `0.4`, a {{CSSXref("<percentage>")}} between `-100%` and `100%`, or the keyword `none` (equivalent to `0%` in this case). This value specifies the color's distance along the `b` axis in the Oklab color space, which defines how blue (moving towards `-0.4`) or yellow (moving towards `+0.4`) the color is. Note that these values are signed (allowing both positive and negative values) and theoretically unbounded, meaning that you can set values outside the `±0.4` (`±100%`) limits. In practice, values cannot exceed `±0.5`. - `A` {{optional_inline}} - - : An {{CSSXref("<alpha-value>")}} or the keyword `none`, where the number `1` corresponds to `100%` (full opacity). + - : An {{CSSXref("<alpha-value>")}} representing the alpha channel value of the color, where the number `0` corresponds to `0%` (fully transparent) and `1` corresponds to `100%` (fully opaque). Additionally, the keyword `none` can be used to explicitly specify no alpha channel. If the `A` channel value is not explicitly specified, it defaults to 100%. If included, the value is preceded by a slash (`/`). + +> **Note:** See [Missing color components](/en-US/docs/Web/CSS/color_value#missing_color_components) for more information on the effect of `none`. + +#### Relative value syntax + +```text +oklab(from L a b[ / A]) +``` + +The parameters are as follows: + +- `from ` + - : The keyword `from` is always included when defining a relative color, followed by a {{cssxref("<color>")}} value representing the **origin color**. This is the original color that the relative color is based on. The origin color can be _any_ valid {{cssxref("<color>")}} syntax, including another relative color. +- `L` + - : A {{CSSXref("<number>")}} between `0` and `1`, a {{CSSXref("<percentage>")}} between `0%` and `100%`, or the keyword `none` (equivalent to `0%` in this case). This value represents the lightness of the output color. The number `0` corresponds to `0%` (black) and the number `1` corresponds to `100%` (white). +- `a` + - : A {{CSSXref("<number>")}} between `-0.4` and `0.4`, a {{CSSXref("<percentage>")}} between `-100%` and `100%`, or the keyword `none` (equivalent to `0%` in this case). This value represents the output color's distance along the `a` axis in the Oklab color space, which defines how green (moving towards `-0.4`) or red (moving towards `+0.4`) the color is. Note that these values are signed (allowing both positive and negative values) and theoretically unbounded, meaning that you can set values outside the `±0.4` (`±100%`) limits. In practice, values cannot exceed `±0.5`. +- `b` + - : A {{CSSXref("<number>")}} between `-0.4` and `0.4`, a {{CSSXref("<percentage>")}} between `-100%` and `100%`, or the keyword `none` (equivalent to `0%` in this case). This value represents the output color's distance along the `b` axis in the Oklab color space, which defines how blue (moving towards `-0.4`) or yellow (moving towards `+0.4`) the color is. Note that these values are signed (allowing both positive and negative values) and theoretically unbounded, meaning that you can set values outside the `±0.4` (`±100%`) limits. In practice, values cannot exceed `±0.5`. +- `A` {{optional_inline}} + - : An {{CSSXref("<alpha-value>")}} representing the alpha channel value of the output color, where the number `0` corresponds to `0%` (fully transparent) and `1` corresponds to `100%` (fully opaque). Additionally, the keyword `none` can be used to explicitly specify no alpha channel. If the `A` channel value is not explicitly specified, it defaults to the alpha channel value of the origin color. If included, the value is preceded by a slash (`/`). + +#### Defining relative color output channel components + +When using relative color syntax inside an `oklab()` function, the browser converts the origin color into an equivalent Oklab color (if it is not already specified as such). The color defined as three distinct color channel values — `l` (lightness), `a` (green/red axis), and `b` (blue/yellow axis) — plus an alpha channel value (`alpha`). These channel values are made available inside the function to be used when defining the output color channel values: + +- The `l` channel value is resolved to a `` between `0` and `1`, inclusive. +- The `a` and `b` channels are each resolved to a `` between `-0.4` and `0.4`, inclusive. +- The `alpha` channel is resolved to a `` between `0` and `1`, inclusive. + +When defining a relative color, the different channels of the output color can be expressed in several different ways. Below, we'll study some examples to illustrate these. + +In the first two examples below, we are using relative color syntax. However, the first one outputs the same color as the origin color and the second one outputs a color not based on the origin color at all. They don't really create relative colors! You'd be unlikely to ever use these in a real codebase, and would probably just use an absolute color value instead. We included these examples as a starting point for learning about relative `oklab()` syntax. + +Let's start with an origin color of `hsl(0 100% 50%)` (equivalent to `red`). The following function outputs the same color as the origin color — it uses the origin color's `l`, `a`, and `b` channel values (`0.627966`, `0.22488`, and `0.125859`) as the output channel values: + +```css +oklab(from hsl(0 100% 50%) l a b) +``` + +This function's output color is `oklab(0.627966 0.22488 0.125859)`. + +The next function uses absolute values for the output color's channel values, outputting a completely different color not based on the origin color: + +```css +oklab(from hsl(0 100% 50%) 42.1% 0.165 -0.101) +``` + +In the above case, the output color is `oklab(0.421 0.165 -0.101)`. + +The following function creates a relative color based on the origin color: + +```css +oklab(from hsl(0 100% 50%) l -0.3 b) +``` + +This example: + +- Converts the `hsl()` origin color to an equivalent `oklab()` color — `oklab(0.627966 0.22488 0.125859)`. +- Sets the `L` and `b` channel values for the output color to those of the origin `oklab()` equivalent's `L` and `b` channel values — those values are `0.627966` and `0.125859`, respectively. +- Sets the output color's `a` channel value to a new value not based on the origin color: `-0.3`. + +The final output color is `oklab(0.627966 -0.3 0.125859)`. + +> **Note:** As mentioned above, if the output color is using a different color model to the origin color, the origin color is converted to the same model as the output color in the background so that it can be represented in a way that is compatible (i.e. using the same channels). -> **Note:** See [Missing color components](/en-US/docs/Web/CSS/color_value#missing_color_components) for the effect of `none`. +In the examples we've seen so far in this section, the alpha channels have not been explicitly specified for either the origin or output colors. When the output color alpha channel is not specified, it defaults to the same value as the origin color alpha channel. When the origin color alpha channel is not specified (and it is not a relative color), it defaults to `1`. Therefore, the origin and output alpha channel values are `1` for the above examples. + +Let's look at some examples that specify origin and output alpha channel values. The first one specifies the output alpha channel value as being the same as the origin alpha channel value, whereas the second one specifies a different output alpha channel value, unrelated to the origin alpha channel value. + +```css +oklab(from hsl(0 100% 50% / 0.8) l a b / alpha) +/* Computed output color: oklab(0.627966 0.22488 0.125859 / 0.8) */ + +oklab(from hsl(0 100% 50% / 0.8) l a b / 0.5) +/* Computed output color: oklab(0.627966 0.22488 0.125859 / 0.5) */ +``` + +In the following example, the `hsl()` origin color is again converted to the `oklab()` equivalent — `oklab(0.627966 0.22488 0.125859)`. {{cssxref("calc")}} calculations are applied to the `L`, `a`, `b`, and `A` values, resulting in an output color of `oklab(0.827966 0.14488 -0.0741406 / 0.9)`: + +```css +oklab(from hsl(0 100% 50%) calc(l + 0.2) calc(a - 0.08) calc(b - 0.2) / calc(alpha - 0.1)) +``` + +> **Note:** Because the origin color channel values are resolved to `` values, you have to add numbers to them when using them in calculations, even in cases where a channel would normally accept ``, ``, or other value types. Adding a `` to a ``, for example, doesn't work. ### Formal syntax @@ -149,6 +249,60 @@ div { {{EmbedLiveSample("Adjusting_opacity_with_oklab", "100%", 155)}} +### Using relative colors with oklab() + +This example styles three {{htmlelement("div")}} elements with different background colors. The middle one is given the unmodified `--base-color`, while the left and right ones are given lightened and darkened variants of that `--base-color`. + +These variants are defined using relative colors — the `--base-color` [custom property](/en-US/docs/Web/CSS/--*) is passed into an `oklab()` function, and the output colors have their lightness channel modified to achieve the desired effect via a `calc()` function. The lightened color has `0.15` (15%) added to the lightness channel, and the darkened color has `0.15` (15%) subtracted from the lightness channel. + +```html hidden +
+
+
+
+
+``` + +#### CSS + +```css hidden +#container { + display: flex; + width: 100vw; + height: 100vh; + box-sizing: border-box; +} + +.item { + flex: 1; + margin: 20px; +} +``` + +```css +:root { + --base-color: orange; +} + +#one { + background-color: oklab(from var(--base-color) calc(l + 0.15) a b); +} + +#two { + background-color: var(--base-color); +} + +#three { + background-color: oklab(from var(--base-color) calc(l - 0.15) a b); +} +``` + +#### Result + +The output is as follows: + +{{ EmbedLiveSample("Using relative colors with oklab()", "100%", "200") }} + ## Specifications {{Specifications}} @@ -160,6 +314,8 @@ div { ## See also - The [`` data type](/en-US/docs/Web/CSS/color_value) for a list of all color notations -- {{cssxref("color_value/oklch",'oklch()')}}: Another functional notation using the same color space as `oklab()` but in a polar coordinate system +- {{cssxref("color_value/lab","lab()")}} and {{cssxref("color_value/oklch","oklch()")}} color functions +- [Using relative colors](/en-US/docs/Web/CSS/CSS_colors/Relative_colors) +- [CSS colors](/en-US/docs/Web/CSS/CSS_colors) module - [A perceptual color space for image processing](https://bottosson.github.io/posts/oklab/) on bottosson.github.io (2023) - [OKLAB color wheel](https://observablehq.com/@shan/oklab-color-wheel) on observablehq.com diff --git a/files/en-us/web/css/color_value/oklch/index.md b/files/en-us/web/css/color_value/oklch/index.md index 89472ba6bb736d0..50a36b5f44e8930 100644 --- a/files/en-us/web/css/color_value/oklch/index.md +++ b/files/en-us/web/css/color_value/oklch/index.md @@ -3,34 +3,139 @@ title: oklch() slug: Web/CSS/color_value/oklch page-type: css-function browser-compat: css.types.color.oklch +spec-urls: + - https://drafts.csswg.org/css-color-5/#relative-Oklch + - https://drafts.csswg.org/css-color/#ok-lab --- {{CSSRef}} -The **`oklch()`** functional notation expresses a given color in the Oklch color space. It has the same L axis as {{cssxref("color_value/oklab","oklab()")}}, but uses polar coordinates C (Chroma) and H (Hue). +The **`oklch()`** functional notation expresses a given color in the Oklch {{glossary("color space")}}. It has the same L axis as {{cssxref("color_value/oklab","oklab()")}}, but uses polar coordinates C (Chroma) and H (Hue). ## Syntax ```css +/* Absolute values */ oklch(40.1% 0.123 21.57) oklch(59.69% 0.156 49.77) oklch(59.69% 0.156 49.77 / .5) + +/* Relative values */ +oklch(from green l c h / 0.5) +oklch(from #0000FF calc(l + 0.1) c h) +oklch(from hsl(180 100% 50%) calc(l - 0.1) c h) ``` ### Values -Functional notation: `oklch(L C H[ / A])` +Below are descriptions of the allowed values for both absolute and [relative colors](/en-US/docs/Web/CSS/CSS_colors/Relative_colors). + +#### Absolute value syntax + +```text +oklch(L C H[ / A]) +``` + +The parameters are as follows: + +- `L` + - : A {{CSSXref("<number>")}} between `0` and `1`, a {{CSSXref("<percentage>")}} between `0%` and `100%`, or the keyword `none` (equivalent to `0%` in this case). This value specifies the color's perceived lightness. In this case, the number `0` corresponds to `0%` (black) and the number `1` corresponds to `100%` (white). +- `C` + - : A {{CSSXref("<number>")}}, a {{CSSXref("<percentage>")}}, or the keyword `none` (equivalent to `0%` in this case). This value is a measure of the color's chroma (roughly representing the "amount of color"). Its minimum useful value is `0`, while the maximum is theoretically unbounded (but in practice does not exceed `0.5`). In this case, `0%` is `0` and `100%` is the number `0.4`. +- `H` + + - : A {{CSSXref("<number>")}}, an {{CSSXref("<angle>")}}, or the keyword `none` (equivalent to `0deg` in this case) representing the color's {{CSSXref("<hue>")}} angle. + > **Note:** The angles corresponding to particular hues differ across the sRGB (used by {{CSSXref("color_value/hsl", "hsl()")}} and {{CSSXref("color_value/hwb", "hwb()")}}), CIELAB (used by {{CSSXref("color_value/lch", "lch()")}}), and Oklab (used by `oklch()`) color spaces. See the {{CSSXref("<hue>")}} reference page for more detail and examples. + +- `A` {{optional_inline}} + - : An {{CSSXref("<alpha-value>")}} representing the alpha channel value of the color, where the number `0` corresponds to `0%` (fully transparent) and `1` corresponds to `100%` (fully opaque). Additionally, the keyword `none` can be used to explicitly specify no alpha channel. If the `A` channel value is not explicitly specified, it defaults to 100%. If included, the value is preceded by a slash (`/`). + +> **Note:** See [Missing color components](/en-US/docs/Web/CSS/color_value#missing_color_components) for more information on the effect of `none`. + +#### Relative value syntax + +```text +oklch(from L C H[ / A]) +``` + +The parameters are as follows: + +- `from ` + - : The keyword `from` is always included when defining a relative color, followed by a {{cssxref("<color>")}} value representing the **origin color**: This is the original color that the relative color is based on. The origin color can be _any_ valid {{cssxref("<color>")}} syntax, including another relative color. - `L` - - : A {{CSSXref("<number>")}} between `0` and `1`, a {{CSSXref("<percentage>")}} between `0%` and `100%`, or the keyword `none`, where the number `0` corresponds to `0%` (black) and the number `1` corresponds to `100%` (white). `L` specifies the perceived lightness. + - : A {{CSSXref("<number>")}} between `0` and `1`, a {{CSSXref("<percentage>")}} between `0%` and `100%`, or the keyword `none` (equivalent to `0%` in this case). This represents the lightness value of the output color. Here the number `0` corresponds to `0%` (black) and the number `1` corresponds to `100%` (white). - `C` - - : A {{CSSXref("<number>")}}, a {{CSSXref("<percentage>")}}, or the keyword `none`, where `0%` is `0` and `100%` is the number `0.4`. It is a measure of the chroma (roughly representing the "amount of color"). Its minimum useful value is `0`, while the maximum is theoretically unbounded (but in practice does not exceed `0.5`). + - : A {{CSSXref("<number>")}}, a {{CSSXref("<percentage>")}}, or the keyword `none` (equivalent to `0%` in this case). This value represents the output color's chroma value (roughly representing the "amount of color"). Its minimum useful value is `0`, while its maximum is theoretically unbounded (but in practice does not exceed `0.5`). In this case, `0%` is `0` and `100%` is the number `0.4`. - `H` - - : A {{CSSXref("<number>")}}, an {{CSSXref("<angle>")}}, or the keyword `none`, which represents the hue angle. More details on this type can be found on the {{CSSXref("<hue>")}} reference. + - : A {{CSSXref("<number>")}}, an {{CSSXref("<angle>")}}, or the keyword `none` (equivalent to `0deg` in this case) representing the output color's {{CSSXref("<hue>")}} angle. - `A` {{optional_inline}} - - : An {{CSSXref("<alpha-value>")}} or the keyword `none`, where the number `1` corresponds to `100%` (full opacity). + - : An {{CSSXref("<alpha-value>")}} representing the alpha channel value of the output color, where the number `0` corresponds to `0%` (fully transparent) and `1` corresponds to `100%` (fully opaque). Additionally, the keyword `none` can be used to explicitly specify no alpha channel. If the `A` channel value is not explicitly specified, it defaults to the alpha channel value of the origin color. If included, the value is preceded by a slash (`/`). + +#### Defining relative color output channel components + +When using relative color syntax inside an `oklch()` function, the browser converts the origin color into an equivalent Oklch color (if it is not already specified as such). The color is defined as three distinct color channel values — `l` (lightness), `c` (chroma), and `h` (hue) — plus an alpha channel value (`alpha`). These channel values are made available inside the function to be used when defining the output color channel values: + +- The `l` channel value is resolved to a `` between `0` and `1`, inclusive. +- The `c` channel value is resolved to a `` between `0` and `0.4`, inclusive. +- The `h` channel value is resolved to a `` between `0` and `360`, inclusive. +- The `alpha` channel is resolved to a `` between `0` and `1`, inclusive. + +When defining a relative color, the different channels of the output color can be expressed in several different ways. Below, we'll study some examples to illustrate these. + +In the first two examples below, we are using relative color syntax. However, the first one outputs the same color as the origin color and the second one outputs a color not based on the origin color at all. They don't really create relative colors! You'd be unlikely to ever use these in a real codebase, and would probably just use an absolute color value instead. We included these examples as a starting point for learning about relative `oklch()` syntax. + +Let's start with an origin color of `hsl(0 100% 50%)` (equivalent to `red`). The following function outputs the same color as the origin color — it uses the origin color's `l`, `c`, and `h` channel values (`0.627966`, `0.257704`, and `29.2346`) as the output channel values: + +```css +oklch(from hsl(0 100% 50%) l c h) +``` + +This function's output color is `oklch(0.627966 0.257704 29.2346)`. + +The next function uses absolute values for the output color's channel values, outputting a completely different color not based on the origin color: + +```css +oklch(from hsl(0 100% 50%) 42.1% 0.25 328.363) +``` + +In the above case, the output color is `oklch(0.421 0.25 328.363)`. + +The following function creates a relative color based on the origin color: + +```css +oklch(from hsl(0 100% 50%) 0.8 0.4 h) +``` + +This example: + +- Converts the `hsl()` origin color to an equivalent `oklch()` color — `oklch(0.627966 0.257704 29.2346)`. +- Sets the `H` channel value for the output color to that of the origin `oklch()` equivalent's `H` channel value — `29.2346`. +- Sets the output color's `L` and `C` channel values to new values not based on the origin color: `0.8` and `0.4` respectively. + +The final output color is `oklch(0.8 0.4 29.2346)`. -> **Note:** See [Missing color components](/en-US/docs/Web/CSS/color_value#missing_color_components) for the effect of `none`. +> **Note:** As mentioned above, if the output color is using a different color model to the origin color, the origin color is converted to the same model as the output color in the background so that it can be represented in a way that is compatible (i.e. using the same channels). + +In the examples we've seen so far in this section, the alpha channels have not been explicitly specified for either the origin or output colors. When the output color alpha channel is not specified, it defaults to the same value as the origin color alpha channel. When the origin color alpha channel is not specified (and it is not a relative color), it defaults to `1`. Therefore, the origin and output alpha channel values are `1` for the above examples. + +Let's look at some examples that specify origin and output alpha channel values. The first one specifies the output alpha channel value as being the same as the origin alpha channel value, whereas the second one specifies a different output alpha channel value, unrelated to the origin alpha channel value. + +```css +oklch(from hsl(0 100% 50% / 0.8) l c h / alpha) +/* Computed output color: oklch(0.627966 0.257704 29.2346 / 0.8) */ + +oklch(from hsl(0 100% 50% / 0.8) l c h / 0.5) +/* Computed output color: oklch(0.627966 0.257704 29.2346 / 0.5) */ +``` + +In the following example, the `hsl()` origin color is again converted to the `oklch()` equivalent — `oklch(0.627966 0.257704 29.2346)`. {{cssxref("calc")}} calculations are applied to the `L`, `C`, `H`, and `A` values, resulting in an output color of `oklch(0.827966 0.357704 9.23462 / 0.9)`: + +```css +oklch(from hsl(0 100% 50%) calc(l + 0.2) calc(c + 0.1) calc(h - 20) / calc(alpha - 0.1)) +``` + +> **Note:** Because the origin color channel values are resolved to `` values, you have to add numbers to them when using them in calculations, even in cases where a channel would normally accept ``, ``, or other value types. Adding a `` to a ``, for example, doesn't work. ### Formal syntax @@ -141,6 +246,60 @@ div { {{EmbedLiveSample("adjusting_the_alpha_value_of_a_color")}} +### Using relative colors with oklch() + +This example styles three {{htmlelement("div")}} elements with different background colors. The middle one is given the unmodified `--base-color`, while the left and right ones are given lightened and darkened variants of that `--base-color`. + +These variants are defined using relative colors — the `--base-color` [custom property](/en-US/docs/Web/CSS/--*) is passed into an `oklch()` function, and the output colors have their lightness channel modified to achieve the desired effect via a `calc()` function. The lightened color has `0.15` (15%) added to the lightness channel, and the darkened color has `0.15` (15%) subtracted from the lightness channel. + +```html hidden +
+
+
+
+
+``` + +#### CSS + +```css hidden +#container { + display: flex; + width: 100vw; + height: 100vh; + box-sizing: border-box; +} + +.item { + flex: 1; + margin: 20px; +} +``` + +```css +:root { + --base-color: orange; +} + +#one { + background-color: oklch(from var(--base-color) calc(l + 0.15) c h); +} + +#two { + background-color: var(--base-color); +} + +#three { + background-color: oklch(from var(--base-color) calc(l - 0.15) c h); +} +``` + +#### Result + +The output is as follows: + +{{ EmbedLiveSample("Using relative colors with oklch()", "100%", "200") }} + ## Specifications {{Specifications}} @@ -152,6 +311,9 @@ div { ## See also - [List of all color notations](/en-US/docs/Web/CSS/color_value) +- [Using relative colors](/en-US/docs/Web/CSS/CSS_colors/Relative_colors) +- [CSS colors](/en-US/docs/Web/CSS/CSS_colors) module - {{CSSXref("<hue>")}} data type +- {{cssxref("color_value/lch","lch()")}} and {{cssxref("color_value/oklab","oklab()")}} color functions - [A perceptual color space for image processing](https://bottosson.github.io/posts/oklab/) - [OKLCH in CSS](https://evilmartians.com/chronicles/oklch-in-css-why-quit-rgb-hsl) diff --git a/files/en-us/web/css/color_value/rgb/index.md b/files/en-us/web/css/color_value/rgb/index.md index 43439ef147c12d9..20248851daf3f63 100644 --- a/files/en-us/web/css/color_value/rgb/index.md +++ b/files/en-us/web/css/color_value/rgb/index.md @@ -3,37 +3,134 @@ title: rgb() slug: Web/CSS/color_value/rgb page-type: css-function browser-compat: css.types.color.rgb +spec-urls: + - https://drafts.csswg.org/css-color-5/#relative-RGB + - https://drafts.csswg.org/css-color/#rgb-functions --- {{CSSRef}} -The **`rgb()`** functional notation expresses a color according to its red, green, and blue components. An optional alpha component represents the color's transparency. - -> **Note:** The legacy `rgba()` syntax is an alias for `rgb()`, accepting the same parameters and behaving in the same way. +The **`rgb()`** functional notation expresses a color in the {{glossary("RGB", "sRGB")}} {{glossary("color space")}} according to its red, green, and blue components. An optional alpha component represents the color's transparency. {{EmbedInteractiveExample("pages/css/function-rgb.html")}} ## Syntax ```css +/* Absolute values */ rgb(255 255 255) rgb(255 255 255 / 50%) + +/* Relative values */ +rgb(from green r g b / 0.5) +rgb(from #0000FF calc(r + 40) calc(g + 40) b) +rgb(from hwb(120deg 10% 20%) r g calc(b + 200)) ``` -The function also accepts a legacy syntax in which all values are separated with commas. +The `rgba()` function can also be used to express sRGB colors. This is an alias for `rgb()` that accepts the same parameters. + +> **Note:** `rgb()`/`rgba()` can also be written in a legacy form in which all values are separated with commas, for example `rgb(255, 0, 0)`. Mixing number and percent value types is not valid in the comma-separated legacy syntax (i.e. the `R`, `G`, and `B` values must be either all numbers or all percentages), and the `none` value is also not permitted. ### Values -Functional notation: `rgb(R G B[ / A])` +Below are descriptions of the allowed values for both absolute and [relative colors](/en-US/docs/Web/CSS/CSS_colors/Relative_colors). + +#### Absolute value syntax + +```text +rgb(R G B[ / A]) +``` + +The parameters are as follows: + +- `R`, `G`, `B` + - : Each value can be represented as a {{CSSXref("<number>")}} between `0` and `255`, a {{CSSXref("<percentage>")}} between `0%` and `100%`, or the keyword `none` (equivalent to `0%` in this case). These values represent the red, green, and blue channels, respectively. +- `A` {{optional_inline}} + - : An {{CSSXref("<alpha-value>")}} representing the alpha channel value of the color, where the number `0` corresponds to `0%` (fully transparent) and `1` corresponds to `100%` (fully opaque). Additionally, the keyword `none` can be used to explicitly specify no alpha channel. If the `A` channel value is not explicitly specified, it defaults to 100%. If included, the value is preceded by a slash (`/`). + +> **Note:** See [Missing color components](/en-US/docs/Web/CSS/color_value#missing_color_components) for more information on the effect of `none`. + +#### Relative value syntax + +```text +rgb(from R G B[ / A]) +``` + +The parameters are as follows: +- `from ` + - : The keyword `from` is always included when defining a relative color, followed by a {{cssxref("<color>")}} value representing the **origin color**: This is the original color that the relative color is based on. The origin color can be _any_ valid {{cssxref("<color>")}} syntax, including another relative color. - `R`, `G`, `B` - - : Each as a {{CSSXref("<number>")}} between `0` and `255`, a {{CSSXref("<percentage>")}} between `0%` and `100%`, or the keyword `none`, which represent the red, green, and blue channels, respectively. + - : Each value can be represented as a {{CSSXref("<number>")}} between `0` and `255`, a {{CSSXref("<percentage>")}} between `0%` and `100%`, or the keyword `none` (equivalent to `0%` in this case). These values represent the red, green, and blue channel values of the output color, respectively. - `A` {{optional_inline}} - - : An {{CSSXref("<alpha-value>")}} or the keyword `none`, where the number `1` corresponds to `100%` (full opacity). + - : An {{CSSXref("<alpha-value>")}} representing the alpha channel value of the output color, where the number `0` corresponds to `0%` (fully transparent) and `1` corresponds to `100%` (fully opaque). Additionally, the keyword `none` can be used to explicitly specify no alpha channel. If the `A` channel value is not explicitly specified, it defaults to the alpha channel value of the origin color. If included, the value is preceded by a slash (`/`). + +> **Note:** The `rgba()` alias can also be used to output relative colors, and to specify origin colors. When using `rgba()` to output a relative color, you must use the comma-less modern syntax. + +> **Note:** To fully enable the representation of the full spectrum of visible colors, the output of relative `rgb()` color functions is serialized to `color(srgb)`. That means that querying the output color value via the {{DOMxRef("HTMLElement.style")}} property or the {{DOMxRef("CSSStyleDeclaration.getPropertyValue()")}} method returns the output color as a [`color(srgb ...)`](/en-US/docs/Web/CSS/color_value/color) value. + +#### Defining relative color output channel components + +When using relative color syntax inside an `rgb()` function, the browser converts the origin color into an equivalent RGB color (if it is not already specified as such). The color is defined as three distinct color channel values — `r` (red), `g` (green), and `b` (blue) — plus an alpha channel value (`alpha`). These channel values are made available inside the function to be used when defining the output color channel values: + +- The `r`, `g` and `b` values are each resolved to ``s between `0` and `255`, inclusive. +- The `alpha` channel is resolved to a `` between `0` and `1`, inclusive. + +When defining a relative color, the different channels of the output color can be expressed in several different ways. Below, we'll study some examples to illustrate these. + +In the first two examples below, we are using relative color syntax. However, the first one outputs the same color as the origin color and the second one outputs a color not based on the origin color at all. They don't really create relative colors! You'd be unlikely to ever use these in a real codebase, and would probably just use an absolute color value instead. We included these examples as a starting point for learning about relative `rgb()` syntax. + +Let's start with an origin color of `hsl(0 100% 50%)` (equivalent to `rgb(255 0 0)`). The following function outputs the same color as the origin color — it uses the origin color's `r`, `g`, and `b` channel values (`255`, `0`, and `0`) as the output channel values: + +```css +rgb(from hsl(0 100% 50%) r g b) +``` + +This function's output color is the sRGB `color()` equivalent of `rgb(255 0 0)`: `color(srgb 1 0 0)`. + +The next function uses absolute values for the output color's channel values, outputting a completely different color not based on the origin color: + +```css +rgb(from hsl(0 100% 50%) 132 132 224) +``` + +In the above case, the output color is the sRGB `color()` equivalent of `rgb(132 132 224)`: `color(srgb 0.517647 0.517647 0.878431)`. + +The following function creates a relative color based on the origin color: + +```css +rgb(from hsl(0 100% 50%) r 80 80) +``` + +This example: + +- Converts the origin color (`hsl(0 100% 50%)`) into an `rgb()` equivalent (`rgb(255 0 0)`). +- Sets the `R` channel value for the output color to the origin color `rgb()` equivalent's `R` channel value — `255`. +- Sets the output color's `G` and `B` channel values to new values not based on the origin color: `80` and `80`, respectively. + +The final output color is the equivalent of `rgb(255 80 80)` in the sRGB color space — `color(srgb 1 0.313726 0.313726)`. -> **Note:** This functional notation serializes to sRGB values, and the values of the red, green, blue components may be rounded in serialization. +> **Note:** As mentioned above, if the output color is using a different color model to the origin color, the origin color is converted to the same model or space as the output color in the background so that it can be represented in a way that is compatible (i.e. using the same channels). -> **Note:** See [Missing color components](/en-US/docs/Web/CSS/color_value#missing_color_components) for the effect of `none`. +In the examples we've seen so far in this section, the alpha channels have not been explicitly specified for either the origin or output colors. When the output color alpha channel is not specified, it defaults to the same value as the origin color alpha channel. When the origin color alpha channel is not specified (and it is not a relative color), it defaults to `1`. Therefore, the origin and output alpha channel values are `1` for the above examples. + +Let's look at some examples that specify origin and output alpha channel values. The first one specifies the output alpha channel value as being the same as the origin alpha channel value, whereas the second one specifies a different output alpha channel value, unrelated to the origin alpha channel value. + +```css +rgb(from hsl(0 100% 50% / 0.8) r g b / alpha) +/* Computed output color: color(srgb 1 0 0 / 0.8) */ + +rgb(from hsl(0 100% 50% / 0.8) r g b / 0.5) +/* Computed output color: color(srgb 1 0 0 / 0.5) */ +``` + +In the following example, the `hsl()` origin color is again converted into an `rgb()` representation — `rgb(255 0 0)`. {{cssxref("calc")}} calculations are applied to the `R`, `G`, `B`, and `A` values. After calculating, the R, G, B and A values are `127.5`, `25`, `175`, and`0.9` respectively. The final output color is the equivalent of `rgb(127.5 25 175 / 0.9)` in the sRGB color space: `color(srgb 0.5 0.0980392 0.686275 / 0.9)`. + +```css +rgb(from hsl(0 100% 50%) calc(r/2) calc(g + 25) calc(b + 175) / calc(alpha - 0.1)) +``` + +> **Note:** Because the origin color channel values are resolved to `` values, you have to add numbers to them when using them in calculations, even in cases where a channel would normally accept ``, ``, or other value types. Adding a `` to a ``, for example, doesn't work. ### Formal syntax @@ -41,6 +138,75 @@ Functional notation: `rgb(R G B[ / A])` ## Examples +### Using relative colors with rgb() + +This example styles three {{htmlelement("div")}} elements with different background colors. The left-hand one is given the unmodified `--base-color`, while the middle and right ones are given variants of that `--base-color` that successively remove more from the red channel and add more to the blue channel. + +These variants are defined using relative colors — the `--base-color` [custom property](/en-US/docs/Web/CSS/--*) is passed into an `rgb()` function, and the output color has its red and blue channels modified to achieve the desired effect via `calc()` functions, while the green channel is left unchanged. + +```html hidden +
+
+
+
+
+``` + +#### CSS + +```css hidden +#container { + display: flex; + width: 100vw; + height: 100vh; + box-sizing: border-box; +} + +.item { + flex: 1; + margin: 20px; +} +``` + +```css +:root { + --base-color: orange; +} + +#one { + background-color: var(--base-color); +} + +#two { + background-color: rgb(from var(--base-color) calc(r - 76.5) g calc(b + 76.5)); + /* 76.5 is 30% of 255 */ +} + +#three { + background-color: rgb(from var(--base-color) calc(r - 153) g calc(b + 153)); + /* 153 is 60% of 255 */ +} + +/* Use @supports to add in support for old syntax that requires r g b values to + be specified as percentages (with units) in calculations. This is required + for Safari 16.4+. */ +@supports (color: rgb(from red r g calc(b + 30%))) { + #two { + background-color: rgb(from var(--base-color) calc(r - 30%) g calc(b + 30%)); + } + + #three { + background-color: rgb(from var(--base-color) calc(r - 60%) g calc(b + 60%)); + } +} +``` + +#### Result + +The output is as follows: + +{{ EmbedLiveSample("Using relative colors with rgb()", "100%", "200") }} + ### Legacy syntax: comma-separated values For legacy reasons, the `rgb()` function accepts a form in which all values are separated using commas. @@ -118,3 +284,5 @@ div.rgba { ## See also - The {{CSSXref("<color>")}} data type for a list of all color notations +- [Using relative colors](/en-US/docs/Web/CSS/CSS_colors/Relative_colors) +- [CSS colors](/en-US/docs/Web/CSS/CSS_colors) module diff --git a/files/en-us/web/css/css_colors/applying_color/index.md b/files/en-us/web/css/css_colors/applying_color/index.md index db27e949cac3ce1..bdab5f7a79a5176 100644 --- a/files/en-us/web/css/css_colors/applying_color/index.md +++ b/files/en-us/web/css/css_colors/applying_color/index.md @@ -397,6 +397,10 @@ For example, if we wanted to show the `display-p3 0 0 1` color, which is outside } ``` +### Relative colors + +The [CSS colors module](/en-US/docs/Web/CSS/CSS_colors) defines [**relative color syntax**](/en-US/docs/Web/CSS/CSS_colors/Relative_colors), which allows {{cssxref("<color>")}} values to be defined relative to other existing colors, rather than defining a color value from scratch each time. This powerful feature enables the creation of complements to existing colors — such as lighter, darker, saturated, semi-transparent, or inverted variants of an original color. Relative colors provide an effective mechanism to create palettes and define color adjustments. + ## Using color Now that you know what CSS properties exist that let you apply color to elements and the formats you can use to describe colors, you can put this together to begin to make use of color. As you may have seen from the list under [Things that can have color](#things_that_can_have_color), there are plenty of things you can color with CSS. Let's look at this from two sides: using color within a {{Glossary("stylesheet")}}, and adding and changing color using {{Glossary("JavaScript")}} code to alter the styles of elements. @@ -684,4 +688,5 @@ With this set, the browser won't tamper with the appearance of the element, and - [Drawing graphics](/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Drawing_graphics) - [Graphics on the web](/en-US/docs/Learn/HTML/Multimedia_and_embedding/Images_in_HTML#other_graphics_on_the_web) +- [Using relative colors](/en-US/docs/Web/CSS/CSS_colors/Relative_colors) - [CSS color module](/en-US/docs/Web/CSS/CSS_colors) diff --git a/files/en-us/web/css/css_colors/index.md b/files/en-us/web/css/css_colors/index.md index cce424ec1d89da6..3147deee76504fc 100644 --- a/files/en-us/web/css/css_colors/index.md +++ b/files/en-us/web/css/css_colors/index.md @@ -39,7 +39,7 @@ To see the code for this color syntax converter, [view the source on GitHub](htt ### Functions -- Absolute color functions, including: +- Color functions: - [`rgb()`](/en-US/docs/Web/CSS/color_value/rgb) and its `rgba()` alias - [`hsl()`](/en-US/docs/Web/CSS/color_value/hsl) and its `hsla()` alias - [`hwb()`](/en-US/docs/Web/CSS/color_value/hwb) @@ -62,7 +62,7 @@ To see the code for this color syntax converter, [view the source on GitHub](htt - {{cssxref("alpha-value")}} - {{cssxref("hue")}} - {{cssxref("system-color")}} -- [``](/en-US/docs/Web/CSS/color_value/color#using_predefined_colorspaces_with_color) +- [``](/en-US/docs/Web/CSS/color_value/color#using_predefined_color_spaces_with_color) ### Glossary terms and keywords @@ -78,12 +78,12 @@ To see the code for this color syntax converter, [view the source on GitHub](htt - [Applying color to HTML elements using CSS](/en-US/docs/Web/CSS/CSS_colors/Applying_color) - : A guide to using CSS to apply color to a variety of types of content. All color-related CSS properties are touched upon. +- [Using relative colors](/en-US/docs/Web/CSS/CSS_colors/Relative_colors) + - : This article explains relative CSS color syntax, shows what the different options are, and looks at some illustrative examples. - [Understanding color and luminance](/en-US/docs/Web/Accessibility/Understanding_Colors_and_Luminance) - : Color perception and using colors with color insensitive (color blind) users, reduced vision users and users with vestibular disorders or other neurological disorders in mind. - [WCAG 1.4.1: Color contrast](/en-US/docs/Web/Accessibility/Understanding_WCAG/Perceivable/Color_contrast) - : Explanation of contrast requirements between background and foreground content to ensure legibility. -- [Color picker tool](/en-US/docs/Web/CSS/CSS_colors/Color_picker_tool) - - : This tool makes it easy to create, adjust, and experiment with custom colors. ## Related concepts @@ -128,3 +128,4 @@ To see the code for this color syntax converter, [view the source on GitHub](htt - The [`VideoColorSpace`](/en-US/docs/Web/API/VideoColorSpace) interface - The SVG [``](/en-US/docs/Web/SVG/Element/feColorMatrix) element - [Canvas API: applying styles and colors](/en-US/docs/Web/API/Canvas_API/Tutorial/Applying_styles_and_colors#colors) +- [Color picker tool](/en-US/docs/Web/CSS/CSS_colors/Color_picker_tool): This tool makes it easy to create, adjust, and experiment with custom colors. diff --git a/files/en-us/web/css/css_colors/relative_colors/index.md b/files/en-us/web/css/css_colors/relative_colors/index.md new file mode 100644 index 000000000000000..aa6ff6f59aeff32 --- /dev/null +++ b/files/en-us/web/css/css_colors/relative_colors/index.md @@ -0,0 +1,796 @@ +--- +title: Using relative colors +slug: Web/CSS/CSS_colors/Relative_colors +page-type: guide +--- + +{{CSSRef}} + +The [CSS colors module](/en-US/docs/Web/CSS/CSS_colors) defines **relative color syntax**, which allows a CSS {{cssxref("<color>")}} value to be defined relative to another color. This is a powerful feature that enables easy creation of complements to existing colors — such as lighter, darker, saturated, semi-transparent, or inverted variants — enabling more effective color palette creation. + +This article explains relative color syntax, shows what the different options are, and looks at some illustrative examples. + +## General syntax + +A relative CSS color value has the following general syntax structure: + +```text +color-function(from origin-color channel1 channel2 channel3) +color-function(from origin-color channel1 channel2 channel3 / alpha) + +// color space included in the case of color() functions +color(from origin-color colorspace channel1 channel2 channel3) +color(from origin-color colorspace channel1 channel2 channel3 / alpha) +``` + +Relative colors are created using the same [color functions](/en-US/docs/Web/CSS/CSS_colors#functions) as absolute colors, but with different parameters: + +1. Include a basic color function (represented by _`color-function()`_ above) such as [`rgb()`](/en-US/docs/Web/CSS/color_value/rgb), [`hsl()`](/en-US/docs/Web/CSS/color_value/hsl), etc. Which one you pick depends on the color model you want to use for the relative color you are creating (the **output color**). +2. Pass in the **origin color** (represented above by _`origin-color`_) your relative color will be based on, preceded by the `from` keyword. This can be any valid {{cssxref("<color>")}} value using any available color model including a color value contained in a [CSS custom property](/en-US/docs/Web/CSS/Using_CSS_custom_properties), system colors, `currentColor`, or even another relative color. +3. In the case of the [`color()`](/en-US/docs/Web/CSS/color_value/color) function, include the _[`colorspace`](/en-US/docs/Web/CSS/color_value/color#colorspace)_ of the output color. +4. Provide an output value for each individual channel. The output color is defined after the origin color — represented above by the _`channel1`_, _`channel2`_, and _`channel3`_ placeholders. The channels defined here depend on the [color function](/en-US/docs/Web/CSS/CSS_colors#functions) you are using for your relative color. For example, if you are using [`hsl()`](/en-US/docs/Web/CSS/color_value/hsl), you would need to define the values for hue, saturation, and lightness. Each channel value can be a new value, the same as the original value, or a value relative to the channel value of the origin color. +5. Optionally, an `alpha` channel value for the output color can be defined, preceded by a slash (`/`). If the `alpha` channel value is not explicitly specified, it defaults to the alpha channel value of the _`origin-color`_ (not 100%, which is the case for absolute color values). + +The browser converts the origin color to a syntax compatible with the color function then destructures it into component color channels (plus the `alpha` channel if the origin color has one). These are made available as appropriately-named values inside the color function — `r`, `g`, `b`, and `alpha` in the case of the `rgb()` function, `l`, `a`, `b`, and `alpha` in the case of the `lab()` function, `h`, `w`, `b`, and `alpha` in the case of `hwb()`, etc. — that can be used to calculate new output channel values. + +Let's look at relative color syntax in action. The below CSS is used to style two {{htmlelement("div")}} elements, one with a absolute background color — `red` — and one with a relative background color created with the `rgb()` function, based on the same `red` color value: + +```html hidden +
+
+
+
+``` + +```css hidden +#container { + display: flex; + width: 100vw; + height: 100vh; + box-sizing: border-box; +} + +.item { + flex: 1; + margin: 20px; +} +``` + +```css +#one { + background-color: red; +} + +#two { + background-color: rgb(from red 200 g b); +} +``` + +The output is as follows: + +{{ EmbedLiveSample("General syntax", "100%", "200") }} + +The relative color uses the [`rgb()`](/en-US/docs/Web/CSS/color_value/rgb) function, which takes `red` as the origin color, converts it to an equivalent `rgb()` color (`rgb(255 0 0)`) and then defines the new color as having a red channel of value `200` and green and blue channels with a value the same as the origin color (it uses the `g` and `b` values made available inside the function by the browser, which are both equal to `0`). + +This results in an output of `rgb(200 0 0)` — a slightly darker red. If we had specified a red channel value of `255` (or just the `r` value), the resulting output color would be exactly the same as the input value. The browser's final output color (the computed value) is an sRGB `color()` value equivalent to `rgb(200 0 0)` — `color(srgb 0.784314 0 0)`. + +> **Note:** As mentioned above, when calculating a relative color the first thing the browser does is to convert the provided origin color (`red` in the above example) into a value compatible with the color function being used (in this case, `rgb()`). This is done so that the browser is able to calculate the output color from the origin color. While the calculations are performed relative to the color function used, the actual output color value depends on the color's color space: +> +> - Older sRGB color functions cannot express the full spectrum of visible colors. The output colors of ([`hsl()`](/en-US/docs/Web/CSS/color_value/hsl), [`hwb()`](/en-US/docs/Web/CSS/color_value/hwb), and [`rgb()`](/en-US/docs/Web/CSS/color_value/rgb)) are serialized to `color(srgb)` to avoid these limitations. That means that querying the output color value via the {{domxref("HTMLElement.style")}} property or the {{domxref("CSSStyleDeclaration.getPropertyValue()")}} method returns the output color as a [`color(srgb ...)`](/en-US/docs/Web/CSS/color_value/color) value. +> - For more recent color functions (`lab()`, `oklab()`, `lch()`, and `oklch()`), relative color output values are expressed in the same syntax as the color function used. For example, if a [`lab()`](/en-US/docs/Web/CSS/color_value/lab) color function is being used, the output color will be a `lab()` value. + +These five lines all produce an equivalent output color: + +```text +red +rgb(255 0 0) +rgb(from red r g b) +rgb(from red 255 g b) +rgb(from red 255 0 0) +``` + +## Syntax flexibility + +There is an important distinction to be made between the destructured origin color channel values made available in the function, and the channel values of the output color set by the developer. + +When a relative color is defined, the channel values of the origin color are made available in the function to use when defining the output color channel values. Those values match the function used. For example, when using an `rgb()` function the origin color channel values are available as `r`, `g`, and `b` values, when using `hsl()` they are available as `h`, `s`, and `l`, when using `lch()` they are available as `h`, `c`, and `h`, and so on. + +The following example defines a relative color using an `rgb()` function and uses the origin color channel values for the output channel values, meaning that the output color is the same as the origin color: + +```css +rgb(from red r g b) +``` + +However, when specifying the output values, you don't need to use the origin color channel values at all. You need to provide the output channel values in the right order (e.g. red, then green, then blue in the case of `rgb()`), but they can be any values you wish provided they are valid values for those channels. This gives relative CSS colors a high degree of flexibility. + +For example, if you wanted to, you could specify absolute values like those shown below, transforming `red` into `blue`: + +```css +rgb(from red 0 0 255) +/* output color is equivalent to rgb(0 0 255), full blue */ +``` + +> **Note:** If you are using relative color syntax but outputting the same color as the origin color or a color not based on the origin color at all, you are not really creating a relative color. You'd be unlikely to ever do this in a real codebase, and would probably just use an absolute color value instead. But, we felt it useful to explain that you _can_ do this with relative color syntax, as a starting point for learning about it. + +You can even mix up or repeat the provided values. The following takes a slightly darker red as an input and outputs a light gray color — the output color's `r`, `g`, and `b` channels are all set to the origin color's `r` channel value: + +```css +rgb(from rgb(200 0 0) r r r) +/* output color is equivalent to rgb(200 200 200), light gray */ +``` + +The following uses the origin color's channel values for the output color's `r`, `g`, and `b` channel values, but in reverse order: + +```css +rgb(from rgb(200 170 0) b g r) +/* output color is equivalent to rgb(0 170 200) */ +``` + +## Color functions that support relative colors + +In the section above we only saw relative colors defined via the [`rgb()`](/en-US/docs/Web/CSS/color_value/rgb) function. However, relative colors can be defined using any modern CSS color function — [`color()`](/en-US/docs/Web/CSS/color_value/color), [`hsl()`](/en-US/docs/Web/CSS/color_value/hsl), [`hwb()`](/en-US/docs/Web/CSS/color_value/hwb), [`lab()`](/en-US/docs/Web/CSS/color_value/lab), [`lch()`](/en-US/docs/Web/CSS/color_value/lch), [`oklab()`](/en-US/docs/Web/CSS/color_value/oklab), [`oklch()`](/en-US/docs/Web/CSS/color_value/oklch), or [`rgb()`](/en-US/docs/Web/CSS/color_value/rgb). The general syntax structure is the same in each case, although the origin color values have different names appropriate for the function being used. + +Below you can find relative color syntax examples for each color function. Each case is the simplest possible, with the output color channel values exactly matching the origin color channel values: + +```css +/* color() with and without alpha channel */ +color(from red a98-rgb r g b) +color(from red a98-rgb r g b / alpha) + +color(from red xyz-d50 x y z) +color(from red xyz-d50 x y z / alpha) + +/* hsl() with and without alpha channel */ +hsl(from red h s l) +hsl(from red h s l / alpha) + +/* hwb() with and without alpha channel */ +hwb(from red h w b) +hwb(from red h w b / alpha) + +/* lab() with and without alpha channel */ +lab(from red l a b) +lab(from red l a b / alpha) + +/* lch() with and without alpha channel */ +lch(from red l c h) +lch(from red l c h / alpha) + +/* oklab() with and without alpha channel */ +oklab(from red l a b) +oklab(from red l a b / alpha) + +/* oklch() with and without alpha channel */ +oklch(from red l c h) +oklch(from red l c h / alpha) + +/* rgb() with and without alpha channel */ +rgb(from red r g b) +rgb(from red r g b / alpha) +``` + +It is worth mentioning again that the color system of the origin color doesn't need to match the color system being used to create the output color. Again, this provides a lot of flexibility. Generally you won't be interested in and might not even know the system the origin color is defined in (you might just have a [custom property value](#using_custom_properties) to manipulate). You'll just want to input a color and, for example, create a lighter variant of it by putting it into an `hsl()` function and varying the lightness value. + +> **Note:** Aliases such as `rgba()` or `hsla()` can be used to output relative colors, and to specify origin colors. When using legacy color functions to output a relative color, you must use the comma-less modern syntax and can't mix percentages and numbers. + +## Using custom properties + +When creating a relative color, you can use values defined in [CSS custom properties](/en-US/docs/Web/CSS/Using_CSS_custom_properties) both for the origin color and within the output color channel value definitions. Let's look at an example. + +In the below CSS we define two custom properties: + +- `--base-color` contains our base brand color — `purple`. Here we are using a named color keyword, but relative colors can accept any color syntax for the origin color. +- `--standard-opacity` contains the standard brand opacity value that we want to apply to semi-transparent boxes — `0.75`. + +We then give two {{htmlelement("div")}} elements a background color. One is given an absolute color — our `--base-color` brand purple. The other one is given a relative color equal to our brand purple, transformed to add an alpha channel equal to our standard opacity value. + +```html hidden +
+
+
+
+``` + +```css hidden +#container { + display: flex; + width: 100vw; + height: 100vh; + box-sizing: border-box; + background-image: repeating-linear-gradient( + 45deg, + white, + white 24px, + black 25px, + black 50px + ); +} + +.item { + flex: 1; + margin: 20px; +} +``` + +```css +:root { + --base-color: purple; + --standard-opacity: 0.75; +} + +#one { + background-color: var(--base-color); +} + +#two { + background-color: hwb(from var(--base-color) h w b / var(--standard-opacity)); +} +``` + +The output is as follows: + +{{ EmbedLiveSample("Using custom properties", "100%", "200") }} + +## Using math functions + +You can use CSS [math functions](/en-US/docs/Web/CSS/CSS_Functions#math_functions) such as {{cssxref("calc")}} to calculate values for the output color channels. Let's look at an example. + +The below CSS is used to style three {{htmlelement("div")}} elements with different background colors. The middle one is given an unmodified `--base-color`, while the left and right ones are given lightened and darkened variants of that `--base-color`. These variants are defined using relative colors — the `--base-color` is passed into an `lch()` function, and the output color has its lightness channel modified to achieve the desired effect via a `calc()` function. The lightened color has 20% added to the lightness channel, and the darkened color has 20% subtracted from it. + +```html hidden +
+
+
+
+
+``` + +```css hidden +#container { + display: flex; + width: 100vw; + height: 100vh; + box-sizing: border-box; +} + +.item { + flex: 1; + margin: 20px; +} +``` + +```css +:root { + --base-color: orange; +} + +#one { + background-color: lch(from var(--base-color) calc(l + 20) c h); +} + +#two { + background-color: var(--base-color); +} + +#three { + background-color: lch(from var(--base-color) calc(l - 20) c h); +} +``` + +The output is as follows: + +{{ EmbedLiveSample("Using math functions", "100%", "200") }} + +## Channel values resolve to `` values + +To make channel value calculations work in relative colors, all origin color channel values resolve to appropriate {{cssxref("<number>")}} values. For example, in the `lch()` examples above, we are calculating new lightness values by adding or subtracting numbers from the origin color's `l` channel value. If we tried to do `calc(l + 20%)`, that would result in an invalid color — `l` is a `` and cannot have a {{cssxref("<percentage>")}} added to it. + +- Channel values originally specified as a `` resolve to a `` appropriate for the output color function. +- Channel values originally specified as a {{cssxref("<hue>")}} angle resolve to a number of degrees in a range of `0` to `360`, inclusive. + +Check the different [color function pages](/en-US/docs/Web/CSS/CSS_colors#functions) for the specifics of what their origin channel values resolve to. + +## Checking for browser support + +You can check that a browser supports relative color syntax by running it through a {{cssxref("@supports")}} at-rule. + +For example: + +```css +@supports (color: hsl(from white h s l)) { + /* safe to use hsl() relative color syntax */ +} +``` + +## Examples + +> **Note:** You can find additional examples demonstrating the use of relative color syntax in the different functional notation types on their dedicated pages: [`color()`](/en-US/docs/Web/CSS/color_value/color#using_relative_colors_with_color), [`hsl()`](/en-US/docs/Web/CSS/color_value/hsl#using_relative_colors_with_hsl), [`hwb()`](/en-US/docs/Web/CSS/color_value/hwb#using_relative_colors_with_hwb), [`lab()`](/en-US/docs/Web/CSS/color_value/lab#using_relative_colors_with_lab), [`lch()`](/en-US/docs/Web/CSS/color_value/lch#using_relative_colors_with_lch), [`oklab()`](/en-US/docs/Web/CSS/color_value/oklab#using_relative_colors_with_oklab), [`oklch()`](/en-US/docs/Web/CSS/color_value/oklch#using_relative_colors_with_oklch), [`rgb()`](/en-US/docs/Web/CSS/color_value/rgb#using_relative_colors_with_rgb). + +### Color palette generator + +This example allows you to choose a base color and a color palette type. The browser will then show an appropriate palette of colors based on the chosen base color. The color palette choices are as follows: + +- **Complementary**: Includes two colors that are at opposite sides of a color wheel, or to put it another way, _opposite hues_ (see the {{cssxref("<hue>")}} data type for more information on hues and color wheels). The two colors are defined as a base color, and the base color with hue channel +180 degrees. +- **Triadic**: Includes three colors equal distances apart around the color wheel. The three colors are defined as a base color, base color with hue channel -120 degrees, and base color with hue channel +120 degrees. +- **Tetradic**: Includes four colors equal distances apart around the color wheel. The four colors are defined as a base color, and base color with hue channel +90, +180, and +270 degrees. +- **Monochrome**: Includes multiple colors with the same hue but varying lightness values. In our example we've defined five colors in a monochrome palette — base color, and base color with lightness channel -20, -10, +10, and +20. + +#### HTML + +The full HTML is included below for reference. The most interesting parts are as follows: + +- The `--base-color` custom property is stored as an inline [`style`](/en-US/docs/Web/HTML/Global_attributes/style) on the {{htmlelement("div")}} element with the ID of `container`. We've placed it there so it is easy to update the value using JavaScript. We've provided an initial value of `#ff0000` (`red`) to show a color palette based on that value when the example loads. Note that normally we'd probably set this on the {{htmlelement("html")}} element, but the MDN live sample was removing it when rendering. +- The base color picker is created using an [``](/en-US/docs/Web/HTML/Element/input/color) control. When a new value is set in this control, the `--base-color` custom property is set to this value using JavaScript, which in turn generates a new color palette. All the displayed colors are relative colors based on `--base-color`. +- The set of [``](/en-US/docs/Web/HTML/Element/input/radio) controls enables choosing a color palette type to generate. When a new value is chosen here, JavaScript is used to set a new class on the `container` `
` to represent the chosen palette. In the CSS, descendant selectors are used to target the child `
`s (e.g. `.comp :nth-child(1)`) so they can have the correct colors applied to them and hide the unused `
` nodes. +- The `container` `
` containing the child `
`s that display the colors of the generated palette. Note that an initial class of `comp` is set on it, so that the page will display a complementary color scheme when first loaded. + +```html +
+

Color palette generator

+
+
+ + +
+
+
+ Select a color palette type: + +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+
+
+
+
+
+
+
+
+
+
+
+``` + +#### CSS + +Below we are only showing the CSS that sets the palette colors. Note how, in each case, descendent selectors are used to apply the correct {{cssxref("background-color")}} to each child `
` for the chosen palette. We care more about the position of the `
`s in the source order than the type of element, so we have used {{cssxref(":nth-child")}} to target them. + +In the last rule we've used the [general sibling selector (`~`)](/en-US/docs/Web/CSS/Subsequent-sibling_combinator) to target the unused `
` elements in each palette type, setting [`display: none`](/en-US/docs/Web/CSS/Subsequent-sibling_combinator) to stop them being rendered. + +The colors themselves include the `--base-color`, plus relative colors derived from that `--base-color`. The relative colors use the [`lch()`](/en-US/docs/Web/CSS/color_value/lch) function — passing in the origin `--base-color` and defining an output color with an adjusted lightness or hue channel as appropriate. + +```css hidden +html { + font-family: sans-serif; +} + +body { + margin: 0; +} + +h1 { + margin-left: 16px; +} + +/* Simple form styling */ + +#color-picker { + margin-left: 16px; + margin-bottom: 20px; +} + +#color-picker label, +legend { + display: block; + font-size: 0.8rem; + margin-bottom: 10px; +} + +input[type="color"] { + width: 200px; + display: block; +} + +fieldset { + display: flex; + gap: 20px; + border: 0; +} + +/* Palette container styling */ + +#container { + display: flex; + width: 100vw; + height: 250px; + box-sizing: border-box; +} + +#container div { + flex: 1; +} +``` + +```css +/* Complementary colors */ +/* Base color, and base color with hue channel +180 degrees */ + +.comp :nth-child(1) { + background-color: var(--base-color); +} + +.comp :nth-child(2) { + background-color: lch(from var(--base-color) l c calc(h + 180)); +} + +/* Use @supports to add in support old syntax that requires deg units + to be specified in hue calculations. This is required for Safari 16.4+. */ +@supports (color: lch(from red l c calc(h + 180deg))) { + .comp :nth-child(2) { + background-color: lch(from var(--base-color) l c calc(h + 180deg)); + } +} + +/* Triadic colors */ +/* Base color, base color with hue channel -120 degrees, and base color */ +/* with hue channel +120 degrees */ + +.triadic :nth-child(1) { + background-color: var(--base-color); +} + +.triadic :nth-child(2) { + background-color: lch(from var(--base-color) l c calc(h - 120)); +} + +.triadic :nth-child(3) { + background-color: lch(from var(--base-color) l c calc(h + 120)); +} + +/* Use @supports to add in support old syntax that requires deg units + to be specified in hue calculations. This is required for Safari 16.4+. */ +@supports (color: lch(from red l c calc(h + 120deg))) { + .triadic :nth-child(2) { + background-color: lch(from var(--base-color) l c calc(h - 120deg)); + } + + .triadic :nth-child(3) { + background-color: lch(from var(--base-color) l c calc(h + 120deg)); + } +} + +/* Tetradic colors */ +/* Base color, and base color with hue channel +90, +180, and +270 degrees */ + +.tetradic :nth-child(1) { + background-color: var(--base-color); +} + +.tetradic :nth-child(2) { + background-color: lch(from var(--base-color) l c calc(h + 90)); +} + +.tetradic :nth-child(3) { + background-color: lch(from var(--base-color) l c calc(h + 180)); +} + +.tetradic :nth-child(4) { + background-color: lch(from var(--base-color) l c calc(h + 270)); +} + +/* Use @supports to add in support old syntax that requires deg units + to be specified in hue calculations. This is required for Safari 16.4+. */ +@supports (color: lch(from red l c calc(h + 90deg))) { + .tetradic :nth-child(2) { + background-color: lch(from var(--base-color) l c calc(h + 90deg)); + } + + .tetradic :nth-child(3) { + background-color: lch(from var(--base-color) l c calc(h + 180deg)); + } + + .tetradic :nth-child(4) { + background-color: lch(from var(--base-color) l c calc(h + 270deg)); + } +} + +/* Monochrome colors */ +/* Base color, and base color with lightness channel -20, -10, +10, and +20 */ + +.monochrome :nth-child(1) { + background-color: lch(from var(--base-color) calc(l - 20) c h); +} + +.monochrome :nth-child(2) { + background-color: lch(from var(--base-color) calc(l - 10) c h); +} + +.monochrome :nth-child(3) { + background-color: var(--base-color); +} + +.monochrome :nth-child(4) { + background-color: lch(from var(--base-color) calc(l + 10) c h); +} + +.monochrome :nth-child(5) { + background-color: lch(from var(--base-color) calc(l + 20) c h); +} + +/* Hide unused swatches for each palette type */ +.comp :nth-child(2) ~ div, +.triadic :nth-child(3) ~ div, +.tetradic :nth-child(4) ~ div { + display: none; +} +``` + +##### An aside on `@supports` testing + +In the example CSS you'll notice {{cssxref("@supports")}} blocks being used to provide different {{cssxref("background-color")}} values to browsers that support a previous draft specification of the relative color syntax. These are required because Safari's initial implementation was based on an older version of the spec in which origin color channel values resolved to {{cssxref("<number>")}}s or other unit types depending on the context. This meant that values sometimes required units when performing additions and subtractions, which created confusion. In newer implementations, origin color channel values always resolve to an equivalent {{cssxref("<number>")}} value, which means calculations are always done with unitless values. + +Note how the support test in each case is done using a simple declaration — `color: lch(from red l c calc(h + 90deg))` for example — rather than the actual value that we need to vary for other browsers. When testing complex values like these, you should use the simplest possible declaration that still contains the syntactic difference you want to test for. + +Including a custom property in the `@supports` test doesn't work — the test always comes back as positive regardless of what value the custom property is given. This is because a custom property value only becomes invalid when assigned to be an invalid value (or part of an invalid value) of a regular CSS property. To work around this, in each test we have replaced `var(--base-color)` with the `red` keyword. + +#### JavaScript + +In the JavaScript, we: + +- Add a [`change`](/en-US/docs/Web/API/HTMLElement/change_event) event listener to the radio buttons so that when one is selected, the `setContainer()` function runs. This function updates the `class` value of the `
` with `id="container"` with the value of the selected radio button so that the correct background colors will be applied to the child `
`s for the chosen palette type. +- Add an [`input`](/en-US/docs/Web/API/Element/input_event) event listener to the color picker control so that when a new color is selected, the `setBaseColor()` function runs. This function sets the `--base-color` custom property's value to the new color. + +```js +const form = document.forms[0]; +const radios = form.elements["palette-type"]; +const colorPicker = form.elements["color"]; +const containerElem = document.getElementById("container"); + +for (const radio of radios) { + radio.addEventListener("change", setContainer); +} + +colorPicker.addEventListener("input", setBaseColor); + +function setContainer(e) { + const palType = e.target.value; + console.log("radio changed"); + containerElem.setAttribute("class", palType); +} + +function setBaseColor(e) { + console.log("color changed"); + containerElem.style.setProperty("--base-color", e.target.value); +} +``` + +#### Results + +The output is as follows. This starts to show the power of relative CSS colors — we are defining multiple colors and generating palettes that are updated live by adjusting a single custom property. + +{{ EmbedLiveSample("Color palette generator", "100%", "470") }} + +### Live UI color scheme updater + +This example shows a card containing a heading and text, but with a twist — below the card is a slider ([``](/en-US/docs/Web/HTML/Element/input/range)) control. When its value is changed, JavaScript is used to set a `--hue` custom property value to the new slider value. + +This in turn adjusts the color scheme for the entire UI: + +- The `--base-color` value is a relative color with its hue channel set to the value of `--hue`. +- The other colors used in the design are relative colors based on `--base-color`. As a result, they change when the `--base-color` changes. + +#### HTML + +The HTML for the example is shown below. + +- The {{htmlelement("main")}} element acts as an outer wrapper to contain the rest of the content, allowing the card and form to be centered vertically and horizontally inside `
` as one unit. +- The {{htmlelement("section")}} element contains the [`

`](/en-US/docs/Web/HTML/Element/Heading_Elements) and {{htmlelement("p")}} elements that define the card's content. +- The {{htmlelement("form")}} element contains the ([``](/en-US/docs/Web/HTML/Element/input/range)) control and its {{htmlelement("label")}}. + +```html +
+
+

A love of colors

+

+ Colors, the vibrant essence of our surroundings, are truly awe-inspiring. + From the fiery warmth of reds to the calming coolness of blues, they bring + unparalleled richness to our world. Colors stir emotions, ignite + creativity, and shape perceptions, acting as a universal language of + expression. Whether in a breathtaking sunset, a bustling marketplace, or + an artist's canvas, colors transcend the visual spectrum, turning the + ordinary into the extraordinary. In their brilliance, colors create a + visually enchanting tapestry that invites admiration and sparks joy. +

+
+
+ + +
+
+``` + +#### CSS + +In the CSS the `:root` has a default `--hue` value set on it, relative [`lch()`](/en-US/docs/Web/CSS/color_value/lch) colors to define the color scheme, plus a radial gradient that fills the whole body. + +The relative colors are as follows: + +- `--base-color`: The base color takes an origin color of `red` (although any full color would do) and adjusts its hue value to the value set in the `--hue` custom property. +- `--bg-color`: A much lighter variant of `--base-color`, intended to be used as a background. This is created by taking an origin color of `--base-color` and adding 40 to its lightness value. +- `--complementary-color`: A complementary color 180 degrees around the color wheel from `--base-color`. This is created by taking an origin color of `--base-color` and adding 180 to its hue value. + +Now have a look at the rest of the CSS and take note of all the places where these colors are used. This includes [backgrounds](/en-US/docs/Web/CSS/background), [borders](/en-US/docs/Web/CSS/border), [`text-shadow`](/en-US/docs/Web/CSS/text-shadow), and even the [`accent-color`](/en-US/docs/Web/CSS/accent-color) of the slider. + +> **Note:** For brevity, only the parts of the CSS relevant to relative color usage are shown. + +```css hidden +html { + font-family: sans-serif; +} + +body { + margin: 0; + width: 100vw; + height: 100vh; + display: flex; + align-items: center; + justify-content: center; +} + +main { + display: flex; + flex-flow: column; + align-items: center; +} + +form { + display: flex; + align-items: center; + justify-content: center; + margin-top: 40px; + width: 50%; + padding: 10px; +} + +label { + padding-right: 10px; +} + +p { + line-height: 1.5; + margin: 0; + padding: 20px; +} + +main { + width: 600px; +} +``` + +```css +:root { + /* Default hue value */ + --hue: 240; + + /* Relative color definitions */ + --base-color: lch(from red l c var(--hue)); + --bg-color: lch(from var(--base-color) calc(l + 40) c h); + --complementary-color: lch(from var(--base-color) l c calc(h + 180)); + + background: radial-gradient(ellipse at center, white 40%, var(--base-color)); +} + +/* Use @supports to add in support for --complementary-color with old + syntax that requires deg units to be specified in hue calculations. + This is required for in Safari 16.4+. */ +@supports (color: lch(from red l c calc(h + 180deg))) { + body { + --complementary-color: lch(from var(--base-color) l c calc(h + 180deg)); + } +} + +/* Box styling */ + +section { + background-color: var(--bg-color); + border: 3px solid var(--base-color); + border-radius: 20px; + box-shadow: 10px 10px 30px rgb(0 0 0 / 0.5); +} + +h1 { + text-align: center; + margin: 0; + padding: 20px; + background-color: var(--base-color); + color: black; + border-radius: 16px 16px 0 0; + font-size: 3rem; + letter-spacing: -1px; + text-shadow: + 1px 1px 1px var(--complementary-color), + -1px -1px 1px var(--complementary-color), + 0 0 3px var(--complementary-color); +} + +/* Range slider styling */ + +form { + background-color: var(--bg-color); + border: 3px solid var(--base-color); +} + +input { + accent-color: var(--base-color); +} +``` + +#### JavaScript + +The JavaScript adds an [`input`](/en-US/docs/Web/API/Element/input_event) event listener to the slider control so that when a new value is set, the `setHue()` function runs. This function sets a new inline `--hue` custom property value on the `:root` (the `` element) that overrides the original default value we set in our CSS. + +```js +const rootElem = document.querySelector(":root"); +const slider = document.getElementById("hue-adjust"); + +slider.addEventListener("input", setHue); + +function setHue(e) { + console.log("hue changed"); + rootElem.style.setProperty("--hue", e.target.value); +} +``` + +#### Results + +The output is shown below. Relative CSS colors are being used here to control the color scheme of an entire UI, which can be adjusted live as a single value is modified. + +{{ EmbedLiveSample("Live UI color scheme updater", "100%", "500") }} + +## See also + +- The {{CSSXref("<color>")}} data type +- [CSS colors](/en-US/docs/Web/CSS/CSS_colors) module +- [sRGB](https://en.wikipedia.org/wiki/SRGB) on Wikipedia +- [CIELAB](https://en.wikipedia.org/wiki/CIELAB_color_space) on Wikipedia +- [CSS relative color syntax](https://developer.chrome.com/blog/css-relative-color-syntax) on developer.chrome.com (2023) diff --git a/files/en-us/web/css/hue/index.md b/files/en-us/web/css/hue/index.md index e99092c44acbce0..c23ecabf22f6a58 100644 --- a/files/en-us/web/css/hue/index.md +++ b/files/en-us/web/css/hue/index.md @@ -17,9 +17,9 @@ It is used in the color functions that accept hue expressed as a single value, s ![An sRGB color wheel](color_wheel.svg) -The color wheel above shows hues at all angles in the [sRGB](https://en.wikipedia.org/wiki/SRGB) color space. In particular, _red_ is at `0deg`, _yellow_ is at `60deg`, _lime_ is at `120deg`, _cyan_ is at `180deg`, _blue_ is at `240deg`, and _magenta_ is at `300deg`. +The color wheel above shows hues at all angles in the [sRGB](https://en.wikipedia.org/wiki/SRGB) {{glossary("color space")}}. In particular, _red_ is at `0deg`, _yellow_ is at `60deg`, _lime_ is at `120deg`, _cyan_ is at `180deg`, _blue_ is at `240deg`, and _magenta_ is at `300deg`. -> **Note:** The angles corresponding to particular hues depend on the color space. For example, the hue angle of sRGB green is `120deg` in the sRGB color space, but `134.39deg` in the CIELAB color space. +The angles corresponding to particular hues differ depending on the color space. For example, the hue angle of sRGB green is `120deg` in the sRGB color space, but `134.39deg` in the CIELAB color space. The following table lists typical colors at various angles in the sRGB (used by {{CSSXref("color_value/hsl", "hsl()")}} and {{CSSXref("color_value/hwb", "hwb()")}}), CIELAB (used by {{CSSXref("color_value/lch", "lch()")}}), and Oklab (used by {{CSSXref("color_value/oklch", "oklch()")}}) color spaces: