Skip to content

Commit b1d09ed

Browse files
committed
css-color-parser: fix normalization of hue to [0, 360] range when hue is a negative number
1 parent 8763337 commit b1d09ed

5 files changed

Lines changed: 73 additions & 1 deletion

File tree

packages/css-color-parser/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# Changes to CSS Color Parser
22

3+
### Unreleased (patch)
4+
5+
- Fix normalization of `hue` to `[0, 360]` range when `hue` is a negative number
6+
37
### 4.1.5
48

59
_June 14, 2026_

packages/css-color-parser/dist/index.mjs

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

packages/css-color-parser/src/functions/hue-normalize-channel-value.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,12 @@ import { toLowerCaseAZ } from '../util/to-lower-case-a-z';
55
export function normalizeHue(token: CSSToken): TokenNumber | false {
66
if (isTokenNumber(token)) {
77
token[4].value = token[4].value % 360;
8+
if (token[4].value < 0) {
9+
token[4].value += 360;
10+
}
11+
812
token[1] = token[4].value.toString();
13+
914
return token;
1015
}
1116

@@ -34,6 +39,9 @@ export function normalizeHue(token: CSSToken): TokenNumber | false {
3439
}
3540

3641
value = value % 360;
42+
if (value < 0) {
43+
value += 360;
44+
}
3745

3846
return [
3947
TokenType.Number,

packages/css-color-parser/test/basic/color-mix-function.mjs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,3 +276,33 @@ assert.deepStrictEqual(
276276
syntaxFlags: new Set(['color-mix']),
277277
},
278278
);
279+
280+
assert.deepStrictEqual(
281+
color(parse('color-mix(in lch, lch(none none none), lch(none none none))')),
282+
{
283+
colorNotation: 'lch',
284+
channels: [Number.NaN, Number.NaN, Number.NaN],
285+
alpha: 1,
286+
syntaxFlags: new Set(['color-mix']),
287+
},
288+
);
289+
290+
assert.deepStrictEqual(
291+
color(parse('color-mix(in lch decreasing hue, lch(50% 50% -40deg), lch(50% 50% 40deg))')),
292+
{
293+
colorNotation: 'lch',
294+
channels: [50, 75, 180],
295+
alpha: 1,
296+
syntaxFlags: new Set(['color-mix']),
297+
},
298+
);
299+
300+
assert.deepStrictEqual(
301+
color(parse('color-mix(in lch decreasing hue, lch(50% 50% 320deg), lch(50% 50% 40deg))')),
302+
{
303+
colorNotation: 'lch',
304+
channels: [50, 75, 180],
305+
alpha: 1,
306+
syntaxFlags: new Set(['color-mix']),
307+
},
308+
);

packages/css-color-parser/test/basic/relative-color.mjs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,36 @@ assert.deepStrictEqual(
134134
},
135135
);
136136

137+
assert.deepStrictEqual(
138+
color(parse('oklch(-2 -3 -400 / -500)')),
139+
{
140+
colorNotation: 'oklch',
141+
channels: [0, 0, 320],
142+
alpha: 0,
143+
syntaxFlags: new Set(['has-number-values', 'has-alpha']),
144+
},
145+
);
146+
147+
assert.deepStrictEqual(
148+
color(parse('oklch(from oklch(0.7 0.45 30 / 40%) -2 -3 -400 / -500)')),
149+
{
150+
colorNotation: 'oklch',
151+
channels: [0, 0, 320],
152+
alpha: 0,
153+
syntaxFlags: new Set(['relative-color-syntax', 'has-number-values', 'has-alpha']),
154+
},
155+
);
156+
157+
assert.deepStrictEqual(
158+
color(parse('oklch(from oklch(0.7 0.45 30 / 40%) -2 -3 -760 / -500)')),
159+
{
160+
colorNotation: 'oklch',
161+
channels: [0, 0, 320],
162+
alpha: 0,
163+
syntaxFlags: new Set(['relative-color-syntax', 'has-number-values', 'has-alpha']),
164+
},
165+
);
166+
137167
[
138168
['color(from color(srgb 0 1 0) srgb r g b)', 'rgb(0, 255, 0)'],
139169
['color(from color(srgb-linear 0 1 0) srgb r g b)', 'rgb(0, 255, 0)'],

0 commit comments

Comments
 (0)