Do we need more HTML colors?
I wrote a blog post about painting my fence. This got me thinking a lot about colors and how I use them as a web developer.
So I asked myself a question: What's the perceptual difference between two adjacent HTML colors?
There are 16,777,216 possible colors (256 x 256 x 256), since there are only 256 possible values for red, green, and blue. I've been using this Delta-E calculator to calculate the perceptual difference between colors:
I chose a random green/blue color (rgb(50,200,180
) and calculated some differences after adding/subtracting one from each color channel. Here are the results:
- 0.1192 = R:50,G:200,B:180 -> R:51,G:200,B:180
- 0.1168 = R:50,G:200,B:180 -> R:49,G:200,B:180
- 0.6929 = R:50,G:200,B:180 -> R:50,G:201,B:180
- 0.6943 = R:50,G:200,B:180 -> R:50,G:199,B:180
- 0.5714 = R:50,G:200,B:180 -> R:50,G:200,B:181
- 0.5711 = R:50,G:200,B:180 -> R:50,G:200,B:179
Subtracting one from the green channel seems to show the biggest perceptual difference.
Here's the difference when you subtract one from each color for pure white (rgb(255, 255, 255
):
- 0.3561 = R:255,G:255,B:255 -> R:254,G:255,B:255
- 0.667 = R:255,G:255,B:255 -> R:255,G:254,B:255
- 0.5079 = R:255,G:255,B:255 -> R:255,G:255,B:254
So the green channel shows the biggest difference for both addition and subtraction. The next largest difference is in the blue channel, and red makes a relatively small difference.
Here's the progression from rgb(255, 255, 255)
down to rgb(255, 232, 255)
You can see that it's very hard to tell the difference between any two colors that are right next to each other.
I thought of another question: What are the biggest and smallest perceptual differences between two adjacent HTML colors?
I decided to write a Ruby script to figure this out. I found this color_difference
Ruby gem that uses the CIEDE2000 Color-Difference formula.
Paper: https://hajim.rochester.edu/ece/sites/gsharma/ciede2000/ciede2000noteCRNA.pdf
require 'color_difference'
max_difference = nil
min_difference = nil
max_difference_colors = []
min_difference_colors = []
0.step(255, 1) do |r|
0.step(255, 1) do |g|
0.step(255, 1) do |b|
color = { r: r, g: g, b: b }
puts "Color: #{color.inspect}"
[1, -1].each do |diff|
%i(r g b).each do |channel|
new_color = color.dup
new_color[channel] += diff
new_color[channel] = [0, new_color[channel]].max
new_color[channel] = [255, new_color[channel]].min
next if new_color == color
difference = ColorDifference.cie2000(color, new_color)
if max_difference.nil? || difference > max_difference
max_difference = difference
max_difference_colors = [color, new_color]
end
if min_difference.nil? || difference < min_difference
min_difference = difference
min_difference_colors = [color, new_color]
end
end
end
end
end
end
def format_float(number)
sprintf('%.15f', number).sub(/0+$/, '').sub(/\.$/, '.0')
end
puts "Max difference: #{format_float max_difference}"
puts "Colors: #{max_difference_colors.inspect}"
puts "------------------------------------"
puts "Min difference: #{format_float min_difference}"
puts "Colors: #{min_difference_colors.inspect}"
Results:
Max difference: 0.012461248722627
Colors: [{:r=>24, :g=>23, :b=>23}, {:r=>24, :g=>24, :b=>23}]
------------------------------------
Min difference: 0.000064328231603
Colors: [{:r=>0, :g=>255, :b=>255}, {:r=>1, :g=>255, :b=>255}]
I've included the colors below. The large blocks are the two adjacent colors with the biggest/smallest differences. The smaller blocks are what it looks like if I continue adding one to their respective color channels (green for the largest difference, and red for the smallest difference.)
Note: It's easier to see the largest difference against a black background.
Largest perceptual difference:
Smallest perceptual difference:
You can clearly see the top blocks becoming more green, while the bottom blocks all look like the same color. (I had to double-check my HTML code to be sure I hadn't made any mistakes!)
I can't even really tell the difference between rgb(0,255,255)
and rgb(30,255,255)
!
I have to go all the way up to rgb(120,255,255)
before I can really notice the difference.
(I'm not color blind! I did a test!)
So I think we now have enough information to answer the question: Do we need more HTML colors?
No, 256 possible values for each color channel is plenty. It's virtually impossible for a human to tell the difference between any two adjacent color codes.