Scenario
You decide to let the users of your application set the preferred colour of an item - this could anything from a simple card to an list item on a Kanban board. This is a straightforward feature and common enough but it can wreak havoc on any foreground text that we place over it, like what happens if our text is white and they choose a light colour ?
Your text will have the visibility of a ghost 👻.
This isn't good. Our foreground text is gone and its because we gave the user an input in the application style, but fear not, the battle hasn't been lost yet.
Le Solution
What if we could check how dark / bright the colour the user selected is ?
We could change the colour of the foreground text dynamically to be visible. To do this we need to find the Luminosity of the background colour, which is a measure of how bright or dark a hue is.
Code
Create a Service folder in your project and create a new class Luminosity.cs
. Within this class we'll keep our helper methods for the task.
We need to first get the luminance of the background colour , then using this value return a colour between white and black. The Luminance will be a double between 0 (black) and 1(white), and we'll then translate this into an RGB value.
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Web;
namespace sampleproject.Services
{
public static class Luminosity
{
public static double GetLuminosity(string colour)
{
//Convert html colour to Color Object
Color color = ColorTranslator.FromHtml(colour);
//Get the Luminancce value from the converted color.
double luminance = (0.299 * color.R + 0.587 * color.G + 0.114 * color.B) / 255;
return luminance;
}
public static string GetColour(string colour)
{
double luminance = GetLuminosity(colour);
// Translate the luminance to RGB values
int c = (255 - Convert.ToInt32( luminance * 255)) ;
/*Add some additional contrast just in case the
luminance was near the 127 props to InHuOfficial for noticing.
*/
if (c > 127 )
{
c += 100;
if (c > 255)
{
c = 255;
}
}
else if (c <= 127 )
{
c -= 100;
if (c < 0)
{
c = 0;
}
}
var color = $"rgb({c},{c},{c})";
return color;
}
}
}
Razor View
Now within the Razor View we can use the helper method to change the value of the foreground text.
@using sampleproject.Services;
@{
ViewBag.Title = "Index";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<div class="card-container">
@foreach (var item in Model)
{
var style = "";
style = "background-color:" + item.Primarycolor + ";color:"+Luminosity.GetColour(item.Primarycolor)+";";
<div class="card" style="@style">
.....card content
</div>
}
</div>
The Result
With the above code we should get a result roughly like the below.
The colour of the foreground text should always be on the opposite end of the scale to the background text.
And if you're feeling generous you can buy me a coffee with the link below ( and yes its all for coffee, I drink a copius amount of it while writing ☕ )
Credits
Cover Photo by Ruvim Noga on Unsplash
Top comments (3)
See I like the concept, but (and I could be reading it wrong) - does this not start failing the closer a colour has to a luminance of 127?
Instead, perhaps you could do something where you try and make the luminance +100, if it goes over 255 then try - 100?
That way you should always get good contrast?
I can't believe I didn't notice that, thanks !
I have adjusted the code to add additional contrast.
I think you made another minor mistake 😜🤣
If you get a 220 luminosity result you are trying to add 100 to it and capping at 255. I think all you have done is swap your greater thans and less thans by mistake!
Also with the way you have done it you could actually just do
Less than 127, add 100. Greater than 127, remove 100. You will never go out of bounds so you don’t need the additional checks. (126+100 or 127 - 100, it will always be within 0 to 255.)