How to generate (attractive) colors in code?

Cloud 66
3 min readOct 12, 2021

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.

--

--

Cloud 66

DevOps-as-a-Service to help developers build, deploy and maintain apps on any Cloud. Sign-up for a free trial by visting: www.cloud66.com