Do we need more HTML colors?

Do we need more HTML colors?
Photo by Joshua Woroniecki / Unsplash

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.

Color Matching Paint In GIMP: Don’t Make These Mistakes
Please note: This post is a stream-of-conciousness journal entry that describes all of the mistakes I made while trying to color match paint. This is not a how-to guide from an expert. We’re renting an old house that needs a lot of maintenance. The landlords are very easy-going so we’re

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:

Delta-E Calculator - ColorMine.org
Accurate and easy color comparisons with our online delta-e calculator. Compare colors in Rgb, Cmy, Cmyk, Hsl, Xyz, CIE-L*ab, CIE-Lch, and Yxy spaces.

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.

GitHub - mmozuras/color_difference: Implementation of CIEDE2000 color-difference formula
Implementation of CIEDE2000 color-difference formula - mmozuras/color_difference

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!)
EnChroma® Free Color Blind Test | Test Your Color Vision
Take the free Enchroma color blind test to accurately assess your color perception. The results provide a recommendation for EnChroma color blind glasses.

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.