Como ler o valor do estilo na função CSS

Nov 07 2020

Estou criando vários divs em Javascript inserindo algo assim

'<div style="background-color:' + bgColor + '</div>'

Agora, quero definir o colordo texto automaticamente com base na luminosidade do fundo para preto ou branco.

Vejo 2 opções - todas baseadas em Javascript ou apenas em CSS. Eu prefiro a opção CSS, no entanto, não sei como ler a cor de fundo de uma função CSS, por exemplo

@function set-color($color) { @if (lightness($color) > 40) {
    @return #000;
  }
  @else {
    @return #FFF;
  }
}

Como posso obter a cor de fundo para fazer algo assim

div { color: set-color(???); }

Que tal mix-blend-mode?

Respostas

3 AHaworth Nov 14 2020 at 15:57

Existem várias idéias apresentadas na pergunta sobre como escolher entre preto e branco para a cor do texto, dependendo da cor de fundo.

A maioria foi respondida de uma forma ou de outra nos comentários. Pegando as ideias uma por uma:

Podemos usar o modo mix-blend-blend CSS - não. Não há uma configuração para isso que garanta que o texto aparecerá legível em todos os fundos possíveis.

Podemos usar CSS (o método preferido) - infelizmente não, pois o div que exige que a cor do texto dependa da cor de fundo é criado por JS em tempo de execução.

Podemos usar JS - sim e como o div está sendo criado por JS e tendo sua cor de fundo definida, então ele também pode ter sua cor definida.

A string JS é como fornecida na pergunta com a adição de uma configuração para a cor:

'<div style = "background-color:' + bgColor + '; color:' + textBlackOrWhite (bgColor) + ';"'

Aqui está um trecho que define a função. O snippet também permite que você escolha uma cor de fundo e então define uma cor que (aproximadamente) depende do 'brilho' do fundo. Consulte as perguntas do SO mencionadas aqui para uma discussão mais aprofundada, pois a percepção humana das cores é um tópico difícil.

//from https://stackoverflow.com/questions/5623838/rgb-to-hex-and-hex-to-rgb
function textBlackOrWhite(hex) {
  // Expand shorthand form (e.g. "03F") to full form (e.g. "0033FF")
  var shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i; hex = hex.replace(shorthandRegex, function(m, r, g, b) { return r + r + g + g + b + b; }); let result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);//also checks we have a well-formed hex number
  
//from https://stackoverflow.com/questions/596216 the answer by @FranciPenov which gives an approximation: (R+R+G+G+G+B)/6 
  let itsbright = function () { return ((2*parseInt(result[1], 16) + 3*parseInt(result[2], 16) + parseInt(result[3], 16))/6)>127; }
  return result ? (itsbright()) ? '#000000' : '#ffffff' : '#000000';//falls back onto black if bgColor was not a well-formed 3 or 6 digit hex color
}
<div id="div" style="font-family: monospace; box-sizing: border-box; margin: 0; padding: 40px 0; width: 100px; height: 100px; border-style: solid; border-radius: 50%; background-color: black; color: white;text-align:center;">#ffffff</div>
Click to choose background color: <input id="input" placeholder='#00000' type='color' value='#000000'/>
<button onclick="let d = document.getElementById('div'); let i = document.getElementById('input'); d.innerHTML = i.value; d.style.backgroundColor = i.value; d.style.color = textBlackOrWhite(i.value);">Submit</button>

1 Rounin Nov 14 2020 at 17:43

Desejo definir a cor do texto automaticamente com base na luminosidade do fundo para preto ou branco.

Eu reconheço que esta é uma abordagem diferente do que você está pedindo, mas uma abordagem somente CSS para ter texto legível universalmente, independentemente de background-colorter whitetexto com blackcontorno (ou vice-versa).

Você pode usar 4 sombras de texto para o contorno:

text-shadow: 1px 1px rgb(0, 0, 0), -1px 1px rgb(0, 0, 0), -1px -1px rgb(0, 0, 0), 1px -1px rgb(0, 0, 0);

Exemplo de Trabalho

const divs = [...document.getElementsByTagName('div')];

for (div of divs) {

  let redValue = Math.floor(Math.random() * 255);
  let greenValue = Math.floor(Math.random() * 255);
  let blueValue = Math.floor(Math.random() * 255);
  
  div.style.backgroundColor = `rgb(${redValue}, ${greenValue}, ${blueValue})`;
}
div {
  float: left;
  width: 180px;
  height: 40px;
  margin: 0 6px 6px 0;
  line-height: 40px;
  color: rgb(255, 255, 255);
  font-size: 32px;
  text-align: center;
  text-shadow: 1px 1px rgb(0, 0, 0), -1px 1px rgb(0, 0, 0), -1px -1px rgb(0, 0, 0), 1px -1px rgb(0, 0, 0);
  background-color: yellow;
}
<div>Sample Text</div>
<div>Sample Text</div>
<div>Sample Text</div>
<div>Sample Text</div>
<div>Sample Text</div>
<div>Sample Text</div>
<div>Sample Text</div>
<div>Sample Text</div>
<div>Sample Text</div>
<div>Sample Text</div>
<div>Sample Text</div>
<div>Sample Text</div>