How to dynamically change the color of the text based on the background color?

Asked

Viewed 2,497 times

2

I am trying to change the color of the text according to the background in css, I have a list, each line is a color, I need that for light backgrounds the text is black and for dark backgrounds the text is clear.

Example:

tr td {
  color: white;
  -webkit-filter: invert(100%);
  filter: invert(100%);
}
.tr1 {
  background-color: white;
}
.tr2 {
  background-color: black;
}
.tr3 {
  background-color: red;
}
.tr4 {
  background-color: blue;
}
<table>
  <tr class="tr1">
    <td>Item 1</td>
  </tr>
  <tr class="tr2">
    <td>Item 2</td>
  </tr>
  <tr class="tr3">
    <td>Item 3</td>
  </tr>
  <tr class="tr4">
    <td>Item 4</td>
  </tr>
</table>

I’m using invert but it ends up reversing shades that do not need.

And +- http://aerolab.github.io/midnight.js/ but without these effects.

  • So you don’t want to reverse the colors?

  • "each line is a color, need that when you mouse over it, it is clearly read" this is not very open to opinion?

  • If you were applying the rule to the elements, being more generic, it would be a problem. But since you have classes, why not use them? .tr1 td:hover { filter: none } would not solve?

  • If you need to control the colors, the solution is probably to clarify the colors instead of using the invert. Put the desired background and front color on hover and it’s done. After all, it’s a cross-broswer solution that works since many versions behind the browsers.

4 answers

6

Using mix-blend-mode:

Acceptance of this parameter is not one of the greatest, but for now I believe to be the only reasonable alternative with pure CSS:

.tr1 {
  background-color: white;
}
.tr2 {
  background-color: black;
}
.tr3 {
  background-color: red;
}
.tr4 {
  background-color: blue;
}

td {
  color:#fff;
  mix-blend-mode: exclusion;
}
<table>
  <tr class="tr1">
    <td>Item 1</td>
  </tr>
  <tr class="tr2">
    <td>Item 2</td>
  </tr>
  <tr class="tr3">
    <td>Item 3</td>
  </tr>
  <tr class="tr4">
    <td>Item 4</td>
  </tr>
</table>

Note that in this case, as it depends on two layers, I am applying the property to <td> and not us <tr>.


Alternative with edge only:

I’m only posting to have a different output of the automatic background color. The idea here is to highlight the writing with a "contour", simulated with text-shadow:

.tr1 {
  background-color: white;
}
.tr2 {
  background-color: black;
}
.tr3 {
  background-color: red;
}
.tr4 {
  background-color: blue;
}

.tr1,.tr2,.tr3,.tr4 {
  color:#000;
  text-shadow: 0 -1px 2px #fff,0 1px 2px #fff,-1px 0 2px #fff,1px 0 2px #fff;
}
<table>
  <tr class="tr1">
    <td>Item 1</td>
  </tr>
  <tr class="tr2">
    <td>Item 2</td>
  </tr>
  <tr class="tr3">
    <td>Item 3</td>
  </tr>
  <tr class="tr4">
    <td>Item 4</td>
  </tr>
</table>

  • But you understand what I want ? I’m almost using javascript to scan all the light background tones and set the text as black and the dark background planes with the white text... but I wanted to see if you can do it with css only

  • Understanding I understood, after you edited the question got better. I just wanted to post an alternative that could be solved with CSS, because probably only with JS even to solve automatically. To tell you the truth, I think it made up for you to spell out the color directly, without complicating it. Instead of just the background-color, you could put the color too, on all the different ones. If you are generating the page with something server-side, it is better than with JS, because it no longer depends on the JS running on the client side.

  • I updated with a CSS alternative

  • Because eh, was testing this mix-blend-mode now, the bad thing is that it ends up leaving the text color of other colors, would like black and white only.

  • I ended up doing this: https://jsfiddle.net/gabrielr47/Lb7dvdr5/

  • If you already use jQuery in the project, it’s a good solution. Otherwise, better to do with pure JS. You can post as answer.

  • Yes, I do. I posted it in response:)

Show 2 more comments

3

What you want is to implement invert except class Tr1.

Change the css of.:

tr td:hover {
  -webkit-filter: invert(1);
  filter: invert(1);
}

for.:

tr:not(.tr1) td:hover {
  -webkit-filter: invert(1);
  filter: invert(1);
}

Stay like this.:

tr:not(.tr1) td:hover {
  -webkit-filter: invert(1);
  filter: invert(1);
}
.tr1 {
  background-color: white;
}
.tr2 {
  background-color: black;
}
.tr3 {
  background-color: red;
}
.tr4 {
  background-color: blue;
}
<table>
  <tr class="tr1">
    <td>Item 1</td>
  </tr>
  <tr class="tr2">
    <td>Item 2</td>
  </tr>
  <tr class="tr3">
    <td>Item 3</td>
  </tr>
  <tr class="tr4">
    <td>Item 4</td>
  </tr>
</table>

1


As I could not find this solution in css and I am using jQuery in my project I created a plugin to scan all backgrounds of tr’s and change them according to their tonality.

Example:

// Alimentando a Tabela para testes

var cores = ['#FFFFFF', '#FF0000', '#33ff33', '#0000FF', '#FF00FF', '#00FFFF', '#000000', '#FFFF00', '#FFFFFF', '#FFCCCC', '#FFCC99', '#FFFFCC', '#CCCCCC', '#C0C0C0', '#999999', '#666666', '#333333',
  '#000000', '#99FF99', '#66FF99', '#33ff33', '#00CC00', '#009900', '#006600', '#003300', '#FF6666', '#FF0000', '#CC0000', '#990000', '#660000', '#330000', '#CCFFFF', '#66FFFF', '#33CCFF',
  '#3366FF', '#3333FF', '#000099', '#000066', '#FFCC33', '#FF9900', '#FF6600', '#CC6600', '#993300', '#663300', '#FFCCFF', '#FF99FF', '#CC66CC', '#CC33CC', '#993366', '#663366', '#330033',
  '#FFFF99', '#70DB93', '#238E23', '#93DB70', '#00FF7F', '#2F4F2F', '#4A766E', '#4F4F2F', '#32CD32', '#527F76', '#215E21', '#9F9F5F', '#32CD99', '#6B8E23', '#426F42', '#7FFF00', '#8FBC8F',
  '#238E68', '#99CC32', '#5C3317', '#A62A2A', '#5C4033', '#97694F', '#855E42', '#D19275', '#8E2323', '#E9C2A6', '#A68064', '#EBC79E', '#6B4226', '#8E6B23', '#DB9370', '#5C4033', '#9F5F9F',
  '#9932CD', '#871F78', '#856363', '#4E2F2F', '#8E236B', '#4F2F4F', '#9370DB', '#DB7093', '#FF6EC7', '#DB70DB', '#BC8F8F', '#EAADEA', '#FF1CAE', '#CC3299', '#6F4242', '#B5A642', '#D9D919',
  '#8C7853', '#A67D3D', '#D98719', '#B87333', '#FF7F00', '#CD7F32', '#DBDB70', '#E47833', '#EAEAAE', '#CFB53B', '#FF7F00', '#FF2400', '#8C1717', '#D8D8BF', '#5F9F9F', '#42426F', '#6B238E',
  '#7093DB', '#C0D9D9', '#8F8FBD', '#3232CD', '#7F00FF', '#70DBDB', '#2F2F4F', '#23238E', '#4D4DFF', '#00009C', '#5959AB', '#3299CC', '#007FFF', '#236B8E', '#38B0DE', '#D8BFD8', '#ADEAEA',
  '#2F4F4F', '#545454', '#C0C0C0', '#A8A8A8', '#D9D9F3', '#E6E8FA', '#CDCDCD'
];
var table = '';
for (i = 0; i < cores.length; i++) {
  table += "<tr style='background-color:" + cores[i] + ";'><td> " + cores[i] + " </td></tr>";
}

table += "<tr><td>#FFFFFF  </td></tr>";

$("#table").append(table);


// Plugin jQuery - Muda a Cor do texto baseado na cor de fundo.

$.fn.textColorSwitch = function() {
  this.init = function() {
    $.each(this.find('tr'), function(key, val) {
      var colors = $(val).css('backgroundColor').match(/^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/);
      if (colors !== null) {
        var cor = 'white';

        var maxColor = (
          Math.floor((colors[1]) * 1) +
          Math.floor((colors[2]) * 1) +
          Math.floor((colors[3]) * 1)
        );

        if (maxColor > 382) {
          cor = 'black';
        }
        $(this).css('color', cor);
      }
    });
  };
  this.init();
  return this;
};

// Chamando o Plugin

$("table").textColorSwitch();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>

<table id="table"></table>

  • Just one observation: if in the real situation you are already generating the table by JS, it is pointless to color later. It would be much simpler to color the front and the background in the generation loop itself. Your solution is good if it is applied to a table that already has colors originally. Note that factors * 1 would actually have to be different depending on the color channel ( R, G and B has a different brightness to our eyes)

  • 1

    @Bacco in my case the tables will already be generated by a library that I do not want to extend or change, to mark as accepted I have to wait 2 days, maybe appear some better answer in the meantime

1

I believe that what you are looking for is clear reading of the text. Come on.

We can do this using simple and , we can still add some basic fade effects that can be removed by deleting the first selection from css if you don’t want to use.

The code is simple, let’s start by keeping your html

<table>
   <tr class="tr1">
      <td>Item 1</td>
   </tr>
   <tr class="tr2">
      <td>Item 2</td>
   </tr>
   <tr class="tr3">
      <td>Item 3</td>
   </tr>
   <tr class="tr4">
      <td>Item 4</td>
   </tr>
</table>

And now to do what we want to make it easier to read, let’s apply an effect fade that will "highlight" the text.

CSS

 tr td {
     display: inline-block;
     vertical-align: middle;
     -webkit-transform: translateZ(0);
     transform: translateZ(0);
     box-shadow: 0 0 1px rgba(0, 0, 0, 0);
    -webkit-backface-visibility: hidden;
     backface-visibility: hidden;
    -moz-osx-font-smoothing: grayscale;
     overflow: hidden;
    -webkit-transition-duration: 0.3s;
    transition-duration: 0.3s;
    -webkit-transition-property: color, background-color;
    transition-property: color, background-color;
}

tr td:hover, tr td:focus, tr td:active {
    background-color: #2098d1;
    color: white;
}

The edition to adapt to your use is very simple too, just changing colors and the like.

The result can be seen here: https://jsfiddle.net/a3sL15j9/4/

Browser other questions tagged

You are not signed in. Login or sign up in order to post.