13

I'm looking for a technique where we could programmatically pick the best color contrast to apply on text over HTML elements of different (unpredictable) background colors.

Since the HTML elements will have different colors, we're looking for a technique that will be able to determine what is the color of the content behind the text, and then adapt the text's color to use the one with the best contrast.

I'm quite sure this can't be CSS only, I've looked for Jquery solutions but couldn't find any... anyone has a clue?

[UPDATE] : Based on the first replies, I guess I need to rephrase. Imagine that I'm building a image sharing service and I want to allow people to tag on the pictures themselves. The pictures can be of any color. How can I pick up the right color of the tags, for each different picture?

Wayne
  • 59,728
  • 15
  • 131
  • 126
Julien Genestoux
  • 31,046
  • 20
  • 66
  • 93

6 Answers6

14

I think this might save any future researchers a little time, this works perfectly for me. Plug in the red green and blue values into the function and it outputs "dark-text" or "light-text".

var darkOrLight = function(red, green, blue) {
  var brightness;
  brightness = (red * 299) + (green * 587) + (blue * 114);
  brightness = brightness / 255000;

  // values range from 0 to 1
  // anything greater than 0.5 should be bright enough for dark text
  if (brightness >= 0.5) {
    return "dark-text";
  } else {
    return "light-text";
  }
}

Using some code from http://particletree.com/notebook/calculating-color-contrast-for-legible-text/ from @David's answer.

Alex Marchant
  • 2,490
  • 27
  • 49
  • 1
    Have a look to this JQuery plugin https://github.com/joggink/jquery-colorcontrast which seems to implement the said function. Be careful (currently) the plugin is not iterating ; you need to call 'each' by yourself – Cerber Dec 27 '12 at 18:03
2

There is now a property called mix-blend-mode in CSS (currently just in draft) that can be used to achieve something similar to what you want.

.contrasting-text {
    mix-blend-mode: difference;
}

CodePen someone has put together demonstrating this: https://codepen.io/thebabydino/pen/JNWqLL

J.D.
  • 1,786
  • 2
  • 22
  • 34
2

Take a look at http://www.0to255.com . Just a moment's glance at the gradients the site presents will light you right up. You'll have to puzzle, but only for about 20 seconds. It's a great site for such problems and a terrific source of ideas for programmatic solutions. And there's no math involved: just plug in some bytes for rgb vals and go.

Pete Wilson
  • 8,610
  • 6
  • 39
  • 51
  • 1
    +1 for the useful resource, although i'm not sure it particularly answers the question! – Town Apr 13 '11 at 14:42
  • Thanks for the link, but that doesn't say how I can actually get the color under the text! – Julien Genestoux Apr 13 '11 at 15:09
  • Ah, yes. I see now that I jumped ahead. You have to use Javascript and DHTML and DOM. In Javascript, find the object whose text color you are going to need to change; extract the background-color attribute from that object; and then proceed to choose a color for the tag text. Is that closer to the answer you're looking for? – Pete Wilson Apr 13 '11 at 16:58
  • @Julien Genestoux -- As to images: personally, I would never even think of trying to integrate colors in a photograph to produce a kind of composite background-color against which to display tag text in a contrasting color. Instead, I would always put a blob of white on top of the photo and display black tag text on that white blob. Just my opinion; there are without doubt cool algorithms that will calculate a good approximation of a average background color. Nut, just speaking for myself, I would not attempt such a thing. – Pete Wilson Apr 13 '11 at 17:07
0

This is my fav resource to calculate the "readability" (contrast ratio) of two colors.

the W3C suggests a contrast ratio of at least 5:1 exists between text and background behind the text http://www.w3.org/TR/2007/WD-WCAG20-TECHS-20070517/Overview.html#G18

From the page:

The compliance rate shown above is the highest compliance rate met. The WCAG 2.0 level AA and proposed Section 508 refresh compliance level is based on achieving a contrast ratio of 3:1 for text with a size of 18 points (14 points if bolded) or larger or 4.5:1 for text with a size less than 18 points. The WCAG 2.0 level AAA compliance level is meet when a contrast ration of 7:1 is achieved for text less than 18 points and 4.5:1 for text 18 points (14 points if bolded) or larger.

SavoryBytes
  • 35,571
  • 4
  • 52
  • 61
  • Sorry, but that's not answering the question. Yes, that would be if I was able to tell the color under my text, but I'm not. How can I? – Julien Genestoux Apr 13 '11 at 15:11
  • You can read out the current background color of the element using JavaScript: $('.myclass').css('background-color') with that value you can calculate the contrast level of any other color. I'm assuming you want to use jQuery since you mentions looking for it. – SavoryBytes Apr 13 '11 at 15:17
  • 2 problems : how do I determine the "myid"? What if it's an image? – Julien Genestoux Apr 13 '11 at 15:18
  • If your background is an image, I would not try to automate processing the colors client side (with canvas) - I'd look at a server side solution as it will have less cross browser issues and scale better. – SavoryBytes Apr 13 '11 at 15:21
0

Here's another approach I got from GitHub where they apply on the color of issue's labels. It actually relies on CSS custom properties with some calculations.

.hx_IssueLabel {
    --label-r:0;
    --label-g:0;
    --label-b:0;

    --lightness-threshold:0.453;
    --perceived-lightness:calc(((var(--label-r) * 0.2126) + (var(--label-g) * 0.7152) + (var(--label-b) * 0.0722)) / 255);
    --lightness-switch:max(0, min(calc((var(--perceived-lightness) - var(--lightness-threshold)) * -1000), 1));

    background:rgb(var(--label-r), var(--label-g), var(--label-b));
    color:hsl(0, 0%, calc(var(--lightness-switch) * 100%));
}

You will need to set the RGB channel separately in custom properties for the background color, then the text color will run from black to white by changing the lightness channel in HSL color. The lightness is calculated by an algorithm that receives RGB as inputs.

phucbm
  • 885
  • 6
  • 13
-1

In just one line this solves the problem:

function getContrast50($hexcolor)
{ 
  return (hexdec($hexcolor) > 0xffffff/2) ? 'white':'black'; 
}

If the contrast need to be reversed just swicth white with black and it does the trick. In php.

Andrew Barber
  • 39,603
  • 20
  • 94
  • 123
Marco
  • 29
  • 1
  • As previous comment states, this is PHP code, not Javascript. hexdec function exists in PHP, not in JS – Daniel Jul 04 '17 at 09:52