I have some color swatches that should show the rgb value of the color displayed, with the background being the actual color. Then, if the color in question is light-ish, the text should be black, and if the color in question is dark-ish, the text color should be white.
How can I detect if the RGB value is light-ish or dark-ish??
JS FIDDLE
<style>
#preview {
display: block;
height: 40px;
line-height: 40px;
font-size: 20px;
vertical-align: middle;
width: 150px;
text-align: center;
}
</style>
<!-- html -->
<button id="new_color">Try Random Color</button>
<p id="preview">Click the button!</p>
<script>
const getRandNum = () => Math.floor(Math.random() * 256);
const get_random_color = () => (`rgb(${getRandNum()}, ${getRandNum()}, ${getRandNum()})`);
const checkColor = (color) => {
// color = 'rgb(x, y, z)';
// check color is light
// or color is dark
return true;
}
$('#new_color').click(function(){
const p = $('#preview');
const bg_color = get_random_color();
const color_is_light = checkColor( bg_color );
const text_color = color_is_light ? 'black' : 'white';
p.css({
color: text_color,
backgroundColor: bg_color
})
});
</script>
I only found solutions for #hex colors, but not for rgb. Any help is very much appreciated.
If you're looking for relative luminance, a quick formula you can use is:
Y = 0.2126R + 0.7152G + 0.0722B
Source: https://en.wikipedia.org/wiki/Relative_luminance
To be able to use the coefficients above directly, you'll have to either normalize your RGB components to 1. Or divide by 255 first. The Y value you'll get is between 0-1, so you can probably then do:
const color_is_light = y > 0.5;
I'd do something like:
const getRandomRgb = () => [
Math.random(),
Math.random(),
Math.random()
];
const getRelativeLuminance = (rgb) =>
0.2126 * rgb[0]
+ 0.7152 * rgb[1]
+ 0.0722 * rgb[2];
const getCssColor = (rgb) => `rgb(${rgb.map((c) => c * 255)}`;
Though, there'll literally be a "gray area" where you will not get enough contrast with either white or black text against a mid-gray background.
You may want to change your get_random_color function to return the individual components, do the math above, and then construct the CSS color value afterwards.
So if you have answers for hex, adapt those for RGB because the hex values are just the base 16 numbers of the rgb base 10 values. Looking for a way to convert between bases now.
EDIT: If your r value in hex is "5a", the way to get that r value in base 10 for rgb() is parseInt("5a",16)
EDIT2: To get the hex value from decimal, this works: const hex = d => Number(d).toString(16).padStart(2, '0') ~ taken from How to convert decimal to hex in JavaScript?
You have to check if(red + green + blue >= 255 * 1.5) for a light color as said by the second answer in this post
const checkColor = (color) => {
// extract values of red, green and blue from color
let clrarr = color.match(/\d+/g).map(num => +num);
if(clrarr[0] + clrarr[1] + clrarr[2] >= 255 * 3 / 2)
return true; // color is light
return false; // color is dark
}
JSFiddle
Related
I have elements that should be colored by some color. However the bigger index of the element the 'lighter' shade of said color it should be, but never gray or white.
What is some function to achieve this? The only thing i have found is
const adjust = (color, amount) => {
return '#' + color.replace(/^#/, '').replace(/../g, color => ('0' + Math.min(255, Math.max(0, parseInt(color, 16) + amount)).toString(16)).substr(-2));
}
function, but it always results in grey and even white color.
e.g:
let elements = fetchElements(); // approx 300 elements
for( let i = 0 ; i < elements.length ;i++ ){
let color = adjust(#000000,i);
buildElement( elements[i]; color );
}
I don't realy undrestand what you are doing here(!) but maybe you could use RGBA format, lower the alpha number on each loop then convert it back to hex.
In my #vue/cli 4.1.1 app user enter color and I have to output
color value with entered color and I wonder how can I calculate and set background color
to be sure that entered color value is good visible. I mean if user entered white color(or near)
background must be dark?
Thanks
You can give an invert color - 255-color for each of rgb
function bg(r, g, b) {return [255-r, 255-g, 255-b]}
if you get it in hex format, you can convert it to rgb, then get the invert. like so:
function invert(hex){
hex = parseInt(hex.substring(1), 16);
var r = hex >> 16;
hex -= r << 16;
var g = hex >> 8;
hex -= g << 8;
var b = hex;
return `rgb(${255-r},${255-g},${255-b})`;
}
var color1 = "#eeff00";
var color2 = "#22faef";
var color3 = "#f1f1f1";
document.querySelector('#a').style = `color:${color1};background-color:${invert(color1)}`;
document.querySelector('#b').style = `color:${color2};background-color:${invert(color2)}`;
document.querySelector('#c').style = `color:${color3};background-color:${invert(color3)}`;
div {
padding: 10px;
}
<div id="a">Hello world!</div>
<div id="b">Hello world!</div>
<div id="c">Hello world!</div>
You can determine the entered color to be light or dark on the basis of its luminance.
Here you can find a formula it's calculated on.
So, you can, for example, define the function isLight like this
function isLight(color) {
// Converting hex color to rgb
const [red, green, blue] = hexToRgb(color);
// Determine luminance
const luminance = (0.299 * red + 0.587 * green + 0.114 * blue)/255;
// Returning true if color is light
return luminance > 0.5;
}
// function for converting hex colors to rgb array format
function hexToRgb(hex) {
const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
return result ? [
parseInt(result[1], 16),
parseInt(result[2], 16),
parseInt(result[3], 16)
] : null;
}
By using this function you can determine if the user color is light or dark and thus set the appropriate background
I'm trying to add a gradient to every element to each page, for now, I've achieved it but I've run into a problem.
If the gradient is too light my text is not visible, is there any way to check if the gradient color is too light and then change the text to black?
Here is my code
This is the gradients element = https://github.com/ghosh/uiGradients/blob/master/gradients.json
const cards = document.querySelectorAll('.card');
cards.forEach((card)=>{
let i = Math.floor(Math.random() * gradients.length);
const color = gradients[i].colors;
color.forEach((color)=> {
let finalGradient = `background: linear-gradient(to right, ${color}, ${color}, ${color}) !important;`;
card.style.cssText = finalGradient;
})
})
Here a function that I use to detect if a color is light or dark. You can use it and adapt to your code:
function isLightOrDark(color) {
// Variables for red, green, blue values
var r, g, b, hsp;
// Check the format of the color, HEX or RGB?
if (color.match(/^rgb/)) {
// If HEX --> store the red, green, blue values in separate variables
color = color.match(/^rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*(\d+(?:\.\d+)?))?\)$/);
r = color[1];
g = color[2];
b = color[3];
}
else {
// If RGB --> Convert it to HEX: http://gist.github.com/983661
color = +("0x" + color.slice(1).replace(
color.length < 5 && /./g, '$&$&'));
r = color >> 16;
g = color >> 8 & 255;
b = color & 255;
}
// HSP (Highly Sensitive Poo) equation from http://alienryderflex.com/hsp.html
hsp = Math.sqrt(
0.299 * (r * r) +
0.587 * (g * g) +
0.114 * (b * b)
);
// Using the HSP value, determine whether the color is light or dark
if (hsp>127.5) {
return 'light';
}
else {
return 'dark';
}
}
I am building a simple website that gives a random quote when I click a button, and with that, the background color changes. The thing is that sometimes the background color is too dark and the font is black, and consequently the person can't read the quote.
My question:
Is there is any way to create a random color code using just bright colors, or pastel colors?
I got this code to generate a random color. I tried to edit to get only A to F strings but no success:
'#'+((1<<24)*(Math.random()+1)|0).toString(16).substr(1)
Thank you very much in advance.
HSL Colors
Using HSL Colors colors may be the easiest. HSL color values are specified in CSS as
hsl( hue, saturation%, lightness%)
where hue is in range 0-360 (without a unit marker when using degrees), and both saturation and lightness are percentages with a trailing % sign.
Note
"Bright" colors refer to the colors of an RGB color wheel formed by starting at red and then blending pure red into green, pure green into blue, and finally pure blue back into red again.
In HSL color space, bright colors are represented by a hue based on their position on the color wheel with 100% saturation and a lightness value of 50%:
hue 0 ▶ ◀ hue 360
saturation: 100%
lightness: 50%
Colors blend with white - and become more "pastel" as lightness increases above 50%. A lightness value of 100% creates white regardless of what the values of hue and saturation are.
Colors blend with grey as the saturation decreases and become more washed out depending on how low the saturation gets. A saturation value of 0% creates a grey-scale tone based on lightness alone.
Colors blend with black as lightness decreases below 50%. A lightness value of 0% creates black no matter what the hue and saturation values are.
Warning
The human eye is least sensitive to the color blue. Black text on a blue background - or blue over black - is harder to read in comparison to other colors. If this becomes an issue for random color selection, example 2 shows one way to compensate.
Example 1: Some random pastel colors with saturation in range 25-95% and lightness in range 85-95%:
function getColor(){
return "hsl(" + 360 * Math.random() + ',' +
(25 + 70 * Math.random()) + '%,' +
(85 + 10 * Math.random()) + '%)'
}
// Generate 20 colors
for( var i = 20; i--; ){
var item = document.createElement('div')
item.style.cssText = `
display:inline-block;
padding: 2em;
margin:5px;
border-radius:50%;
background: ${getColor()};
`
document.body.appendChild(item);
}
Example 2: This example demonstrates adjusting colors for the eye's lack of sensitivity to blue. It generates a boxed set of letters colored with hues in the range 0 to 340 presented on a black background.
"use strict";
// individual letter classes:
function letterCSS(letter, i, length, blueBoost) {
let hue = Math.floor( i/length * 341); // between 0 and 340
let saturation = 100;
let lightness = 50;
// color adjustment:
if( blueBoost && hue > 215 && hue < 265) {
const gain = 20;
let blueness = 1 - Math.abs( hue-240)/25;
let change = Math.floor( gain * blueness);
lightness += change;
saturation -= change;
}
let hsl = `hsl(${hue}, ${saturation}%, ${lightness}%)`;
return `.${letter} {
color: ${hsl};
border-color: ${hsl};
background-color: black;
}
` ;
}
// generate and display boxed letters of the alphabet
function letterBlocks() {
let letters = Array.from("ABCDEFGHIJKLMNOPQRSTUVWXYZ");
let cssText = "";
let html = ""
let blueBoost = document.getElementById("boost").checked;
letters.forEach( (letter, i, a) => {
cssText += letterCSS( letter, i, a.length, blueBoost);
html += ` <span class="letter ${letter}">${letter}<\/span> `;
});
let style = document.createElement("style");
style.textContent = cssText;
document.body.appendChild(style);
let p = document.getElementById("blocks");
p.innerHTML = html;
}
#blocks {
line-height: 2.5rem;
}
.letter {
display: inline-block;
text-align: center;
line-height: 2rem;
font-size: 1.5rem;
height: 2rem;
width: 2rem;
font-family: sans-serif;
font-weight: bold;
border-width: 0.125rem;
border-style: solid;
border-radius: 0.25rem;
}
<button type="button" onclick="letterBlocks()">Generate Letter Blocks</button><label>
- optionally lighten colors near pure blue:<input type="checkbox" id="boost">
</label>
<p id="blocks"></p>
Letter colors start out with full saturation and 50% lightness. Check the option box and click the button to adjust colors close to blue by increasing lightness and decreasing saturation.
"Close to blue" is hard coded to mean within 25 degree units of hue value 240,
The maximum adjustment amount is set by gain to 20 percentage units,
Demonstration code. Real code and adjustment values would be altered on a case by case basis depending on why and how color adjustments are being made.
By randomizing only the hue, it's faster.
HSLA colors are made of Hue, saturation, lightness and alpha.
Example, lightness to be adjusted as needed (third value).
function randomHSL(){
return "hsla(" + ~~(360 * Math.random()) + "," +
"70%,"+
"80%,1)"
}
rdm.onclick = (function(){
document.body.style.backgroundColor = randomHSL()
})
rdm.click()
<button id="rdm">Random pastel color!</button>
Or similary:
function randomHSL(){
return `hsla(${~~(360 * Math.random())},70%,70%,0.8)`
}
rdm.onclick = (function(){
document.body.style.backgroundColor = randomHSL()
})
rdm.click()
<button id="rdm">Random pastel color!</button>
You could choose among lighter colours by appropriately setting the background-color property using rgb.
rgb(0,0,0) is black, while rgb(255,255,255) is white. You could therefore use random values which are closer to (but not higher than) 255.
An example (using JQuery):
var rand = Math.floor(Math.random() * 10);
var colorQ = "rgb(" + (215 - rand * 3) + "," + (185 - rand * 5) + "," + (185 - rand * 10) + " )";
$("body").css("background-color", colorQ);
You can play around with the values until you find the colours that you prefer - keep in mind that the closer the 3 rgb values are to each other, the closer your colour will be to grey. E.g. rgb(100,100,100), rgb(221,221,221) and rgb(133,133,133) are all shades of grey. What changes is how light your grey will be.
I'm looking for a way, with jQuery ideally, to determine the correct text color, based on the brightness of the background color?
E.g. white background, black text colour. I believe this could be done crudely with adding the HEX value and guesstimating but does anyone know a better way or jQuery way to do this?
You can try inverting the hex value of the color. So #FFFFFF becomes #000000 and #AAAAAA becomes #555555. Of course, this method falls through when you have #888888 which when inverted, gives you #777777 (they don't contrast as much).
This blog post describes another way (they only use black or white for the foreground color, depending on the background color). I've translated it into Javascript:
function idealTextColor(bgColor) {
var nThreshold = 105;
var components = getRGBComponents(bgColor);
var bgDelta = (components.R * 0.299) + (components.G * 0.587) + (components.B * 0.114);
return ((255 - bgDelta) < nThreshold) ? "#000000" : "#ffffff";
}
function getRGBComponents(color) {
var r = color.substring(1, 3);
var g = color.substring(3, 5);
var b = color.substring(5, 7);
return {
R: parseInt(r, 16),
G: parseInt(g, 16),
B: parseInt(b, 16)
};
}