Important

This slide deck was created for use in a controlled environment, during a talk. It works best with Firefox 28+ at 1280x720 or 1024x768 with enabled blending modes in about:config. It WILL NOT work properly in other browsers. The demos were live coded, so these slides are a bit pointless if you never watched the talk.

The Chroma Zone

Engineering color on the Web

By Lea Verou (@LeaVerou)

Picture of me
Hi, I’m Lea

I make stuff

More: lea.verou.me/projects

CSS WG Invited Expert

O’Reilly author (ETA Q4 2014)

MIT PhD
candidate

How colour works on screen

Apple iPad 2, 1024×768, 9.7″
Apple iPad Retina Display (2012), 2048×1536, 9.7″
Apple iPhone 4S, 960×640, 3.5″
ASUS Eee Pad Transformer Prime, 1280×800, 10.1″

Anti-aliasing

-webkit-font-smoothing: subpixel-antialiased;
-webkit-font-smoothing: antialiased; /* greyscale anti-aliasing */
-webkit-font-smoothing: none; /* NO anti-aliasing! */
-moz-osx-font-smoothing: grayscale;
-moz-osx-font-smoothing: auto; /* subpixel anti-aliasing */

Please, avoid.

No, really.

8 bits

= 28 states

8 bits

= 256 states

8 bits

= 0-255 range

= 24 bits per pixel

= 3 bytes per pixel
(in uncompressed images)

256³ possible colors

Colour & Code

Colours in HTML 3.2

#ff005a

= Red: 255
Green: 0
Blue: 90

So, 255 —> FF and 0 —> 00. What about 90? Hmmm… 90 = 5×16+10 —> 5A, so #FF005A!
— No one, ever

red lime blue aqua fuchsia yellow green maroon navy olive purple teal white silver gray black

HTML 3.2 colors

  • #rrggbb Confusing and cryptic >:(
  • Color names Mostly useless :'(

Colors in CSS 1 - 2.1

orange

CSS 1 - 2.1 colors

  • rgb() Better, but still confusing :/
  • #rgb Shorter, but still confusing :/
  • orange named color Are you kidding me?!

Colors in CSS Color Level 3

Simple JS “class” for RGB colors

function Color(rgba) {
	if (!(this instanceof Color)) return new Color(rgba);
	
	this.rgba = rgba || [0,0,0,1];
};

Color.prototype = {
	get rgb () { return this.rgba.slice(0,3) },
	set rgb(arr) {
		this.rgba = arr.concat(this.alpha);
	}
	
	get alpha () { return this.rgba[3] },
	set alpha (a) { this.rgba[3] = a }
}
var magenta = new Color([255, 0, 127, 1]);
var magenta = new Color();
magenta.rgb = [255, 0, 127];
// Example method
Color.prototype.invert = function () {
	this.rgb = this.rgb.map(function(c) {
		return 255 - c;
	});
};

Multiply

multiply: function(dest) {
	this.rgb = this.rgb.map(function(c,i) {
		return 255 * (this.rgb[i]/255) *
		             (dest.rgb[i]/255);
	});
}
var red = Color([255,0,0]),
    blue = Color([0,0,255]);
red.multiply(blue); // -> black
normal
multiply
screen
overlay
darken
lighten
color-dodge
color-burn
hard-light
soft-light
difference
exclusion
hue
saturation
color
luminosity
hsl(60, 100%, 50%) hsl(240, 100%, 50%)

A color space has

Perceptual uniformity

when the perceptual similarity of two colors
is measured by the distance between them.

RGB is not perceptually uniform.

Neither is HSL, as it’s just a transformation of RGB.

rgb(255, 128, 255) rgb(255, 0, 255) rgb(128, 0, 255)

Lightness != luminance

el.style.background = color;
el.style.color = color.lightness > 50?
                   'black' : 'white';
get lightness () {
	var max = Math.max.apply(Math, this.rgb),
	    min = Math.min.apply(Math, this.rgb);
		
	return Math.round((min + max)/2.55/2);
}

Relative luminance

get luminance () { // Formula from WCAG 2.0
	var rgb = this.rgb.map(function(c){
		c /= 255; // to 0-1 range
		return c < .03928 ? 
		         c / 12.92 : 
		         Math.pow((c+.055)/1.055, 2.4);
	});
	
	return 21.26 * rgb[0] + // red
	       71.52 * rgb[1] + // green
	        7.22 * rgb[2];  // blue
}
0%
vs
0%

Color contrast

Color.prototype.contrast = function(color) {
	var l1 = this.luminance;
	var l2 = color.luminance;
	var ret = (l1 + .05) / (l2 + .05);
	
	return ret < 1? 1 / ret : ret;
};

Named colors distribution

blanchedalmond cornflowerblue darkgoldenrod darkolivegreen lavenderblush lightgoldenrodyellow lightseagreen lightslategray lightsteelblue mediumaquamarine mediumseagreen mediumslateblue mediumspringgreen mediumturquoise mediumvioletred palegoldenrod paleturquoise palevioletred
blanchedalmond chartreuse cornflowerblue goldenrod dodgerblue gainsboro lemonchiffon linen moccasin oldlace olivedrab orchid
indianred navajowhite peru
gray darkgray

WTF?!

Some text

CSS Color Level 3 additions

  • hsl() Better, but not great :/
  • rgba() and hsla() Badly needed :)
  • MOAR Color names Mostly useless :'(
  • currentColor Cool, but limited :)

Colors in CSS Color Level 4

gray() with SASS

@function gray($l, $alpha: 1) {
  @return rgba($l, $l, $l, $alpha);
}

background: gray(50%); /* → #7f7f7f */
background: gray(255, .2); 
       /* → rgba(255, 255, 255, 0.2); */

HWB != HSB

hwb() with SASS

@function hwb($hue, $w, $b) {
	$base: hsl($hue, 100%, 50%);
  
	@return $base * (1 - ($w + $b)/100%)
	        + 255*$w/100%;
}

body {
  background: hwb(335, 20%, 20%); // #cc3372
}

hwb() with SASS

@function hwb($hue, $w, $b) {
	$base: hsl($hue, 100%, 50%);
  
 @if ($w + $b > 100%) {
	$factor: 100%/($w + $b);
	$w: $w * $factor;
	$b: $b * $factor;
}
  
	@return $base * (1 - ($w + $b)/100%)
	        + 255*$w/100%;
}

color() adjusters

red green blue alpha rgb
hue h
saturation s
lightness l
whiteness w blackness b
tint shade blend blenda contrast

tint & shade in SASS

@function tint($color, $amount) {
	@return mix(white, $color, $amount);
}
@function shade($color, $amount) {
	@return mix(black, $color, $amount);
}

background: tint(red, 10%); /* → #ff1919 */
background: shade(red, 10%); /* → #e50000 */

Note: tint() & shade() are already included in Bourbon

CSS Color Level 4 (Tentative!!)

  • gray()
  • #rgba and #rrggbbaa
  • hwb()
  • color()
  • named hues and <angle> in hsl()
  • rgb() and hsl() will accept alpha values

Other color spaces

CMY: Subtractive color

CMY: Theory and reality

Adding the Key in CMYK

Color gamut

ICC color profiles

Color difference (CIEDE2000)