Inspired by this great post by @dailydevtips1 about how to create random colors with Vanilla Javascript, I decided to write a little follow-up to make sure, the random color also has a matching font-color.
Creating the Random Background Color
As a reminder, we are generating random hexadecimal number with this function:
Math.floor(Math.random()*10000000).toString(16)
Actually, we might as well use 16777215 as a multiplier, which is the maximum possible decimal for a color (meaning 16777215 === #FFFFFF).
The result of this formula is a 6-digit hexadecimal number. Like RGB colors it consists of three parts:
- The first two digits represent the color red
- digits three and four represent the color green
- the last two digits represent the color blue
Determining the Font Color
To determine, which is the best possible font-color for a certain background, we can follow the recommended algorithm on www.w3.org.
Color brightness is determined by the following formula:
((Red value X 299) + (Green value X 587) + (Blue value X 114)) / 1000
Converting this formula to Javascript could look something like this:
const red = parseInt(color.substring(0,2),16)
const green = parseInt(color.substring(2,4),16)
const blue = parseInt(color.substring(4,6),16)
const brightness = red*0.299 + green*0.587 + blue*0.114
Now we have an integer value for the perceived brightness of our background color.
We took each color from the previously generated random color using substring
and converted the hexadecimal to a decimal using parseInt()
.
Since the variable brightness
of our function represents the brightness of our color, we can now use it to define the font color. I found that 180 is a good threshold to switch from white to black, but it's probably best to experiment a bit.
The function to set the font color could look like this.
if (brightness > 180) {
return { backgroundColor: '#' + color }
}
else return {
backgroundColor: '#' + color,
color: '#ffffff'
}
And my whole function looks like this:
const randomColor = () => {
let color = Math.floor(Math.random()*16777215).toString(16)
/* sometimes the returned value does not have
* the 6 digits needed, so we do it again until
* it does
*/
while (color.length<6) {
color = Math.floor(Math.random()*16777215).toString(16)
}
let red = parseInt(color.substring(0,2),16)
let green = parseInt(color.substring(2,4),16)
let blue = parseInt(color.substring(4,6),16)
let brightness = red*0.299 + green*0.587 + blue*0.114
/* if (red*0.299 + green*0.587 + blue*0.114) > 180
* use #000000 else use #ffffff
*/
if (brightness > 180) {
return { backgroundColor: '#' + color }
}
else return {
backgroundColor: '#' + color,
color: '#ffffff'
}
}
In an app it would look like this:
Top comments (2)
Interesting, could this be used for, say, a website that lets the user dynamically choose the colors? (Primary and accent). Excellent post by the way!
I guess so. You just have to make sure that the color the user chooses can be split into red, green and blue. When using random colors I sometimes had 5 digits and the formula did not work, which is why I added the
when
loop.Thanks! 😀