You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[css-color-5] When mixing hue, there are two ways round the hue range #4735
Mixing hue in lch() leads to ambiguity (or undesirable results) because hue is an angle around the circle, so there are two paths between any two values. In some cases, authors may want a hue mix that traverses the 0deg/360deg point, at other times not.
I have been wondering about that myself. Maybe an extra parameter with two values, to go 'the long way round' or 'the short way round' with shorter path being the default if unspecified? It would also need tie logic, so that both paths are available when the path is exactly 180deg.
Once the spec is fixed to not mod the angle eagerly, the consistent answer is to just do a linear interpolation from the start to the end angle. If you want a particular direction, you can specify the angles to cause that direction, just like you do with 'rotate'.
the consistent answer is to just do a linear interpolation from the start to the end angle
The big problem is that many authors are going to want to set gradient stops or color mix endpoints either (a) from coordinates provided by a graphical tool, (b) in a different coordinate system [mixing in polar-coordinate CIELAB (L*, C*, h*) space is apparently the default irrespective of the space in which a color is specified], or (c) from a specific named color not specified adjacent to the usage in a gradient/color mix.
When this happens for e.g. a red and a purple, the gradient should go the short way through red–purple, but from what I can tell according to this proposal will instead go all the way around via orange→yellow→green→blue.
This is going to be very confusing for authors, and difficult or even impossible for them to fix in a straightforward way.
For creators of graphical tools for creating gradients or color mixtures, outputting to css, this is going to create some sticky edge cases which are difficult to work around. The hue angle specified for each color will need to be adjusted by an arbitrary multiple of 360° based on the specified angle of the previous color.
If trying to make a collection of color mixes between several different colors, each original color may need to be specified multiple times for different numbers of turns around the circle, so that mixtures with others end up behaving as expected.
You've mentioned authors using "a graphical tool" consistently in your case for using the shortest path between the angles. Presumably this tool could also convert a gradient from 340° to 20° into -20° to 20° in the generated CSS.
There are 2 cases: (1) an author uses a graphical tool to obtain coordinates, and then copy/pastes those coordinates into a document. That puts the burden of figuring out what multiple of 360° to get the desired behavior onto the end user; (2) the graphical tool generates a whole gradient or color mix or whatever, and outputs CSS. In that case you are complicating the tool programmer’s job and making it more likely that their tools will have undesired behavior.
For e.g. a gradient, the tool is going to need to keep track of the turning number of every gradient stop, and potentially change every one in response to any change to the gradient. What would previously be a local update to 1 value becomes a fiddly global update.
Once the spec is fixed to not mod the angle eagerly, the consistent answer is to just do a linear interpolation from the start to the end angle. If you want a particular direction, you can specify the angles to cause that direction, just like you do with 'rotate'
Suppose I have
--start: lch(52% 58.1 22.7)
--end: lch(56% 49.1 257.1)
// currently, this goes the long way around
color-mix(var(--start) var(--end) hue(75.23%));
// 22.7 * 0.7523 + 257.1 * 0.2477 = 80.76
// mixed result is lch(52% 58.1 80.76)
You seem to be saying that going the other way round I would need to inspect the values of the two custom properties and if needed, add or subtract 360 to make it do what I want.
--otherend: lch(56% 49.1 -102.9)
// now it goes the short way around
color-mix(var(--start) var(--otherend) hue(75.23%));
// 22.7 * 0.7523 + -102.9 * ( 1 - 0.7523 ) = -8.41112
// mixed result is lch(52% 58.1 -8.41112)
while what I am suggesting does not require making adjusted copies of custom properties:
// this would go the short way around
color-mix(var(--start) var(--end) hue(75.23% short));
// this would go the long way around
color-mix(var(--start) var(--end) hue(75.23% long));
// new default if unspecified, go the short way around
color-mix(var(--start) var(--end) hue(75.23%));
Also, doing calculations in LCH does not mean that the colors being mixed were originally specified in LCH. So tweaking the angle by adding or subtracting 360 is not even an option in those cases.
Consider mixing a hex color (thus, sRGB) with a color in prophoto-rgb:
The two input colors are auto-converted to LCH and then mixed. Relying on the user tweaking hue angle implies always requiring the user to first convert the colors to LCH.
Just doing a linear interpolation is simpler and more consistent with how all other values in CSS transition, and gives authors that are hand-authoring the values simple, straightforward control over how their transition proceeds. It does mean that authors doing generic work on custom property values don't have insight into how it'll work (tho the users of the component in question can always hand-tweak their values to get the desired result), and yes, when your endpoints aren't in a cylindrical space you don't have any control.
Doing a "shortest-path" interpolation is a break from that: it might be more commonly what's desired, but it means we have to make an arbitrary decision for 180deg separation, and we have to add further controls to let the author opt into the other modes when that's desired (at least four settings, as {longest path, shortest path}×{CW when 180deg, CCW when 180deg} are all possible).
After reading Chris's posts, I'm going to change my opinion. Under any other circumstances I'm very strongly for normal linear interpolation like we do everywhere else, but for color-mix, I think you have to take the shortest route.
The critical difference is that colors are likely being mixed in a different space to the one they're specified - even if both colors are specified in the same space. So the user has no real control over the components being mixed.
I expect the vast, vast majority of people using this will be doing so in RGB, and most of them won't have even heard of Lch. If someone tries to mix from green to yellow and find it goes "the long way round", it's going to seem wrong and won't be obvious how to solve it.
One solution is to explain the Lch colorwheel and give them a flag to set; another is for them to specify both colors in Lch. Neither is good.
I think the principle of least surprise requires color-mix to interpolate in the shortest direction, certainly when either color is not specified in Lch. Myself, I think the 180° decision should be arbitrary and fixed (e.g. to clockwise).
If both colors are Lch to start with, you could go either way - shortest path for consistency, normal interpolation for full control. I lean towards the latter, as it means for most people in most colorspaces it will do the right thing, and those that really care about the details can specify their colors in Lch.
with the default, if omitted, being 'shorter' and the direction, if the hue difference is exactly 180deg, being 'clockwise'. So you get what you want most of the time, and you can get exactly what you want by being specific.
shorter and longer still have the problem that they're ambiguous if the difference is 180deg; we'd either have to make an arbitrary choice or make the grammar [shorter | longer] || [clockwise | anticlockwise].
The CSS Working Group just discussed [css-color-5] When mixing hue, there are two ways round the hue range, and agreed to the following:
RESOLVED: Publish a version with all keywords but longer
The full IRC log of that discussion
<dael> Topic: [css-color-5] When mixing hue, there are two ways round the hue range
<dael> github: https://github.com//issues/4735
<dael> leaverou: When interpolate between hues usually you don't want interpolate in same way. If going between hue 0 and hue 400 you don't want a whole rainbow
<dael> leaverou: What we put in spec is by dfault use shortest arc which does expected in common. Have keywords for longest arc etc and also as-specified keyword to allow raw interp
<dael> leaverou: Wasn't sure if all needed. Esp specified one. If impl want to store value as normalized keyword doesn't allow
<dael> leaverou: I put algo in spec which tweaked by dbaron. Good to get sanity check.
<smfr> https://drafts.csswg.org/css-color-5/#hue-interpolation
<Rossen_> q?
<dael> fantasai: Can you summerize the proposal?
<dael> leaverou: Do we need all 5 keywords?
<dael> leaverou: We need shorter b/c that's what you expect in most cases. Do we need specified which is interp as specified so if you go between 0 and 720 2 rainbows. Need increasing, decreasing, longest or is that completist
<dael> fantasai: Are there use cases? We can add keywords. If there's not a use case might want to note possibility for future reference in case we need to add later. If not a use case don't need to add.
<dael> fantasai: I think it's usefult o think of all and makes sure keywords are a set that make sense even if we only include 1 or 2 in spec
<dael> dbaron: Intent is these would eventually apply to all gradients, animations, and color mix funct or only some?
<dael> leaverou: Good to design with that in mind. Not sure how text for animation snad gradients but if we have a syntax making sense it would be good to have the option
<miriam> q+
<astearns> for gradients and animations the workaround would be to add more steps/stops to mimic the non-short behavior?
<dael> fantasai: My suggestion is draft all in spec, put an issue in saying we're not sure if we need all and we might limit to a subset with the subset that makes sense to you and also note might expand to gradients. Encourage people to think what that would look like
<tantek> +1 to publishing at least one draft with more keywords to get the ideas published
<dael> fantasai: Early stage WD so makes sense to put ideas and poke at them with people like Una to make cases
<leaverou> http://localhost:8002/csswg-drafts/css-color-5/Overview.html#hue-interpolation
<leaverou> https://drafts.csswg.org/css-color-5/#hue-interpolation
<dael> leaverou: Does math make sense? This is the section ^
<florian> q+
<Rossen_> ack miriam
<dael> miriam: THinking of specified I'd have use cases when comes to gradient. As pointed out in chat that could be do with extra stops.
<dael> miriam: Can't think of cases when mixing colors. I don't know if that's separate but might be. Math makes sense. Shorter and longer fall apart at 180 which maybe implies need to determine direction without them
<Rossen_> ack florian
<dael> florian: I haven't reviewed math for correctnss, but intuitive seems right. Longer seems least useful. Wanting longer for being longer seems odd. Might pick if gives right thing.
<miriam> +1 to longer being less useful than increase/decrease
<dael> florian: Approach about putting in spec now with note for use cases sounds good
<dael> dbaron: On math have a PR to tweak. I think set notation doesn't match pseudo code and I think pseudo code is right. I have some weaks for 180 case but it's not clear that's what we want
<dael> leaverou: 180 chris said we can pick one as long as it's well defined. Doesn't matter increasing or decreasing
<dael> florian: Makes sense. If you have a preference you can say it.
<dael> fantasai: We use 'closest' in radial gradients so maybe that instead of 'shorter'?
<dael> leaverou: Than what longer?
<dael> fantasai: 'father'?
<dael> florian: I don't think longer is needed so I don't mind not having a good replacement
<fantasai> s/father/farthest/
<tantek> near and far, close and distant, short and long ?
<dael> fantasai: We have farthest and closest side
<dael> leaverou: That's differ than angles
<dael> Rossen_: Apart from bikeshedding I hear 2 proposals. 1) let's push a version of the spec with all the keywords initially or as many as we want so we encourage more incubation.
<dael> Rossen_: 2) I hear agreement that longer doesn't seem useful. I didn't hear a use case to prove otherwise.
<dael> Rossen_: I don't want to bikeshed.
<dael> Rossen_: SHould we resolve to keep the keywords becides longer and publish?
<dael> leaverou: I'd rather hear from Una and Adam before we resolve.
<dael> fantasai: This isn't final. We're drafting for dicussion to encourage participation. I think it's fine to put it all in the draft, explain the thoughts, and enougage feedback. We can publish often
<dael> Rossen_: Objections to Publish a version with all keywords but longer?
<fantasai> "Publish early, publish often"
<tantek> +1
<dael> RESOLVED: Publish a version with all keywords but longer
I'd like to experiment with adding these five hue interpolation types to my library, and I wondered — at the hue fixup step, should we also do something about grays, which in LCh have c: 0 and h: 0? The hue value is misleading here, in the absence of a chroma.
In the case of mixing two colors, the achromatic one can inherit the hue from the other color, if it has chroma. But if we were to extend hue interpolation to gradients, which accept more than one color stop, how should hues for achromatic colors be handled?
I've added an interactive visualization of the various hue fixup methods, and changed the fixup algorithms to work with any number of hues. Here are the formulas I use currently; they need to be tested more thoroughly, but at first blush they seem correct.
In the case of longer, repeated equal values produce a zero-width interval, to remain consistent with the other methods, but that only works in some cases:
Edit: To get it to work consistently, I ended up converting the list of hues from absolutes to relative values (deltas), apply the fixup rules, then convert back to absolutes.
does that mean that hsl(), lch() etc. will not normalize their hue to the interval [0, 360)
Correct. Normalization happens as a first stage of interpolation. The specified value of an hsl()color is as specified, including angles outside [0,360). The computed value is rgb().
I thought that the specification was clear about hue angles outside the range [0, 360) but it isn't.
The third argument is the hue angle. It’s interpreted similarly to the argument of hsl(), but doesn’t map hues to angles in the same way because they are evenly spaced perceptually. Instead, 0deg points along the positive "a" axis (toward purplish red), (as does 360deg, 720deg, etc.); 90deg points along the positive "b" axis (toward mustard yellow), 180deg points along the negative "a" axis (toward greenish cyan), and 270deg points along the negative "b" axis (toward sky blue).
In HSL (and HWB) the angle 0deg represents sRGB primary red (as does 360deg, 720deg, etc.), and the rest of the hues are spread around the circle, so 120deg represents sRGB primary green, 240deg represents sRGB primary blue, etc.
Activity
svgeesus commentedon Feb 4, 2020
I have been wondering about that myself. Maybe an extra parameter with two values, to go 'the long way round' or 'the short way round' with shorter path being the default if unspecified? It would also need tie logic, so that both paths are available when the path is exactly 180deg.
jrus commentedon Feb 5, 2020
Unless explicitly specified, this should always be the shortest arc.
tabatkins commentedon Feb 6, 2020
Once the spec is fixed to not mod the angle eagerly, the consistent answer is to just do a linear interpolation from the start to the end angle. If you want a particular direction, you can specify the angles to cause that direction, just like you do with 'rotate'.
jrus commentedon Feb 8, 2020
The big problem is that many authors are going to want to set gradient stops or color mix endpoints either (a) from coordinates provided by a graphical tool, (b) in a different coordinate system [mixing in polar-coordinate CIELAB (L*, C*, h*) space is apparently the default irrespective of the space in which a color is specified], or (c) from a specific named color not specified adjacent to the usage in a gradient/color mix.
When this happens for e.g. a red and a purple, the gradient should go the short way through red–purple, but from what I can tell according to this proposal will instead go all the way around via orange→yellow→green→blue.
This is going to be very confusing for authors, and difficult or even impossible for them to fix in a straightforward way.
For creators of graphical tools for creating gradients or color mixtures, outputting to css, this is going to create some sticky edge cases which are difficult to work around. The hue angle specified for each color will need to be adjusted by an arbitrary multiple of 360° based on the specified angle of the previous color.
If trying to make a collection of color mixes between several different colors, each original color may need to be specified multiple times for different numbers of turns around the circle, so that mixtures with others end up behaving as expected.
faceless2 commentedon Feb 9, 2020
You've mentioned authors using "a graphical tool" consistently in your case for using the shortest path between the angles. Presumably this tool could also convert a gradient from 340° to 20° into -20° to 20° in the generated CSS.
jrus commentedon Feb 9, 2020
There are 2 cases: (1) an author uses a graphical tool to obtain coordinates, and then copy/pastes those coordinates into a document. That puts the burden of figuring out what multiple of 360° to get the desired behavior onto the end user; (2) the graphical tool generates a whole gradient or color mix or whatever, and outputs CSS. In that case you are complicating the tool programmer’s job and making it more likely that their tools will have undesired behavior.
For e.g. a gradient, the tool is going to need to keep track of the turning number of every gradient stop, and potentially change every one in response to any change to the gradient. What would previously be a local update to 1 value becomes a fiddly global update.
svgeesus commentedon Mar 11, 2020
@tab wrote:
Suppose I have
You seem to be saying that going the other way round I would need to inspect the values of the two custom properties and if needed, add or subtract 360 to make it do what I want.
while what I am suggesting does not require making adjusted copies of custom properties:
svgeesus commentedon Mar 11, 2020
Also, doing calculations in LCH does not mean that the colors being mixed were originally specified in LCH. So tweaking the angle by adding or subtracting 360 is not even an option in those cases.
Consider mixing a hex color (thus, sRGB) with a color in prophoto-rgb:
The two input colors are auto-converted to LCH and then mixed. Relying on the user tweaking hue angle implies always requiring the user to first convert the colors to LCH.
tabatkins commentedon Mar 11, 2020
Yeah, there's tradeoffs.
Just doing a linear interpolation is simpler and more consistent with how all other values in CSS transition, and gives authors that are hand-authoring the values simple, straightforward control over how their transition proceeds. It does mean that authors doing generic work on custom property values don't have insight into how it'll work (tho the users of the component in question can always hand-tweak their values to get the desired result), and yes, when your endpoints aren't in a cylindrical space you don't have any control.
Doing a "shortest-path" interpolation is a break from that: it might be more commonly what's desired, but it means we have to make an arbitrary decision for 180deg separation, and we have to add further controls to let the author opt into the other modes when that's desired (at least four settings, as {longest path, shortest path}×{CW when 180deg, CCW when 180deg} are all possible).
faceless2 commentedon Mar 12, 2020
After reading Chris's posts, I'm going to change my opinion. Under any other circumstances I'm very strongly for normal linear interpolation like we do everywhere else, but for
color-mix, I think you have to take the shortest route.The critical difference is that colors are likely being mixed in a different space to the one they're specified - even if both colors are specified in the same space. So the user has no real control over the components being mixed.
I expect the vast, vast majority of people using this will be doing so in RGB, and most of them won't have even heard of Lch. If someone tries to mix from green to yellow and find it goes "the long way round", it's going to seem wrong and won't be obvious how to solve it.
One solution is to explain the Lch colorwheel and give them a flag to set; another is for them to specify both colors in Lch. Neither is good.
I think the principle of least surprise requires
color-mixto interpolate in the shortest direction, certainly when either color is not specified in Lch. Myself, I think the 180° decision should be arbitrary and fixed (e.g. to clockwise).If both colors are Lch to start with, you could go either way - shortest path for consistency, normal interpolation for full control. I lean towards the latter, as it means for most people in most colorspaces it will do the right thing, and those that really care about the details can specify their colors in Lch.
svgeesus commentedon Mar 24, 2020
So I'm thinking of an optional second argument to the hue adjuster. Instead of
it will be
with the default, if omitted, being 'shorter' and the direction, if the hue difference is exactly 180deg, being 'clockwise'. So you get what you want most of the time, and you can get exactly what you want by being specific.
tabatkins commentedon Mar 25, 2020
shorterandlongerstill have the problem that they're ambiguous if the difference is 180deg; we'd either have to make an arbitrary choice or make the grammar[shorter | longer] || [clockwise | anticlockwise].svgeesus commentedon Mar 26, 2020
@tabatkins wrote:
which is why I wrote, earlier:
24 remaining items
css-meeting-bot commentedon Jul 1, 2020
The CSS Working Group just discussed
[css-color-5] When mixing hue, there are two ways round the hue range, and agreed to the following:RESOLVED: Publish a version with all keywords but longerThe full IRC log of that discussion
<dael> Topic: [css-color-5] When mixing hue, there are two ways round the hue range<dael> github: https://github.com//issues/4735
<dael> leaverou: When interpolate between hues usually you don't want interpolate in same way. If going between hue 0 and hue 400 you don't want a whole rainbow
<dael> leaverou: What we put in spec is by dfault use shortest arc which does expected in common. Have keywords for longest arc etc and also as-specified keyword to allow raw interp
<dael> leaverou: Wasn't sure if all needed. Esp specified one. If impl want to store value as normalized keyword doesn't allow
<dael> leaverou: I put algo in spec which tweaked by dbaron. Good to get sanity check.
<smfr> https://drafts.csswg.org/css-color-5/#hue-interpolation
<Rossen_> q?
<dael> fantasai: Can you summerize the proposal?
<dael> leaverou: Do we need all 5 keywords?
<dael> leaverou: We need shorter b/c that's what you expect in most cases. Do we need specified which is interp as specified so if you go between 0 and 720 2 rainbows. Need increasing, decreasing, longest or is that completist
<dael> fantasai: Are there use cases? We can add keywords. If there's not a use case might want to note possibility for future reference in case we need to add later. If not a use case don't need to add.
<dael> fantasai: I think it's usefult o think of all and makes sure keywords are a set that make sense even if we only include 1 or 2 in spec
<dael> dbaron: Intent is these would eventually apply to all gradients, animations, and color mix funct or only some?
<dael> leaverou: Good to design with that in mind. Not sure how text for animation snad gradients but if we have a syntax making sense it would be good to have the option
<miriam> q+
<astearns> for gradients and animations the workaround would be to add more steps/stops to mimic the non-short behavior?
<dael> fantasai: My suggestion is draft all in spec, put an issue in saying we're not sure if we need all and we might limit to a subset with the subset that makes sense to you and also note might expand to gradients. Encourage people to think what that would look like
<tantek> +1 to publishing at least one draft with more keywords to get the ideas published
<dael> fantasai: Early stage WD so makes sense to put ideas and poke at them with people like Una to make cases
<leaverou> http://localhost:8002/csswg-drafts/css-color-5/Overview.html#hue-interpolation
<leaverou> https://drafts.csswg.org/css-color-5/#hue-interpolation
<dael> leaverou: Does math make sense? This is the section ^
<florian> q+
<Rossen_> ack miriam
<dael> miriam: THinking of specified I'd have use cases when comes to gradient. As pointed out in chat that could be do with extra stops.
<dael> miriam: Can't think of cases when mixing colors. I don't know if that's separate but might be. Math makes sense. Shorter and longer fall apart at 180 which maybe implies need to determine direction without them
<Rossen_> ack florian
<dael> florian: I haven't reviewed math for correctnss, but intuitive seems right. Longer seems least useful. Wanting longer for being longer seems odd. Might pick if gives right thing.
<miriam> +1 to longer being less useful than increase/decrease
<dael> florian: Approach about putting in spec now with note for use cases sounds good
<dael> dbaron: On math have a PR to tweak. I think set notation doesn't match pseudo code and I think pseudo code is right. I have some weaks for 180 case but it's not clear that's what we want
<dael> leaverou: 180 chris said we can pick one as long as it's well defined. Doesn't matter increasing or decreasing
<dael> florian: Makes sense. If you have a preference you can say it.
<dael> fantasai: We use 'closest' in radial gradients so maybe that instead of 'shorter'?
<dael> leaverou: Than what longer?
<dael> fantasai: 'father'?
<dael> florian: I don't think longer is needed so I don't mind not having a good replacement
<fantasai> s/father/farthest/
<tantek> near and far, close and distant, short and long ?
<dael> fantasai: We have farthest and closest side
<dael> leaverou: That's differ than angles
<dael> Rossen_: Apart from bikeshedding I hear 2 proposals. 1) let's push a version of the spec with all the keywords initially or as many as we want so we encourage more incubation.
<dael> Rossen_: 2) I hear agreement that longer doesn't seem useful. I didn't hear a use case to prove otherwise.
<dael> Rossen_: I don't want to bikeshed.
<dael> Rossen_: SHould we resolve to keep the keywords becides longer and publish?
<dael> leaverou: I'd rather hear from Una and Adam before we resolve.
<dael> fantasai: This isn't final. We're drafting for dicussion to encourage participation. I think it's fine to put it all in the draft, explain the thoughts, and enougage feedback. We can publish often
<dael> Rossen_: Objections to Publish a version with all keywords but longer?
<fantasai> "Publish early, publish often"
<tantek> +1
<dael> RESOLVED: Publish a version with all keywords but longer
danburzo commentedon Jul 5, 2020
I'd like to experiment with adding these five hue interpolation types to my library, and I wondered — at the hue fixup step, should we also do something about grays, which in LCh have
c: 0andh: 0? The hue value is misleading here, in the absence of a chroma.In the case of mixing two colors, the achromatic one can inherit the hue from the other color, if it has chroma. But if we were to extend hue interpolation to gradients, which accept more than one color stop, how should hues for achromatic colors be handled?
Edit: Oops, found a separate discussion in #4928
danburzo commentedon Jul 5, 2020
I've added an interactive visualization of the various hue fixup methods, and changed the fixup algorithms to work with any number of hues. Here are the formulas I use currently; they need to be tested more thoroughly, but at first blush they seem correct.
In the case of
longer, repeated equal values produce a zero-width interval, to remain consistent with the other methods, but that only works in some cases:Edit: To get it to work consistently, I ended up converting the list of hues from absolutes to relative values (deltas), apply the fixup rules, then convert back to absolutes.
danburzo commentedon Jul 6, 2020
Trying to find justifying use-cases for each of the fixup methods, a couple of questions came up:
specifiedto produce more than "one rainbow", does that mean thathsl(),lch()etc. will not normalize their hue to the interval[0, 360)?normalizedfixup method that just normalizes the hues? (likespecifiedbut with normalized hues)[css-color-5] Adjustments to edge cases and set notation for hue inte…
svgeesus commentedon Jan 30, 2021
Re-tagging to css color 4 because the color interpolation section moved.
svgeesus commentedon Feb 6, 2021
Correct. Normalization happens as a first stage of interpolation. The specified value of an
hsl()color is as specified, including angles outside [0,360). The computed value isrgb().I thought that the specification was clear about hue angles outside the range [0, 360) but it isn't.
The existence and validity of such angles is mentioned in passing for LCH:
and, again in passing, for HSL:
However the main section on the
<hue>type is entirely silent on this. It should be explicit.svgeesus commentedon Feb 6, 2021
The normalization range depends on the method though. So for
decreasing, it is: