skip to Main Content

I’m facing the problem that users can change background colours for HTML components which sometimes conflict with text colours they can’t change (or more generally, background and text colour are visually too similar). As a result, the text may become invisible (or difficult to see) if those colours are visually close enough.

See below where’s there’s a triangle (=text)…

enter image description here

…which only becomes more visible on hover.

enter image description here

(the user could also have also opted for a grey background which would have made this even worse)

I’ve tried to tinker with filters (e.g. filter: brightness(50%) contrast(150%); or filter: saturate(0) grayscale(1) brightness(.7) contrast(1000%) invert(1) as suggested here), but that’s sensitive to the selected colours (i.e. may not work in all cases of background and text colour combinations). Is there a way (in CSS, without JS as shown here) that would change the text colour slightly (ideally, the "type of colour" itself is somewhat maintained), so that text on conflicting (too close) background and text colours becomes visible?

I realise that this question is asking for 2 things (1. detecting the conflict and 2. resolving the conflict by applying some sort of filter (or others)). If some suggestions are made for how to resolve the conflicting colours (2.), I’d already be happy.

Trying mix-blend-mode: difference

Without mix-blend-mode: difference;

enter image description here

With mix-blend-mode: difference;

enter image description here

2

Answers


  1. This article demonstrates a CSS method for switching the (text) color between black and white based on the (perceived) luminance of the background color. So it’s not exactly what you’re asking for, but it’s close.

    A simpler alternative you could consider is using a contrasting text-shadow to improve readability when the text and background colours are similar.

    :root {
      --clr-white-80: rgb(255 255 255 / 0.8);
    }
    
    body {
      background: lightsalmon;
      font-size: 2.5em;
    }
    
    p {
      color: peru;
      margin: 0;
    }
    
    .p2 {
      text-shadow: 0 0 5px var(--clr-white-80);
    }
    
    .p3 {
      text-shadow: 0 0 20px var(--clr-white-80);
    }
    
    .p4 {
      text-shadow: 2px 2px 0 var(--clr-white-80);
    }
    <p class="p1">Is this readable?</p>
    <p class="p2">What about now?</p>
    <p class="p3">Or with a larger spread</p>
    <p class="p4">Or with an offset</p>
    Login or Signup to reply.
  2. For mix-blend-mode: difference to work you have to use color: white property

    <div style="background-color: #000000;">
        <h1 style="mix-blend-mode: difference; color: white;">
            HEADER
        </h1>
    </div>
    

    Here the h1 tag’s color value will dynamically change according to the div tag’s background-color value.

    But if you want to set the colors to either black or white based on contrast you have to use js instead of css.

    Here is how you can do it

    function setTextColorBasedOnBackground() {
      const div = document.querySelector('div');
      const heading = document.querySelector('h1');
    
      // get the computed background color of the div
      const bgColor = window.getComputedStyle(div).backgroundColor;
    
      // convert the RGB color to an array of integers
      const rgb = bgColor.match(/d+/g).map(Number);
    
      // calculate the brightness of the background color
      const brightness = Math.round(((parseInt(rgb[0]) * 299) +
                                     (parseInt(rgb[1]) * 587) +
                                     (parseInt(rgb[2]) * 114)) / 1000);
    
      // set the text color based on brightness
      heading.style.color = (brightness > 125) ? 'black' : 'white';
    }
    

    run this function on content loads or when the background color of div changes.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search