Skip to content

Latest commit

 

History

History
457 lines (300 loc) · 15.6 KB

color-4-hwb.md

File metadata and controls

457 lines (300 loc) · 15.6 KB

HWB Color Functions: Draft 1

(Issue)

This proposal adds a new hwb() color format to the sass:color module, along with inspection and adjustment options for whiteness and blackness.

Table of Contents

Background

This section is non-normative.

The CSS Color Module level 4 provides several new CSS formats for describing color, but hwb() stands out as part of the same sRGB color system that Sass already uses internally.

Summary

This section is non-normative.

This proposal defines a Sassified version of the hwb() color function added to CSS Color Level 4 – along with relevant inspection and adjustment options. This function will only be available inside the sass:color module to avoid conflicts with the CSS syntax, and will be converted to more common color-name, hex, or rgba() syntax for output -- following the same logic as our current color functions.

  • New color.hwb() function describes colors in the sRGB colorspace using $hue (defined identically to the hsl() "hue" value), along with $whiteness, $blackness, and optional $alpha transparency.
  • New color.whiteness() and color.blackness() functions return the respective values of w or b for a given color.
  • Existing color.adjust(), color.scale(), and color.change() functions will accept additional $whiteness and $blackness parameters before the final $alpha parameter.

Design Decisions

Both rgb/a() and hsl/a() are available in the global namespace because both of these formats are part of a stable CSS spec, and we want to make any standard CSS representation of a color parse as a Sass color. However, although hwb() is defined in Color Level 4, it's not yet implemented by any browser. Sass policy is to avoid supporting any new CSS syntax until it's shipped in a real browser, so hwb() will not be available in the global namespace initially. Instead, it will appear in the sass:color namespace which is guaranteed to be forwards-compatible with future CSS changes.

Because the color.hwb() function isn't currently intended to directly implement CSS's native hwb() function, it will not accept special number string or special variable string values that can only be resolved in CSS. However, for consistency with Sass's rgb() and hsl() functions it will support both space-delimited and comma-delimited arguments.

Future Designs

It's likely that as CSS Color Level 4 matures, hwb() will be stabilized and supported in browsers in one form or another. At this point, Sass will likely add support for a global hwb() function that's compatible with its CSS usage, including supporting special number and variable strings. The details of this are left to a future proposal.

Procedures

Scaling a Number

This algorithm takes a number number, a value factor, and a number max. It's written "scale <number> by <factor> with a max of <max>". It returns a number with a value between 0 and max and the same units as number.

Note: in practice, this is only ever called with number <= max.

  • If factor isn't a number with unit % between -100% and 100% (inclusive), throw an error.

  • If factor > 0%, return number + (max - number) * factor / 100%.

  • Otherwise, return number + number * factor / 100%.

Functions

All new functions are part of the sass:color built-in module.

hwb()

  • hwb($hue, $whiteness, $blackness, $alpha: 1)
    
    • If any of $hue, $whiteness, $blackness, or $alpha aren't numbers, throw an error.

    • If $hue has any units other than deg, throw an error.

    • If either of $whiteness or $blackness don't have unit % or aren't between 0% and 100% (inclusive), throw an error.

    • Let hue be $hue without units.

    • Let whiteness be $whiteness / 100%.

    • Let blackness be $blackness / 100%.

    • If whiteness + blackness > 1:

      • Set whiteness to whiteness / (whiteness + blackness).

      • Set blackness to blackness / (whiteness + blackness).

    • Let red, green, and blue be the result of converting hue, whiteness, and blackness to RGB.

    • Set red, green, and blue to their existing values multiplied by 255 and rounded to the nearest integers.

    • Let alpha be the result of percent-converting $alpha with a max of 1.

    • Return a color with the given red, green, blue, and alpha channels.

  • hwb($channels)
    
    • If $channels is not an unbracketed space-separated list, throw an error.

    • If $channels does not includes exactly three elements, throw an error.

    • Let hue and whiteness be the first two elements of $channels

    • If the third element of $channels has preserved its status as two slash-separated numbers:

      • Let blackness be the number before the slash and alpha the number after the slash.
    • Otherwise:

      • Let blackness be the third element of $channels.
    • Call hwb() with hue, whiteness, blackness, and alpha (if it's defined) as arguments and return the result.

whiteness()

whiteness($color)
  • If $color is not a color, throw an error.

  • Return a number with unit % between 0% and 100% (inclusive) such that:

    • hwb(hue($color), whiteness($color), blackness($color)) returns a color with the same red, green, and blue channels as $color.

    • whiteness($color) + blackness($color) <= 100%.

    The specific number returned here is left purposefully open-ended to allow implementations to pursue different strategies for representing color values. For example, one implementation may eagerly convert all colors to RGB channels and convert back when whiteness() or blackness() is called, where another may keep around their original HWB values and return those as-is.

blackness()

blackness($color)
  • If $color is not a color, throw an error.

  • Return a number with unit % between 0% and 100% (inclusive) such that:

    • hwb(hue($color), whiteness($color), blackness($color)) returns a color with the same red, green, and blue channels as $color.

    • whiteness($color) + blackness($color) <= 100%.

    The specific number returned here is left purposefully open-ended to allow implementations to pursue different strategies for representing color values. For example, one implementation may eagerly convert all colors to RGB channels and convert back when whiteness() or blackness() is called, where another may keep around their original HWB values and return those as-is.

adjust()

This proposal adds new $whiteness and $blackness parameters to the adjust() function, and its global adjust-color() alias.

adjust($color,
  $red: null, $green: null, $blue: null,
  $hue: null, $saturation: null, $lightness: null,
  $whiteness: null, $blackness: null,
  $alpha: null)

This function's new definition is as follows:

  • If $color isn't a color, throw an error.

  • Let alpha be $color's alpha channel.

  • If $alpha isn't null:

    • If $alpha isn't a number between -1 and 1 (inclusive), throw an error.

    • Set alpha to alpha + $alpha clamped between 0 and 1.

  • If $hue isn't a number or null, throw an error.

  • If any of $red, $green, or $blue aren't null:

    • If any of $hue, $saturation, $lightness, $whiteness, or $blackness aren't null, throw an error.

    • If any of $red, $green, or $blue aren't either null or numbers between -255 and 255 (inclusive), throw an error.

    • Let red, green, and blue be $color's red, green, and blue channels.

    • If $red isn't null, set red to red + $red clamped between 0 and 255.

    • If $green isn't null, set green to green + $green clamped between 0 and 255.

    • If $blue isn't null, set blue to blue + $blue clamped between 0 and 255.

    • Return a color with red, green, blue, and alpha as the red, green, blue, and alpha channels, respectively.

  • Otherwise, if either $saturation or $lightness aren't null:

    • If either $whiteness or $blackness aren't null, throw an error.

    • If either $saturation or $lightness aren't either null or numbers between -100 and 100 (inclusive), throw an error.

    • Let hue, saturation, and lightness be the result of calling hue($color), saturation($color), and lightness($color) respectively.

    • If $hue isn't null, set hue to hue + $hue.

    • If $saturation isn't null, set saturation to saturation + $saturation clamped between 0 and 100.

    • If $lightness isn't null, set lightness to lightness + $lightness clamped between 0 and 100.

    • Return the result of calling hsl() with hue, saturation, lightness, and alpha.

  • Otherwise, if either $hue, $whiteness, or $blackness aren't null:

    • If either $whiteness or $blackness aren't either null or numbers with unit % between -100% and 100% (inclusive), throw an error.

    • Let hue, whiteness, and blackness be the result of calling hue($color), whiteness($color), and blackness($color) respectively.

    • If $hue isn't null, set hue to hue + $hue.

    • If $whiteness isn't null, set whiteness to whiteness + $whiteness clamped between 0% and 100%.

    • If $blackness isn't null, set blackness to blackness + $blackness clamped between 0% and 100%.

    • Return the result of calling hwb() with hue, whiteness, blackness, and alpha.

  • Otherwise, return a color with the same red, green, and blue channels as $color and alpha as its alpha channel.

change()

This proposal adds new $whiteness and $blackness parameters to the change() function, and its global change-color() alias.

change($color,
  $red: null, $green: null, $blue: null,
  $hue: null, $saturation: null, $lightness: null,
  $whiteness: null, $blackness: null,
  $alpha: null)

This function's new definition is as follows:

  • If $color isn't a color, throw an error.

  • If $alpha isn't either null or a number between 0 and 1 (inclusive), throw an error.

  • Let alpha be $color's alpha channel if $alpha is null or $alpha without units otherwise.

  • If $hue isn't a number or null, throw an error.

  • If any of $red, $green, or $blue aren't null:

    • If any of $hue, $saturation, $lightness, $whiteness, or $blackness aren't null, throw an error.

    • If any of $red, $green, or $blue aren't either null or numbers between 0 and 255 (inclusive), throw an error.

    • Let red be $color's red channel if $red is null or $red without units otherwise.

    • Let green be $color's green channel if $green is null or $green without units otherwise.

    • Let blue be $color's blue channel if $blue is null or $blue without units otherwise.

    • Return a color with red, green, blue, and alpha as the red, green, blue, and alpha channels, respectively.

  • Otherwise, if either $saturation or $lightness aren't null:

    • If either $whiteness or $blackness aren't null, throw an error.

    • If either $saturation or $lightness aren't either null or numbers between 0 and 100 (inclusive), throw an error.

    • Let hue be the result of calling hue($color) if $hue is null, or $hue otherwise.

    • Let saturation be the result of calling saturation($color) if $saturation is null, or $saturation otherwise.

    • Let lightness be the result of calling lightness($color) if $lightness is null, or $lightness otherwise.

    • Return the result of calling hsl() with hue, saturation, lightness, and alpha.

  • Otherwise, if either $hue, $whiteness, or $blackness aren't null:

    • If either $whiteness or $blackness aren't either null or numbers with unit % between 0% and 100% (inclusive), throw an error.

    • Let hue be the result of calling hue($color) if $hue is null, or $hue otherwise.

    • Let whiteness be the result of calling whiteness($color) if $whiteness is null, or $whiteness otherwise.

    • Let blackness be the result of calling blackness($color) if $blackness is null, or $blackness otherwise.

    • Return the result of calling hwb() with hue, whiteness, blackness, and alpha.

  • Otherwise, return a color with the same red, green, and blue channels as $color and alpha as its alpha channel.

scale()

This proposal adds new $whiteness and $blackness parameters to the scale() function, and its global scale-color() alias.

scale($color,
  $red: null, $green: null, $blue: null,
  $saturation: null, $lightness: null,
  $whiteness: null, $blackness: null,
  $alpha: null)

This function's new definition is as follows:

  • If $color isn't a color, throw an error.

  • Let alpha be $color's alpha channel.

  • If $alpha isn't null, set alpha to the result of scaling alpha by $alpha with max 1.

  • If any of $red, $green, or $blue aren't null:

    • If any of $saturation, $lightness, $whiteness, or $blackness aren't null, throw an error.

    • Let red, green, and blue be $color's red, green, and blue channels.

    • If $red isn't null, set red to the result of scaling red by $red with max 255.

    • If $green isn't null, set green to the result of scaling green by $green with max 255.

    • If $blue isn't null, set blue to the result of scaling blue by $blue with max 255.

    • Return a color with red, green, blue, and alpha as the red, green, blue, and alpha channels, respectively.

  • Otherwise, if either $saturation or $lightness aren't null:

    • If either $whiteness or $blackness aren't null, throw an error.

    • Let hue, saturation, and lightness be the result of calling hue($color), saturation($color), and lightness($color) respectively.

    • If $saturation isn't null, set saturation to the result of scaling saturation by $saturation with max 100%.

    • If $lightness isn't null, set lightness to the result of scaling lightness by $lightness with max 100%.

    • Return the result of calling hsl() with hue, saturation, lightness, and alpha.

  • Otherwise, if either $hue, $whiteness, or $blackness aren't null:

    • Let hue, whiteness, and blackness be the result of calling hue($color), whiteness($color), and blackness($color) respectively.

    • If $whiteness isn't null, set whiteness to the result of scaling whiteness by $whiteness with max 100%.

    • If $blackness isn't null, set blackness to the result of scaling blackness by $blackness with max 100%.

    • Return the result of calling hwb() with hue, whiteness, blackness, and alpha.

  • Otherwise, return a color with the same red, green, and blue channels as $color and alpha as its alpha channel.