Skip to content

Commit 6ef5c1a

Browse files
committed
Implement hsl / hsla.
1 parent 3224bde commit 6ef5c1a

File tree

2 files changed

+41
-8
lines changed

2 files changed

+41
-8
lines changed

README

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,14 @@ JavaScript parser for CSS color strings.
1414
null
1515
> parseCSSColor('ffffff');
1616
null
17+
> parseCSSColor('hsla(900, 15%, 90%, 0.5)')
18+
[ 226, 233, 233, 0.5 ]
19+
> parseCSSColor('hsla(900, 15%, 90%)')
20+
null
21+
> parseCSSColor('hsl(900, 15%, 90%)')
22+
[ 226, 233, 233, 1 ]
23+
> parseCSSColor('hsl(900, 0.15, 90%)') // NOTE: not spec compliant.
24+
[ 226, 233, 233, 1 ]
1725

1826

1927
(c) Dean McNamee <dean@gmail.com>, 2012.

csscolorparser.js

Lines changed: 33 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ var kCSSColorTable = {
9898
"yellow": [255,255,0,1], "yellowgreen": [154,205,50,1]}
9999

100100
function clamp_css_byte(i) { // Clamp to integer 0 .. 255.
101-
i = i >> 0;
101+
i = Math.round(i); // Seems to be what Chrome does (vs truncation).
102102
return i < 0 ? 0 : i > 255 ? 255 : i;
103103
}
104104

@@ -118,6 +118,16 @@ function parse_css_float(str) { // float or percentage.
118118
return clamp_css_float(parseFloat(str));
119119
}
120120

121+
function css_hue_to_rgb(m1, m2, h) {
122+
if (h < 0) h += 1;
123+
else if (h > 1) h -= 1;
124+
125+
if (h * 6 < 1) return m1 + (m2 - m1) * h * 6;
126+
if (h * 2 < 1) return m2;
127+
if (h * 3 < 2) return m1 + (m2 - m1) * (2/3 - h) * 6;
128+
return m1;
129+
}
130+
121131
function parseCSSColor(css_str) {
122132
// Remove all whitespace, not compliant, but should just be more accepting.
123133
var str = css_str.replace(/ /g, '').toLowerCase();
@@ -150,20 +160,35 @@ function parseCSSColor(css_str) {
150160
if (op !== -1 && ep + 1 === str.length) {
151161
var fname = str.substr(0, op);
152162
var params = str.substr(op+1, ep-(op+1)).split(',');
163+
var alpha = 1; // To allow case fallthrough.
153164
switch (fname) {
165+
case 'rgba':
166+
if (params.length !== 4) return null;
167+
alpha = parse_css_float(params.pop());
168+
// Fall through.
154169
case 'rgb':
155170
if (params.length !== 3) return null;
156171
return [parse_css_int(params[0]),
157172
parse_css_int(params[1]),
158173
parse_css_int(params[2]),
159-
1];
160-
case 'rgba':
174+
alpha];
175+
case 'hsla':
161176
if (params.length !== 4) return null;
162-
return [parse_css_int(params[0]),
163-
parse_css_int(params[1]),
164-
parse_css_int(params[2]),
165-
parse_css_float(params[3])];
166-
// TODO(deanm): HSL / HSV.
177+
alpha = parse_css_float(params.pop());
178+
// Fall through.
179+
case 'hsl':
180+
if (params.length !== 3) return null;
181+
var h = (((parseFloat(params[0]) % 360) + 360) % 360) / 360; // 0 .. 1
182+
// NOTE(deanm): According to the CSS spec s/l should only be
183+
// percentages, but we don't bother and let float or percentage.
184+
var s = parse_css_float(params[1]);
185+
var l = parse_css_float(params[2]);
186+
var m2 = l <= 0.5 ? l * (s + 1) : l + s - l * s;
187+
var m1 = l * 2 - m2;
188+
return [clamp_css_byte(css_hue_to_rgb(m1, m2, h+1/3) * 255),
189+
clamp_css_byte(css_hue_to_rgb(m1, m2, h) * 255),
190+
clamp_css_byte(css_hue_to_rgb(m1, m2, h-1/3) * 255),
191+
alpha];
167192
default:
168193
return null;
169194
}

0 commit comments

Comments
 (0)