Not all colors look good. Let me rephrase: not all colors look good on everything. This is even more applicable when it comes to websites. When put next to each other, it is important for colors to look good, have the right contrast and be readable. Thankfully there are ways to generate such colors — attractive, readable and complementary — using code.
I started looking into generating attractive and complementary colors when we were working on a feature involving tags. We wanted to let users choose the color of their tags, and not only help them choose a good looking color, but also automatically derive variations of their color for the best visual effect. Take a look at this:
The text and the border are the same color (#369E33).
Now this:
The border is now slightly “lighter” (#60BF5D).
This might not look much, but when used in a small area and alongside other tags, a darker border can make the page look busy.
Here is another example — this time a button:
There are two colors here: the background (#4D7BFF) and the border (#7F98EE). For a button, you might want to add a third color for hover:
The hover background is lighter here (#628BFE).
Wouldn’t be nice if we could let the user choose the color they like from a list of randomly generated good-looking colors and derive one or two variations of that color as well?
The code below generates distinct colors that look good and are consistent in lightness and saturation. It is written using the algorithm developed by Martin Ankler in his blog post.
module Colors class Random # generates a count number of duo of a random color, one bright and one dark def self.generate_trio(count = 1) gen = ::Colors::Random.new golden_ratio_conjugate = 0.618033988749895 h = rand result = [] count.times do duo = {} h += golden_ratio_conjugate h %= 1
r, g, b = gen.hsv_to_rgb(h, 0.5, 0.95)
duo[:bright] = gen.rgb_to_hex(r, g, b)
r, g, b = gen.hsv_to_rgb(h, 0.5, 0.80)
duo[:middle] = gen.rgb_to_hex(r, g, b)
r, g, b = gen.hsv_to_rgb(h, 0.5, 0.70)
duo[:dark] = gen.rgb_to_hex(r, g, b)
result << duo end return result end def hsv_to_rgb(h, s, v) h_i = (h*6).to_i
f = h*6 - h_i
p = v * (1 - s)
q = v * (1 - f*s)
t = v * (1 - (1 - f) * s)
r, g, b = v, t, p if h_i==0
r, g, b = q, v, p if h_i==1
r, g, b = p, v, t if h_i==2
r, g, b = p, q, v if h_i==3
r, g, b = t, p, v if h_i==4
r, g, b = v, p, q if h_i==5
[(r*256).to_i, (g*256).to_i, (b*256).to_i] end def rgb_to_hex(r, g, b) return sprintf("#%02x%02x%02x", r, g, b) end end end
You can use this code to generate as many as color duos as you like:
colors = ::Colors::Random.generate_trio(4) # generate 4 color sets colors.each do |color| light_variant = color[:bright] middle_variant = color[:middle] dark_variant = color[:dark] # ... each variant comes as a string in an HTML friendly format (#RRGGBB) end
You can keep calling the generate_trio
method to rotate through a series of distinct, random colors, allowing visitors choose their own favorite!
Originally published at https://blog.cloud66.com on October 12, 2021.