DEV Community

Cover image for Changing text colour based on 

background colour luminosity
Jamie Mc Manus
Jamie Mc Manus

Posted on • Edited on

Changing text colour based on background colour luminosity

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;
        }


    }
}
Enter fullscreen mode Exit fullscreen mode
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>
Enter fullscreen mode Exit fullscreen mode
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.

Alt 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 ☕ )

Buy Me A Coffee

Credits

Cover Photo by Ruvim Noga on Unsplash

Top comments (3)

Collapse
 
grahamthedev profile image
GrahamTheDev • Edited

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?

Collapse
 
jamiemcmanus profile image
Jamie Mc Manus

I can't believe I didn't notice that, thanks !

I have adjusted the code to add additional contrast.

Collapse
 
grahamthedev profile image
GrahamTheDev

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.)