Determine font color based on background color
I encountered similar problem. I had to find a good method of selecting contrastive font color to display text labels on colorscales/heatmaps. It had to be universal method and generated color had to be "good looking", which means that simple generating complementary color was not good solution - sometimes it generated strange, very intensive colors that were hard to watch and read.
After long hours of testing and trying to solve this problem, I found out that the best solution is to select white font for "dark" colors, and black font for "bright" colors.
Here's an example of function I am using in C#:
Color ContrastColor(Color color)
{
int d = 0;
// Counting the perceptive luminance - human eye favors green color...
double luminance = (0.299 * color.R + 0.587 * color.G + 0.114 * color.B)/255;
if (luminance > 0.5)
d = 0; // bright colors - black font
else
d = 255; // dark colors - white font
return Color.FromArgb(d, d, d);
}
This was tested for many various colorscales (rainbow, grayscale, heat, ice, and many others) and is the only "universal" method I found out.
Edit
Changed the formula of counting a
to "perceptive luminance" - it really looks better! Already implemented it in my software, looks great.
Edit 2
@WebSeed provided a great working example of this algorithm: http://codepen.io/WebSeed/full/pvgqEq/
Calculate text color depending to a background color
You can consider the fact that a color with negative luminosity is always black and a white color is a color with luminosity bigger than 100%
.
Here is an idea where I use calc(30% - luminosity)
which will return a positive value if the luminosity is less than 30% (white color) and will return a negative value if the luminosity bigger than 30% (black color). I multiply everything by 100
to always have white in case of small positive value.
:root {
--main-color-hue: 205;
--main-color-saturation: 73%;
--main-color-luminosity: 29%;
--main-color: hsla(var(--main-color-hue), var(--main-color-saturation), var(--main-color-luminosity), 1);
--main-dark-color: hsla(var(--main-color-hue), var(--main-color-saturation), calc(var(--main-color-luminosity) * 0.5), 1);
--main-light-color: hsla(var(--main-color-hue), var(--main-color-saturation), calc(var(--main-color-luminosity) * 1.5), 1);
--main-text-color: hsl(0,100%, calc((30% - var(--main-color-luminosity)) *100));
--main-dark-text-color: hsl(0,100%, calc((30% - var(--main-color-luminosity)*0.5) *100));
--main-light-text-color: hsl(0,100%, calc((30% - var(--main-color-luminosity)*1.5) *100));
}
button {
background-color: var(--main-color);
color: var(--main-text-color);
border: 0;
padding: 16px;
}
button.dark {
background-color: var(--main-dark-color);
color: var(--main-dark-text-color);
border: 0;
padding: 16px;
}
button.light {
background-color: var(--main-light-color);
color: var(--main-light-text-color);
border: 0;
padding: 16px;
}
Main
<button>test</button>
Dark
<button class="dark">test</button>
Light
<button class="light">test</button>
How to decide font color in white or black depending on background color?
Building on my answer to a similar question.
You need to break the hex code into 3 pieces to get the individual red, green, and blue intensities. Each 2 digits of the code represent a value in hexadecimal (base-16) notation. I won't get into the details of the conversion here, they're easy to look up.
Once you have the intensities for the individual colors, you can determine the overall intensity of the color and choose the corresponding text.
if (red*0.299 + green*0.587 + blue*0.114) > 186 use #000000 else use #ffffff
The threshold of 186 is based on theory, but can be adjusted to taste. Based on the comments below a threshold of 150 may work better for you.
Edit: The above is simple and works reasonably well, and seems to have good acceptance here at StackOverflow. However, one of the comments below shows it can lead to non-compliance with W3C guidelines in some circumstances. Herewith I derive a modified form that always chooses the highest contrast based on the guidelines. If you don't need to conform to W3C rules then I'd stick with the simpler formula above. For an interesting look into the problems with this see Contrast Ratio Math and Related Visual Issues.
The formula given for contrast in the W3C Recommendations (WCAG 2.0) is (L1 + 0.05) / (L2 + 0.05)
, where L1
is the luminance of the lightest color and L2
is the luminance of the darkest on a scale of 0.0-1.0. The luminance of black is 0.0 and white is 1.0, so substituting those values lets you determine the one with the highest contrast. If the contrast for black is greater than the contrast for white, use black, otherwise use white. Given the luminance of the color you're testing as L
the test becomes:
if (L + 0.05) / (0.0 + 0.05) > (1.0 + 0.05) / (L + 0.05) use #000000 else use #ffffff
This simplifies down algebraically to:
if L > sqrt(1.05 * 0.05) - 0.05
Or approximately:
if L > 0.179 use #000000 else use #ffffff
The only thing left is to compute L
. That formula is also given in the guidelines and it looks like the conversion from sRGB to linear RGB followed by the ITU-R recommendation BT.709 for luminance.
for each c in r,g,b:
c = c / 255.0
if c <= 0.04045 then c = c/12.92 else c = ((c+0.055)/1.055) ^ 2.4
L = 0.2126 * r + 0.7152 * g + 0.0722 * b
The threshold of 0.179 should not be changed since it is tied to the W3C guidelines. If you find the results not to your liking, try the simpler formula above.
CSS Custom text color based on background
You can try using inverted colors and re-inverting the whole thing with a CSS filter like so:
body {
margin: 0;
}
#sf-coming-up {
filter: invert(1);
height: 100vh;
}
.blob {
position: absolute;
top: 15%;
right: 15%;
z-index: -1;
width: 70%;
height: 70%;
border-radius: 25% 75% 25% 50% / 75% 25% 50% 25%;
background: springgreen;
}
.title {
padding: 25vh 0 0 12.5vh;
color: springgreen;
mix-blend-mode: difference;
}
<div id="sf-coming-up">
<div class="title">Binnenkort in ons theater</div>
<div class="blob"></div>
</div>
Change text color based on brightness of the covered background area?
Interesting resources for this:
- W3C - Ensure that foreground and background color combinations provide sufficient contrast
- Calculating the Perceived Brightness of a Color
Here's the W3C algorithm (with JSFiddle demo too):
const rgb = [255, 0, 0];
// Randomly change to showcase updates
setInterval(setContrast, 1000);
function setContrast() {
// Randomly update colours
rgb[0] = Math.round(Math.random() * 255);
rgb[1] = Math.round(Math.random() * 255);
rgb[2] = Math.round(Math.random() * 255);
// http://www.w3.org/TR/AERT#color-contrast
const brightness = Math.round(((parseInt(rgb[0]) * 299) +
(parseInt(rgb[1]) * 587) +
(parseInt(rgb[2]) * 114)) / 1000);
const textColour = (brightness > 125) ? 'black' : 'white';
const backgroundColour = 'rgb(' + rgb[0] + ',' + rgb[1] + ',' + rgb[2] + ')';
$('#bg').css('color', textColour);
$('#bg').css('background-color', backgroundColour);
}
#bg {
width: 200px;
height: 50px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="bg">Text Example</div>
How to change Text color depending on background so that there is good contrast between the two colors
you can use computeLuminance() of Color class. Something like this:
@override
Widget build(BuildContext context) {
var backgroundColor = Colors.orange; // this color could be anything
var foregroundColor = backgroundColor.computeLuminance() > 0.5 ? Colors.black : Colors.white;
return Scaffold(
body: Center(
child: Container(
padding: const EdgeInsets.all(12),
color: backgroundColor,
child: Text("Hello World", style: TextStyle(color: foregroundColor)),
),
),
);
}
Of course you need to play around with the luminance IF-statement ... 1.0 is white and 0.0 is black. Yellow for instance is something about 0.8.
Related Topics
Create Line After Text with CSS
Wrapping a Text Around a Circular Element
How to Identify and Eliminate Unused CSS Styles from My Bloated Stylesheet
Display:Block Not Working in Chrome or Safari
How to Change a Background Image Opacity Without Changing on Div Content
Rounding Numbers in SASS and Adjusting the Amount of Decimals
How to Use a Data Attribute to Set a Background-Image in CSS
What Is That Thing Between CSS "Selectors" Called
Has the ::-Webkit-Selection Selector Ever Been Supported
Label Next to Selectinput in Shiny
Svg + CSS3 Animation Not Working with Link Markup
404 Errors on Bundled Jquery CSS, VS2012 Publishing to Azure
Change the Default Responsive Navbar Breakpoint
Why Doesn't My Child Element Inherit Color from Its Parent When Parent Has More Specific Selector
Flex Item with Image Child Doesn't Adjust Its Size Properly