Archived:
🚚 This content is being maintained elsewhere. Our notes are likely out-of-date.
See the official Sass proposal for details.
(Issue)
This proposal adds Sass support for several new CSS color spaces defined in CSS Color Level 4, including access to non-RGB color models and colors outside the sRGB gamut.
Table of Contents ¶
See auto-generated TOC in header.
Background ¶
This section is non-normative.
When working with color on the web, there are a few important terms:
- A color model is a mathematical approach to representing colors and their relationships. Historically, RGB has been the dominant color model for both computer monitors and web browsers. Lately, CIELab and OKLab models have shown significant benefits by providing a more perceptually uniform distribution of colors, so that similar mathematical adjustments achieve visually similar results.
- A color space is the result of projecting a color model into a coordinate
system. In CSS, each color format describes a specific (and often unique)
color space. For example,
rgb()
projects the RGB color model into a cubic coordinate system, whilehsl()
projects the same model into a cylindrical (polar-angle) space. Different spaces will have different benefits when adjusting or interpolating colors for different purposes. - A color gamut is the full range of colors that can be described in a color space. Historically, all CSS spaces have been limited to the same sRGB gamut. However, modern computer monitors often support wider gamuts like display-p3.
Historically, CSS has only provided authors with color formats using the RGB model, limited to the sRGB gamut. As CSS is used for more applications (such as print) and displays continue to improve, those limitations become more clear. The CSS Color Level 4 specification defines a number of new color spaces, each with its own syntax, representing both new color models and wider RGB gamuts.
Since all CSS colors up until this point have been restricted to RGB math in the sRGB gamut, Sass has treated all color formats as interchangeable. That has allowed authors to inspect and manipulate colors in any space, without careful management or gamut mapping. It has also allowed Sass to output the most browser-compatible CSS format for any given color.
In order to support the color spaces in CSS Sass will need to start tracking the space and gamut associated with any given color, and provide author tools for managing those color spaces. In addition to supporting the new color space functions, we plan to update all functions in the color module, and provide some additional space and gamut management and inspection functions.
Summary ¶
This section is non-normative.
This proposal defines Sassified versions of all the color functions in CSS Color Level 4. Since the CIE color space defines the entire gamut of visible color, much larger than the target sRGB gamut, out-of-range color definitions will be clipped using a relative-colorimetric approach that leaves in-gamut colors unaffected.
There are several rules of thumb for working with color spaces in Sass:
- The
rgb
,hsl
, andhwb
spaces are considered ‘legacy spaces’, and will often get special handling for the sake of backwards compatibility. Colors defined using hex notation or CSS color names are considered part of thergb
color space. Legacy colors are emitted in the most compatible format. - Otherwise, any color defined in a given space will remain in that space, and be emitted in that space.
- Authors can explicitly convert a color’s space by using
color.to-space()
. This can be useful to enforce non-legacy behavior, by converting into a non-legacy space, or to ensure the color output is compatible with older browsers by converting colors into a legacy space before emitting. - The
srgb
color space is equivalent torgb
, except that one is a legacy space, and the other is not. - Color functions that allow specifying a color space for manipulation will
always use the source color space by default. When an explicit space is
provided for manipulation, the resulting color will still be returned in the
same space as the origin color. For
color.mix()
, the first color parameter is considered the origin color. - All legacy and RGB spaces represent bounded gamuts of color. When converting (
colors into a bounded gamut space, out-of-gamut channel values are maintained
whenever possible. The only exception is that
hsl
andhwb
color spaces are not able to express out-of-gamut color, so converting colors into those spaces will require gamut-mapping. - Mapping colors into a gamut is a lossy process. Whenever possible, it should
be left to the browser, which can map colors based on a given user’s display
capabilities. However, authors can perform explicit gamut mapping with the
color.to-gamut()
function. - Legacy browsers require colors in the
srgb
gamut. However, most modern displays support the widerdisplay-p3
gamut.
The oklab()
(cubic) and oklch()
(cylindrical) functions provide access to
an unbounded gamut of colors in perceptually uniform space. Authors can use
these functions to define reliably uniform colors. For example, the following
colors are perceptually similar in luminosity and saturation:
$pink: oklch(64% 0.196 353); // hsl(329.8 70.29% 58.75%)
$blue: oklch(64% 0.196 253); // hsl(207.4 99.22% 50.69%)
The oklch()
format uses consistent ‘lightness’ and ‘chroma’ values, while the
hsl()
format shows dramatic changes in both ‘lightness’ and ‘saturation’.
As such, oklch
is often the best space for consistent transforms.
The new color()
function provides access to a number of specialty spaces.
Most notably, display-p3
is a common space for wide-gamut monitors, making
it likely one of the more popular options for authors who simply want access to
a wider range of colors. For example, P3 greens are significantly ‘brighter’
and more saturated than the greens available in sRGB:
$fallback-green: rgb(0% 100% 0%);
$brighter-green: color(display-p3 0 1 0);
By default, all Sass color transformations are handled and returned in the
color space of the original color parameter. However, all relevant functions
now allow specifying an explicit color space for transformations. For example,
lightness & darkness adjustments are most reliable in oklch
:
$brand: hsl(0 100% 25.1%);
// result: hsl(0 100% 50.1%)
$hsl-lightness: color.adjust($brand, $lightness: 25%);
// result: hsl(6.57 61.7% 57.2%)
$oklch-lightness: color.adjust($brand, $lightness: 25%, $space: oklch);
Note that the returned color is still emitted in the original color space, even when the adjustment is performed in a different space.
Design Decisions ¶
Most of the design decisions involved in the proposal are based on the CSS Color Level 4 specification, which we have tried to emulate as closely as possible, while maintaining support for legacy projects. In some cases, that required major changes to the way Sass handles colors:
- RGB channel values are no longer clamped to the gamut of a color space,
except for the
hsl
andhwb
spaces, which are unable to represent out-of-gamut colors. By default Sass will output CSS with out-of-gamut colors, because browsers can provide better gamut mapping based on the user device capabilities. However, authors can use the providedcolor.to-gamut()
function to enforce mapping a color into a specific gamut. - RGB channel values are no longer rounded to the nearest integer, since the spec now requires maintaining precision wherever possible. This is especially important in RGB spaces, where color distribution is inconsistent.
We are not attempting to support all of CSS Color Level 5 at this
point, since it is not yet implemented in browsers. However, we have used it as
a reference while updating color manipulation functions such as color.mix()
.
Different color spaces often represent different color-gamuts, which can present
a new set of problems for authors. Some color manipulations are best handled
in a wide-gamut space like oklch
, but then need to be mapped back to a
narrower gamut like srgb
for legacy browsers. We established the following
guidelines for color conversion and mapping in Sass color functions:
- Every color function returns a color in the same space as the original color,
no matter what space was used for transformations. The only exception is
color.to-space()
, which can be used for manual space conversion. Functions that accept two colors (e.g.color.mix()
) return a color in the same space as the first color argument. - No color function performs gamut-mapping on out-of-gamut channels, except
color.to-gamut()
, which can be used for manual gamut-mapping.
Unfortunately, the legacy hsl
and hwb
color spaces are not able to express
out-of-gamut colors, even with out-of-range channel values, so any conversion
into those spaces (using color.to-gamut()
or manipulating colors in those
spaces) must always require gamut-mapping into the srgb
gamut. This is
defined as part of the CSS Color Level 4 specification for
converting colors.
Definitions ¶
Color ¶
Note that channel values are stored as specified, maintaining precision where possible, even when the values are out-of-gamut for the known color space.
A color is an object with several parts:
-
A color space that is either a known color space or an unquoted string.
-
An ordered list of numeric channel values.
-
A floating-point number alpha value between
0-1
, inclusive.While it’s valid to specify numbers outside this range, they are meaningless, and can be clamped by input functions when generating a color.
Legacy Color ¶
Both Sass and CSS have similar legacy behavior that relies on all colors being interchangeable as part of a shared
srgb
color space. While the new color formats will opt users into new default behavior, some legacy color formats behave differently for the sake of backwards-compatibility.
Colors in the rgb
, hsl
, or hwb
color spaces are
considered legacy colors. The output of a legacy color is not required to
match the input color space, and several color functions maintain legacy
behavior when manipulating legacy colors.
This includes colors defined using the CSS color names, hex syntax,
rgb()
,rgba()
,hsl()
,hsla()
, orhwb()
– along with colors that are manually converted into legacy color spaces.
Known Color Space ¶
Sass colors are stored as part of a known color space. Each space has a name and an ordered list of associated channels. Each channel has a name and position index (1-indexed) defined by the space and the order of channels in that space, and a number value with units matching those allowed by the space. Space and channel names match unquoted strings, ignoring case. They are always emitted as unquoted lowercase strings by inspection functions.
Values outside a bounded gamut range are valid, and remain un-clamped, but are considered out of gamut for the given color space. If the channel is bounded, or has a percentage mapping with a lower-boundary of zero, then the channel is considered scalable.
Some color spaces use a polar angle value for the hue
channel. Polar-angle
hues represent an angle position around a given hue wheel, using a CSS <angle>
dimension or number (interpreted as a deg
value), and are serialized with
deg
units.
Colors specified using a CSS color keyword or the hex notation are converted
to rgb
and serialized as part of the rgb
color space.
The known color spaces and their channels are:
-
rgb
(RGB, legacy):red
,green
,blue
:-
gamut: bounded
-
number:
[0,255]
Percentages
[0%,100%]
map to the[0,255]
range.
-
-
hwb
(RGB, legacy):hue
: polar anglewhiteness
,blackness
:- gamut: bounded
- percentage:
[0%,100%]
-
hsl
(RGB, legacy):hue
: polar anglesaturation
,lightness
:- gamut: bounded
- percentage:
[0%,100%]
-
srgb
,srgb-linear
,display-p3
,a98-rgb
,prophoto-rgb
,rec2020
(RGB):red
,green
,blue
:-
gamut: bounded
-
number:
[0,1]
Percentages
[0%,100%]
map to the[0,1]
range.
-
-
xyz
,xyz-d50
,xyz-d65
:x
,y
,z
:-
gamut: un-bounded, scalable
-
number:
[0,1]
Percentages
[0%,100%]
map to the[0,1]
range.
-
-
lab
:-
lightness
:-
gamut: un-bounded, scalable
-
number:
[0,100]
Percentages
[0%,100%]
map to the[0,100]
range.
-
-
a
,b
:-
gamut: un-bounded
-
number:
[-125,125]
Percentages
[-100%,100%]
map to the[-125,125]
range.
-
-
-
lch
:-
lightness
:-
gamut: un-bounded, scalable
-
number:
[0,100]
Percentages
[0%,100%]
map to the[0,100]
range.
-
-
chroma
:-
gamut: un-bounded, scalable
-
number:
[0,150]
Percentages
[0%,100%]
map to the[0,150]
range.
-
-
hue
: polar angle
-
-
oklab
:-
lightness
:-
gamut: un-bounded, scalable
-
number:
[0,1]
Percentages
[0%,100%]
map to the[0,1]
range.
-
-
a
,b
:-
gamut: un-bounded
-
number:
[-0.4,0.4]
Percentages
[-100%,100%]
map to the[-0.4,0.4]
range.
-
-
-
oklch
:-
lightness
:-
gamut: un-bounded, scalable
-
number:
[0,1]
Percentages
[0%,100%]
map to the[0,1]
range.
-
-
chroma
:-
gamut: un-bounded, scalable
-
number:
[0,0.4]
Percentages
[0%,100%]
map to the[0,0.4]
range.
-
-
hue
: polar angle
-
Predefined Color Spaces ¶
‘Predefined color spaces’ can be described using the
color()
function.
The predefined RGB spaces are:
srgb
srgb-linear
display-p3
a98-rgb
prophoto-rgb
rec2020
The predefined XYZ spaces are:
xyz
xyz-d50
xyz-d65
(an alias forxyz
)
Missing Components ¶
In some cases, a color can have one or more missing components (channel or
alpha values). Missing components are represented by the keyword none
. When
interpolating between colors, the missing component is replaced by the value
of that same component in the other color. In all other cases, the missing
value is treated as 0
.
For the sake of interpolating between colors with missing components, the following analogous components are defined by CSS Color Level 4:
| Category | Components | | Reds | r,x | | Greens | g,y | | Blues | b,z | | Lightness | l | | Colorfulness | c,s | | Hue | h |
If any analogous missing components are present, they will be carried forward and re-inserted in the converted color before linear interpolation takes place.
Powerless Components ¶
In some color spaces, it is possible for a channel value to become ‘powerless’
in certain circumstances. If a powerless channel value is produced as the
result of color-space conversion, then that value is considered to be
missing, and is replaced by the keyword none
.
-
hsl
:-
If the
saturation
value is0%
, then thehue
channel is powerless. -
If the
lightness
value is either0%
or100%
, then both thehue
andsaturation
values are powerless.
-
-
hwb
:- If the combined
whiteness
andblackness
values (after normalization) are equal to100%
, then thehue
channel is powerless.
- If the combined
-
lab
/oklab
:- If the
lightness
value is0%
, then both thea
andb
channels are powerless.
The current spec has an inline issue asking if high values of
lightness
(whites) should make thea
andb
values powerless: See: https://drafts.csswg.org/css-color-4/#issue-e05ac5c3 - If the
-
lch
/oklch
:-
If the
chroma
value is 0%, then thehue
channel is powerless. -
If the
lightness
value is0%
, then both thehue
andchroma
channels are powerless.
The current spec has an inline issue asking if high values of
lightness
(whites) should make thehue
andchroma
values powerless. See: https://drafts.csswg.org/css-color-4/#issue-1813c844 -
Color Interpolation Method ¶
A color interpolation method is a space-separated list of unquoted strings, parsed according to the following syntax definition:
ColorInterpolationMethod ::= ‘in’ (
RectangularColorSpace
| PolarColorSpace HueInterpolationMethod?
)
RectangularColorSpace ::= ‘srgb’
| ‘srgb-linear’
| ‘lab’
| ‘oklab’
| ‘xyz’
| ‘xyz-d50’
| ‘xyz-d65’
PolarColorSpace ::= ‘hsl’
| ‘hwb’
| ‘lch’
| ‘oklch’
HueInterpolationMethod ::= (
‘shorter’
| ‘longer’
| ‘increasing’
| ‘decreasing’
| ‘specified’
) ‘hue’
The resulting interpolation color space is the known color space whose name
is given by either the PolarColorSpace
or RectangularColorSpace
productions.
Different color interpolation methods provide different advantages. For that reason, individual color procedures and functions can establish their own color interpolation defaults, or provide a syntax for authors to explicitly choose the method that best fits their need. The CSS Color Level 4 specification provides additional guidance for determining appropriate defaults.
Procedures ¶
Converting a Color ¶
Colors can be converted from one known color space to another. Algorithms for
color conversion are defined in the CSS Color Level 4
specification. Each algorithm takes a color origin-color
, and a known color
space target-space
, and returns a color output-color
.
The algorithms are:
For additional details, see the Sample code for color conversions.
Gamut Mapping ¶
Some [known color spaces] describe limited color gamuts. If a color is ‘out of gamut’ for a particular space (most often because of conversion from a larger-gamut color-space), it can be useful to ‘map’ that color to the nearest available ‘in-gamut’ color. Gamut mapping is the process of finding an in-gamut color with the least objectionable change in visual appearance.
Gamut mapping in Sass follows the CSS gamut mapping algorithm.
This procedure accepts a color origin
in the color space origin color space
,
and a destination color space destination
. It returns the result of a
CSS gamut map procedure, which is a color in the destination
color
space.
This algorithm implements a relative colorimetric intent, and colors inside the destination gamut are unchanged. Since the process is lossy, authors should be encouraged to let the browser handle gamut mapping when possible.
Parsing Color Components ¶
This procedure accepts an input
parameter to parse, along with an optional
known color space space
. It throws common parse errors when necessary, and
returns either null
or three values: an optional color space, a list of
channel numbers, and a floating-point alpha value.
This supports both the space-specific color formats like
hsl()
andrgb()
, where the space is determined by the function, as well as the syntax ofcolor()
, where the space is included as one of the input arguments (and may be a user-defined space).
The procedure is:
-
If
input
is a special variable string, returnnull
. -
Let
include-space
be true ifspace
is null, and false otherwise. -
If
input
is a bracketed list, or a list with a separator other than ‘slash’ or ‘space’, throw an error. -
If
input
is a slash-separated list:-
If
input
doesn’t have exactly two elements, throw an error. -
Otherwise, let
components
be the first element andalpha
the second element ofinput
.
-
-
Otherwise:
-
Let
components
be an unbracketed space separated list of all except the last element ofinput
. -
If the last element of
input
is an unquoted string that contains/
:-
Let
split-last
be the result callingstring.split()
with the last element ofinput
as the string to split, and/
as the separator. -
If there are not two items in
split-last
, throw an error. -
If either item in
split-last
can be coerced to a number, replace the current value of the item with the resulting number value. -
Let
alpha
be the second element insplit-last
, and append the first element ofsplit-last
tocomponents
.
This solves for a legacy handling of
/
in Sass that would produce an unquoted string when the alpha value is a CSS function such asvar()
or when either value is the keywordnone
. -
-
Otherwise, if the last element of
input
has preserved its status as two slash-separated numbers:- Let
alpha
be the number after the slash, and append the number before the slash tocomponents
.
- Let
-
Otherwise, append the last element of
input
tocomponents
.
-
-
If
components
is an empty list, throw an error. -
If
components
is a special variable string:- Let
channels
be the value ofcomponents
.
- Let
-
Otherwise:
-
If
components
is not an unbracketed space-separated list, throw an error. -
If
space
is null:-
Let
input-space
be the first element incomponents
. -
If
input-space
is not either a known color space or an unquoted string, throw an error. -
Let
space
be the value ofinput-space
. -
Let
channels
be an unbracketed space-separated list with the remaining elements fromcomponents
.
-
-
Otherwise, let
channels
be the value ofcomponents
. -
Let
expected
be the number of channels inspace
ifspace
is a known color space, and null otherwise. -
If any element of channels is not either a number, a special variable string, a special number string, or the keyword
none
, throw an error.
-
-
If
alpha
is null, letalpha
be1
. -
Otherwise, If
alpha
is not a special number string:-
If
alpha
is a number, setalpha
to the result of percent-convertingalpha
with a max of 1, and then clamping the value between 0 and 1, inclusive. -
Otherwise, throw an error.
-
-
If
space
orchannels
is a special variable string, or ifalpha
is a special number string, returnnull
. -
If any element of
channels
is a special number string, returnnull
.Doing this late in the process allows us to throw any obvious syntax errors, even for colors that can’t be fully resolved on the server.
-
If
expected
is not null, and the length ofchannels
is not equal toexpected
, throw an error.Once special values have been handled, any colors remaining should have exactly the expected number of channels.
-
Set
normal
to the result of normalizingchannels
inspace
. -
If
include-space
is true, letparsed
be an unbracketed space-separated list withspace
as the first element, andnormal
as the second. -
Otherwise, let
parsed
be the value ofnormal
. -
Return an unbracketed slash-separated list with
parsed
as the first element, andalpha
as the second.This results in valid CSS color-value output, while also grouping space, channels, and alpha as separate elements in nested lists. Alternately, we could allow
parsed
to be a single flat list, even when the color-space is included?
Percent-Converting a Number ¶
This algorithm takes a SassScript number number
and a number max
. It returns
a number relative to the range [0,max]
without clamping.
In order to support both out-of-gamut channels and unbounded ranges, this value is no longer clamped between 0 and
max
-
If
number
has units other than%
, throw an error. -
If
number
has the unit%
, setnumber
tonumber * max / 100
, without units. -
Return
number
.
Normalizing Color Channels ¶
This process accepts an ordered list channels
to validate, and a known color
space space
to normalize against. It throws an error if any channel is
invalid for a known color space, or returns a normalized list of valid channels.
-
If
space
is not a known color space or an unquoted string, throw an error. -
If
channels
is not an ordered list, throw an error. -
Let
normal
be an empty list. -
For each
channel
inchannels
:-
If
channel
is not a number or the keywordnone
, throw an error. -
If
channel
is the keywordnone
, or ifspace
is not a known color space, appendchannel
as the next item innormal
.We don’t attempt further channel normalization for unknown color spaces.
-
Otherwise:
-
Let
valid
be the corresponding channel defined by the known color spacespace
. -
If
valid
is a polar-anglehue
:-
Let
normal-channel
be the result of convertingchannel
todeg
allowing unitless. -
Append
normal-channel
as the next item innormal
.
Normalizing the result into a half-open range of
[0,360)
would be a lossy transformation, since some forms of hue interpolation require the specified hue values. -
-
Otherwise, if
valid
requires a percentage:-
If
channel
is a number with units other than%
, throw an error. -
Append
channel
as the next item innormal
.
-
-
Otherwise:
-
Set
channel
to the result of percent-convertingchannel
with amax
defined by thevalid
channel range. -
Append
channel
as the next item innormal
.
-
-
-
-
Return
normal
.
Interpolating Colors ¶
This procedure is based on the color interpolation procedures defined in CSS Color Level 4.
This procedure accepts two color arguments (color1
and color2
), a
[color interpolation method] method
, and a percentage weight
for color1
in the mix. It returns a new color mix
that represents the appropriate mix of
input colors.
-
If either
color1
orcolor2
is not a color, throw an error. -
If
weight
is null, setweight
to50%
. -
Set
weight
to the result of percent-convertingweight
with a max of 1, and then clamping the value between 0 and 1, inclusive. -
Otherwise:
-
If
method
is not a color interpolation method, throw an error. -
Let
space
be the interpolation color space specified inmethod
. -
If
space
is a PolarColorSpace:- Let
hue-arc
be theHueInterpolationMethod
specified inmethod
, orshorter
if no hue interpolation is specified.
- Let
-
-
For each
color
ofcolor1
andcolor2
:-
Let
origin-space
becolor
’s color space. -
If
origin-space
is not a known color space, throw an error. -
Let
missing
be a list of channel names incolor
that are missing. -
Set
color
to the results of convertingcolor
intospace
. -
For each
channel
inmissing
:- If
space
has an analogous component tochannel
, setchannel
tonone
.
- If
-
If any
component
ofcolor
isnone
, set thatcomponent
to the value of the corresponding component in the other color.If both values are
none
, the interpolation result for that component will also benone
. -
Set
color
to the result of premultiplyingcolor
.
-
-
Let
mix
be a new color in the known color spacespace
, withnone
for alpha and all channel values. -
For each
channel
ofmix
:-
Let
channel1
andchannel2
be the corresponding channel values incolor1
andcolor2
respectively. -
If
channel
represents a hue angle, setchannel1
andchannel2
respectively to the results of hue interpolation withchannel1
ashue1
,channel2
ashue2
, using thehue-arc
method. -
Set
channel
to the result of calculating(channel1 * weight) + (channel2 * (1 - weight))
.Channel rounding has been removed, since it is a lossy transform.
-
-
Return the result of un-premultiplying
mix
.
Premultiply Transparent Colors ¶
When the colors being interpolated are not fully opaque, they are transformed
into premultiplied color values. This process accepts a single color
and
updates the channel values if necessary, returning a new color with
premultiplied channels.
-
If the
color
has analpha
value of 1 ornone
, returncolor
unchanged.It’s not possible to premultiply channels relative to a missing alpha, and no multiplication is necessary with full opacity.
-
Otherwise, for each
channel
incolor
:-
If the
channel
value isnone
, or ifchannel
represents a polar-anglehue
, keep the original value ofchannel
. -
Otherwise, set
channel
to the result of multiplying thechannel
value by thealpha
value.
-
-
Return the resulting
color
with premultiplied channels.
The same process can be run in reverse, to un-premultiply the channels of a
given color
:
-
If
color
has analpha
value of 1, 0, ornone
, returncolor
unchanged. -
Otherwise, for each
channel
incolor
:-
If the
channel
valuenone
, or ifchannel
represents a polar-anglehue
, keep the original value ofchannel
. -
Otherwise, set
channel
to the result of dividing the premultipliedchannel
value by thealpha
value.
-
-
Return the resulting
color
with un-premultiplied channels.
Hue Interpolation ¶
When interpolating between polar-angle hue channels, there are multiple ‘directions’ the interpolation could move, following different logical rules.
This process accepts two hue angles (hue1
and hue2
), and returns both hues
adjusted according to the given method
. When no hue interpolation method
is
specified, the default is shorter
.
The process for each hue interpolation method is defined
in CSS Color Level 4. If the method
is not the value 'specified'
,
both hue angles are set to angle % 360deg
prior to interpolation.
Deprecated Functions ¶
Individual color-channel functions defined globally or in the color module are
deprecated in favor of the new color.channel()
function. That includes:
color.red()
/red()
color.green()
/green()
color.blue()
/blue()
color.hue()
/hue()
color.saturation()
/saturation()
color.lightness()
/lightness()
color.whiteness()
color.blackness()
Legacy global color functions are also deprecated:
adjust-hue()
saturate()
/desaturate()
transparentize()
/opacify()
/fade-in()
lighten()
/darken()
adjust-color()
/change-color()
/scale-color()
mix()
/complement()
/invert()
/grayscale()
While deprecated, if the specified color argument is not a legacy color, throw an error.
New Color Module Functions ¶
These new functions are part of the built-in sass:color
module.
color.space()
¶
-
space($color)
-
If
$color
is not a color, throw an error. -
Return an unquoted string with the name of
$color
s known color space.
-
color.to-space()
¶
-
to-space($color, $space)
-
If
$color
is not a color, throw an error. -
Let
origin-space
be the result of callingcolor.space($color)
. -
If
origin-space == $space
, return$color
.This allows unknown spaces, as long as they match the origin space.
-
If either
origin-space
or$space
is not a known color space, throw an error. -
Return the result of converting the
origin-color
$color
to thetarget-space
$space
.
-
color.is-legacy()
¶
-
is-legacy($color)
-
If
$color
is not a color, throw an error. -
Return
true
if$color
is a legacy color, orfalse
otherwise.
-
color.is-powerless()
¶
-
is-powerless($color, $channel, $space: null)
-
If
$color
is not a color, throw an error. -
If
$space
is null:- Let
color
be$color
, and letspace
be the result of callingspace($color)
.
- Let
-
Otherwise:
- Let
color
be the result of callingcolor.to-space($color, $space)
, and letspace
be$space
.
- Let
-
If
space
is not a known color space, throw an error. -
If
$channel
is not the name of a channel in the color-spacespace
, throw an error. -
Return
true
if the channel$channel
is powerless incolor
, otherwise returnfalse
.
-
color.is-in-gamut()
¶
-
is-in-gamut($color, $space: null)
-
If
$color
is not a color, throw an error. -
Let
space
be the value of$space
if specified, or the result of callingcolor.space($color)
otherwise. -
If
space
is not a known color space, throw an error. -
Let
color
be the result of callingcolor.to-space($color, space)
. -
For all bounded channels in
space
, if the associated channel value in$color
is outside the bounded range, returnfalse
. -
Otherwise, return
true
.
-
color.to-gamut()
¶
-
to-gamut($color, $space: null)
-
If
$color
is not a color, throw an error. -
Let
origin-space
be the result of callingcolor.space($color)
. -
Let
target-space
be the value of$space
if specified, or the value oforigin-space
otherwise. -
If
target-space
is not a known color space, throw an error. -
Return the result of gamut mapping with
$color
as the origin color,origin-space
as the origin color space, andtarget-space
as the destination color space.
-
color.channel()
¶
Note that channel values are stored as specified, even if those values are out-of-gamut for the known color space used. Similarly, this color-channel inspection function may return out-of-gamut channel values.
-
channel($color, $channel, $space: null)
-
If
$space
is null:- Let
space
be the result of callingcolor.space($color)
, and letcolor
be the value of$color
.
- Let
-
Otherwise:
- Let
color
be the result of callingcolor.to-space($color, $space)
, and letspace
be the value of$space
.
- Let
-
Let
channels
be a map 1-indexed integer channel keys and their corresponding values incolor
. -
If
space
is a known color space:-
Let
named-channels
be a map of channel names defined byspace
, and their corresponding values incolor
. -
Set
channels
to the result ofmap.merge(channels, named-channels)
.
-
-
Let
value
be the result of callingmap.get(channels, $channel)
. -
If
value
isnull
, throw an error. -
Otherwise, return
value
.
-
Modified Color Module Functions ¶
color.hwb()
¶
These functions are now deprecated. Authors should use global hwb()
instead.
Channel clamping and scaling have been removed from the global function, since we now allow out-of-gamut color-channels to be stored as specified.
-
hwb($channels)
- Return the result of calling the global function
hwb($channels)
.
- Return the result of calling the global function
-
hwb($hue, $whiteness, $blackness, $alpha: 1)
- Return the result of calling the global function
hwb($hue $whiteness $blackness / $alpha)
.
- Return the result of calling the global function
color.mix()
¶
mix($color1, $color2,
$weight: 50%,
$method: null)
-
If either
$color1
or$color2
is not a color with a known color space, throw an error. -
If
$method
is null:-
If either
$color1
or$color2
is not a legacy color, throw an error.Method is required for non-legacy colors. This matches the
color-mix()
function defined in Colors Level 5, and allows us to add additional default behavior in the future. -
Let
color1
andcolor2
be the result of converting$color1
and$color2
respectively into thergb
known color space. -
Let
weight-scale
be the result of percent-converting$weight
with amax
of 1, and clamping the value between 0 and 1, inclusive. -
Let
normal-weight
beweight-scale * 2 - 1
. -
Let
alpha1
andalpha2
be the alpha values ofcolor1
andcolor2
, respectively. -
Let
alpha-distance
bealpha1 - alpha2
. -
Let
weight-by-distance
benormal-weight * alpha-distance
. -
If
weight-by-distance == -1
, letcombined-weight1
benormal-weight
. -
Otherwise:
-
Let
weight-distance-sum
benormal-weight + alpha-distance
. -
Let
combined-weight1
beweight-distance-sum / (1 + weight-by-distance)
.
-
-
Let
weight1
be(combined-weight1 + 1) / 2
. -
Let
weight2
be1 - weight1
. -
Let
red1
andred2
be the red channels ofcolor1
andcolor2
respectively. -
Let
red
be the result of roundingred1 * weight1 + red2 * weight2
to the nearest integer. -
Let
green1
andgreen2
be the green channels ofcolor1
andcolor2
respectively. -
Let
green
be the result of roundinggreen1 * weight1 + green2 * weight2
to the nearest integer. -
Let
blue1
andblue2
be the blue channels ofcolor1
andcolor2
respectively. -
Let
blue
be the result of roundingblue1 * weight1 + blue2 * weight2
to the nearest integer. -
Let
alpha
bealpha1 * weight-scale + alpha2 * (1 - weight-scale)
. -
Return a legacy color in the
rgb
space, with the givenred
,green
, andblue
channels, andalpha
value.
-
-
Otherwise:
-
If
$method
is not a color interpolation method, throw an error. -
Let
space
be the known color space specified in$method
.
-
-
If
space
is unquoted andspace == hsl
orspace == hwb
:- Let
color1
andcolor2
be the result of converting and gamut mapping$color1
and$color2
respectively intospace
.
These color spaces are unable to express colors outside the
srgb
gamut. - Let
-
Otherwise, let
color1
andcolor2
be the result of converting$color1
and$color2
respectively intospace
. -
Return the result of interpolating between
color1
andcolor2
with the specified$weight
and$method
.
color.change()
¶
change($color, $args...)
This function is also available as a global function named change-color()
.
-
If
$color
is not a color, throw an error. -
If any item in
$args
is not a keyword argument, throw an error. -
Let
space
be$color
’s color space. -
If the keyword argument
$space
is specified in$args
:-
If
$space
is not a known color space, and$space != space
, throw an error. -
Set
space
to the value of$space
. -
Let
color
be the result of converting$color
tospace
.
-
-
Otherwise, let
color
be the value of$color
. -
Let
legacy
betrue
if$color
is a legacy color andspace
is a legacy color space, andfalse
otherwise. -
Let
alpha
becolor
’s alpha property. -
If the keyword argument
$alpha
is specified in$args
:- Set
alpha
to the result of percent-converting$alpha
, and clamping it between 0 and 1 (inclusive).
- Set
-
Let
channel-args
be the remaining keyword arguments in$args
, not including$space
or$alpha
arguments. -
Let
channels
be a list of thecolor
’s channels. -
For each keyword
key
and valuenew
inchannel-args
:-
If
key
is a string in the formatchannel<integer>
, setkey
to the value of<integer>
.This allows e.g.
color.change($color, $channel1: 0.25)
for changing color channels in unknown color spaces. -
If
key
is not the name or index of a channel inchannels
, throw an error. -
Set the corresponding
channel
inchannels
tonew
.
-
-
If
space
is a known color space, setchannels
to the result of normalizingchannels
inspace
. -
Return a color in color space
space
, withchannels
channels, and an alpha ofalpha
.
color.adjust()
¶
adjust($color, $args...)
This function is also available as a global function named adjust-color()
.
-
If
$color
is not a color, throw an error. -
If any item in
$args
is not a keyword argument, throw an error. -
Let
space
be$color
’s color space. -
If the keyword argument
$space
is specified in$args
:-
If
$space
is not a known color space, and$space != space
, throw an error. -
Set
space
to the value of$space
. -
Let
color
be the result of converting$color
tospace
.
-
-
Otherwise, let
color
be the value of$color
. -
Let
legacy
betrue
if$color
is a legacy color andspace
is a legacy color space, andfalse
otherwise. -
Let
alpha
becolor
’s alpha property. -
If the keyword argument
$alpha
is specified in$args
:-
If
$alpha
is not a unitless number between-1
and1
(inclusive), throw an error. -
Set
alpha
to the value of$alpha + alpha
clamped between 0 and 1.
-
-
Let
channel-args
be the remaining keyword arguments in$args
, not including$space
or$alpha
arguments. -
Let
channels
be a list of thecolor
’s channels. -
For each keyword
key
and valueadjust
inchannel-args
:-
If
key
is a string in the formatchannel<integer>
, setkey
to the value of<integer>
.This allows e.g.
color.change($color, $channel1: 0.25)
for changing color channels in unknown color spaces. -
If
key
is not the name or index of a channel inchannels
, throw an error. -
Set the corresponding
channel
inchannels
tochannel + adjust
, treating anynone
keyword as a value of0
.
-
-
If
space
is a known color space, setchannels
to the result of normalizingchannels
inspace
. -
Return a color in color space
space
, withchannels
channels, and an alpha ofalpha
.
color.scale()
¶
scale($color, $args...)
This function is also available as a global function named scale-color()
.
-
If
$color
is not a color, throw an error. -
If any item in
$args
is not a keyword argument, throw an error. -
Let
space
be$color
’s known color space. -
If the keyword argument
$space
is specified in$args
:-
If
$space
is not a known color space, throw an error. -
Set
space
to the value of$space
. -
Let
color
be the result of converting$color
tospace
.
-
-
Otherwise, let
color
be the value of$color
. -
Let
legacy
betrue
if$color
is a legacy color andspace
is a legacy color space, andfalse
otherwise. -
Let
alpha
becolor
’s alpha property. -
If the keyword argument
$alpha
is specified in$args
:-
If
$alpha
is not a unitless number between-1
and1
(inclusive), throw an error. -
Set
alpha
to the result of [scaling]alpha
by$alpha
withmax
1, treating anynone
keyword as a value of0
.
-
-
Let
channel-args
be the remaining keyword arguments in$args
, not including$space
or$alpha
arguments. -
Let
channels
be a list of thecolor
’s channels. -
For each keyword
scale
inchannel-args
:-
If
scale
is not the name of a bounded or percentage-mapped channel inchannels
, throw an error. -
Set the corresponding
channel
inchannels
to the result of [scaling]channel
byscale
with amax
defined by the channel boundary.
-
-
Let
normal
be the result of normalizingchannels
. -
Return a color in color space
space
, withnormal
channels, and an alpha ofalpha
.
color.complement()
¶
complement($color, $space: null)
This function is also available as a global function named complement()
.
-
If
$color
is not a color, throw an error. -
If
$space
is null:-
If
$color
is a legacy color, letspace
behsl
. -
Otherwise, throw an error.
-
-
Otherwise:
-
If
$space
is not a known color space with a polar-angle hue channel, throw an error.This currently allows
hsl
,hwb
,lch
, andoklch
. We may decide to provide additional options in the future. -
Let
space
be the value of$space
.
-
-
Return the result of calling
color.adjust($color, $hue: 180deg, $space: space)
.
color.invert()
¶
invert($color, $space: null)
This function is also available as a global function named invert()
.
-
If
$color
is not a color, throw an error. -
If
$space
is null:-
If
$color
is a legacy color, letspace
bergb
, and letmix-space
be null.This allows us to also enforce legacy behavior in the final weighted mix.
-
Otherwise, throw an error.
-
-
Otherwise:
-
If
$space
is not a known color space, throw an error. -
Let
space
be$space
, and letmix-space
be$space
.
-
-
Let
color
be the result of converting and gamut mapping$color
into the color spacespace
. -
If
space == hwb
:-
Let
hue
,whiteness
, andblackness
be the three elements ofcolor
’s channels. -
Let
hue-out
be the result of(hue + 180deg) % 360deg
. -
Let
gray
be the result ofwhiteness + blackness
. -
Let
white
begray - whiteness
, and letblack
begray - blackness
. -
Let
invert
be the result of callingcolor.change(color, $hue: hue-out, $whiteness: white, $blackness: black)
.
-
-
Otherwise:
-
Let
invert
be the value ofcolor
. -
For each
channel
element incolor
’s channels:-
If
channel
represents a polar-angle hue:- Let
new
be(channel + 180deg) % 360deg
.
- Let
-
Otherwise, if
channel
represents either chroma or saturation:- Let
new
bechannel
.
- Let
-
Otherwise:
-
Let
min
andmax
be the minimum and maximum values defined forchannel
inspace
. -
Let
new
bemax - channel
ifmin == 0
, andchannel * -1
otherwise.
-
-
Set the corresponding channel of
invert
to benew
.
-
-
-
Return the result of calling
color.mix(invert, color, $weight, mix-space)
.
color.grayscale()
¶
grayscale($color)
No space argument is provided, since the results should always be in gamut.
This function is also available as a global function named grayscale()
.
-
If
$color
is not a color, throw an error. -
If
$color
is a legacy color:- Return the result of converting
$color
tohsl
, and changing the ‘saturation’ channel to 0.
- Return the result of converting
-
Otherwise:
-
Let
origin
be$color
’s known color space. -
Let
color
be the result of converting$color
tooklch
, and setting thechroma
channel to 0. -
Return the result of converting
color
toorigin
.
-
color.ie-hex-str()
¶
This function is also available as a global function named ie-hex-str()
. Both
functions are deprecated.
ie-hex-str($color)
-
If
$color
is not a color, throw an error. -
Let
rgb
be the result of converting$color
torgb
. -
Let
hex-list
be an empty list. -
For each
channel
inrgba
’s channels, as numbers:-
Let
hex-channel
be the hexadecimal representation ofchannel
’s value. -
Append
hex-channel
as the next item inhex-list
.
-
-
Let
alpha
bergb
’s alpha value. -
Let
hex-alpha
be the hexadecimal representation ofalpha * 255
. -
Append
hex-alpha
as the next item inhex-list
. -
Return the result of concatenating
hex-list
into a string.
New Global Functions ¶
These new CSS functions are provided globally.
hwb()
¶
-
hwb($channels)
-
Let
components
be the result of parsing$channels
with anhwb
space. -
If
components
is null, return a plain CSS function string with the name"hwb"
and the argument$channels
. -
Let
channels
be the first element andalpha
the second element ofcomponents
. -
Let
hue
,whiteness
, andblackness
be the three elements ofchannels
.Channel clamping and scaling have been removed, since we now allow out-of-gamut color-channels to be stored as specified.
-
Return a legacy color in the
hwb
space, with the givenhue
,whiteness
, andblackness
channels, andalpha
value.
-
lab()
¶
-
lab($channels)
-
Let
components
be the result of parsing$channels
in anlab
space. -
If
components
is null, return a plain CSS function string with the name"lab"
and the argument$channels
. -
Let
channels
be the first element andalpha
the second element ofcomponents
. -
Let
lightness
,a
, andb
be the three elements ofchannels
. -
Return a color in the
lab
known color space, with the givenlightness
,a
, andb
channels, andalpha
value.
-
lch()
¶
-
lch($channels)
-
Let
components
be the result of parsing$channels
in anlch
space. -
If
components
is null, return a plain CSS function string with the name"lab"
and the argument$channels
. -
Let
channels
be the first element andalpha
the second element ofcomponents
. -
Let
lightness
,chroma
, andhue
be the three elements ofchannels
. -
Return a color in the
lch
known color space, with the givenlightness
,chroma
, andhue
channels, andalpha
value.
-
oklab()
¶
-
oklab($channels)
-
Let
components
be the result of parsing$channels
in anoklab
space. -
If
components
is null, return a plain CSS function string with the name"lab"
and the argument$channels
. -
Let
channels
be the first element andalpha
the second element ofcomponents
. -
Let
lightness
,a
, andb
be the three elements ofchannels
. -
Return a color in the
oklab
known color space, with the givenlightness
,a
, andb
channels, andalpha
value.
-
oklch()
¶
-
oklch($channels)
-
Let
components
be the result of parsing$channels
in anoklch
space. -
If
components
is null, return a plain CSS function string with the name"lab"
and the argument$channels
. -
Let
channels
be the first element andalpha
the second element ofcomponents
. -
Let
lightness
,chroma
, andhue
be the three elements ofchannels
. -
Return a color in the
oklch
known color space, with the givenlightness
,chroma
, andhue
channels, andalpha
value.
-
color()
¶
-
color($description)
-
Let
components
be the result of parsing$description
without a space. -
If
components
is null, return a plain CSS function string with the name"color"
and the argument$description
. -
Let
color
be the first element andalpha
the second element ofcomponents
. -
Let
space
be the first element andchannels
the second element ofcolor
. -
Return a color in
space
, with the givenchannels
andalpha
value.
-
Modified Global Functions ¶
Any legacy global functions that are not explicitly updated here should continue to behave as alias functions for their appropriately updated counterparts.
Note that the new logic preserves decimal values in color channels, as well as preserving the initial color-space used in defining a color.
rgb()
and rgba()
¶
The rgba()
function is identical to rgb()
, except that if it would return a
plain CSS function named "rgb"
that function is named "rgba"
instead.
-
rgb($red, $green, $blue, $alpha: 1)
-
If any argument is a [special number], return a plain CSS function string with the name
"rgb"
and the arguments$red
,$green
,$blue
, and$alpha
. -
If
$alpha
is not a number, throw an error. -
Let
alpha
be the result of percent-convertingalpha
with a max of 1, and then clamping the value between 0 and 1, inclusive. -
Let
red
,green
, andblue
be the three elements returned by normalizing($red, $green, $blue)
inrgb
color space. -
Return a legacy color in the
rgb
space, with the givenred
,green
, andblue
channels, andalpha
value.
-
-
rgb($red, $green, $blue)
-
If any argument is a [special number], return a plain CSS function string with the name
"rgb"
and the arguments$red
,$green
, and$blue
. -
Otherwise, return the result of calling
rgb($red, $green, $blue, 1)
.
-
-
rgb($channels)
-
Let
components
be the result of parsing$channels
with anrgb
space. -
If
components
is null, return a plain CSS function string with the name"rgb"
and the argument$channels
. -
Let
channels
be the first element andalpha
the second element ofcomponents
. -
Let
red
,green
, andblue
be the three elements ofchannels
. -
Return the result of calling
rgb(red, green, blue, alpha)
.
-
-
rgb($color, $alpha)
-
If either argument is a special variable string, return a plain CSS function string with the name
"rgb"
and the same arguments. -
If
$color
is not a legacy color, throw an error. -
Return the result of calling
rgb()
with$color
’s red, green, and blue channels as unitless number arguments, and$alpha
as the final argument.
-
hsl()
and hsla()
¶
The hsla()
function is identical to hsl()
, except that if it would return a
plain CSS function named "hsl"
that function is named "hsla"
instead.
-
hsl($hue, $saturation, $lightness, $alpha: 1)
-
If any argument is a [special number], return a plain CSS function string with the name
"hsl"
and the arguments$hue
,$saturation
,$lightness
, and$alpha
. -
If
$alpha
is not a number, throw an error. -
Let
alpha
be the result of percent-convertingalpha
with a max of 1, and then clamping the value between 0 and 1, inclusive. -
Let
hue
,saturation
, andlightness
be the three elements returned by normalizing($hue, $saturation, $lightness)
inhsl
color space.
Clamping and conversion to rgb have been removed.
- Return a legacy color in the
hsl
space, with the givenhue
,saturation
, andlightness
channels, andalpha
value.
-
-
hsl($hue, $saturation, $lightness)
-
If any argument is a [special number], return a plain CSS function string with the name
"hsl"
and the arguments$hue
,$saturation
, and$lightness
. -
Otherwise, return the result of calling
hsl($hue, $saturation, $lightness, 1)
.
-
-
hsl($hue, $saturation)
-
If either argument is a special variable string, return a plain CSS function string with the name
"hsl"
and the same arguments. -
Otherwise, throw an error.
-
-
hsl($channels)
-
Let
components
be the result of parsing$channels
with anhsl
space. -
If
components
is null, return a plain CSS function string with the name"hsl"
and the argument$channels
. -
Let
channels
be the first element andalpha
the second element ofcomponents
. -
Let
hue
,saturation
, andlightness
be the three elements ofchannels
. -
Return a legacy color in the
hsl
space, with the givenhue
,saturation
, andlightness
channels, andalpha
value.
-