¿Cómo decidir el color de fuente en blanco o negro según el color de fondo?

Resuelto DJPB asked hace 14 años • 27 respuestas

Quiero mostrar algunas imágenes como este ejemplo.texto alternativo

El color de relleno lo decide un campo en la base de datos con el color en hexadecimal (ej:ClassX -> Color: #66FFFF). Ahora, quiero mostrar datos encima de un relleno con el color seleccionado (como en la imagen de arriba) pero necesito saber si el color es oscuro o claro para saber si las palabras deben estar en blanco o negro. ¿Hay alguna manera? gracias

DJPB avatar Oct 15 '10 20:10 DJPB
Aceptado

Basándome en mi respuesta a una pregunta similar .

Debes dividir el código hexadecimal en 3 partes para obtener las intensidades individuales de rojo, verde y azul. Cada 2 dígitos del código representa un valor en notación hexadecimal (base 16). No entraré en detalles de la conversión aquí, son fáciles de consultar.

Una vez que tenga las intensidades de los colores individuales, puede determinar la intensidad general del color y elegir el texto correspondiente.

if (red*0.299 + green*0.587 + blue*0.114) > 186 use #000000 else use #ffffff

El umbral de 186 se basa en la teoría, pero se puede ajustar al gusto. Según los comentarios por debajo de un umbral de 150 puede funcionar mejor para usted.


Editar: lo anterior es simple y funciona razonablemente bien, y parece tener buena aceptación aquí en StackOverflow. Sin embargo, uno de los comentarios a continuación muestra que puede llevar al incumplimiento de las pautas del W3C en algunas circunstancias. A continuación obtengo una forma modificada que siempre elige el contraste más alto según las pautas. Si no necesita cumplir con las reglas del W3C, entonces me quedaría con la fórmula más simple anterior. Para obtener una visión interesante de los problemas relacionados con esto, consulte Matemáticas de relación de contraste y problemas visuales relacionados .

La fórmula dada para el contraste en las Recomendaciones del W3C (WCAG 2.0) es (L1 + 0.05) / (L2 + 0.05), donde L1es la luminancia del color más claro y L2es la luminancia del color más oscuro en una escala de 0,0-1,0. La luminancia del negro es 0,0 y la del blanco es 1,0, por lo que sustituir esos valores le permite determinar el que tiene el mayor contraste. Si el contraste del negro es mayor que el contraste del blanco, utilice negro; en caso contrario, utilice blanco. Dada la luminancia del color que estás probando, Lla prueba se vuelve:

if (L + 0.05) / (0.0 + 0.05) > (1.0 + 0.05) / (L + 0.05) use #000000 else use #ffffff

Esto se simplifica algebraicamente a:

if L > sqrt(1.05 * 0.05) - 0.05

O aproximadamente:

if L > 0.179 use #000000 else use #ffffff

Lo único que queda es calcular L. Esa fórmula también se proporciona en las pautas y parece la conversión de sRGB a RGB lineal seguida de la recomendación ITU-R BT.709 para luminancia.

for each c in r,g,b:
    c = c / 255.0
    if c <= 0.04045 then c = c/12.92 else c = ((c+0.055)/1.055) ^ 2.4
L = 0.2126 * r + 0.7152 * g + 0.0722 * b

El umbral de 0,179 no debe cambiarse ya que está vinculado a las directrices del W3C. Si encuentra que los resultados no son de su agrado, pruebe la fórmula más simple anterior.

Mark Ransom avatar Oct 15 '2010 14:10 Mark Ransom

No me atribuyo ningún crédito por este código ya que no es mío, pero lo dejo aquí para que otros lo encuentren rápidamente en el futuro:

Según la respuesta de Mark Ransoms, aquí hay un fragmento de código para la versión simple:

function pickTextColorBasedOnBgColorSimple(bgColor, lightColor, darkColor) {
  var color = (bgColor.charAt(0) === '#') ? bgColor.substring(1, 7) : bgColor;
  var r = parseInt(color.substring(0, 2), 16); // hexToR
  var g = parseInt(color.substring(2, 4), 16); // hexToG
  var b = parseInt(color.substring(4, 6), 16); // hexToB
  return (((r * 0.299) + (g * 0.587) + (b * 0.114)) > 186) ?
    darkColor : lightColor;
}

y aquí está el fragmento de código para la versión avanzada:

function pickTextColorBasedOnBgColorAdvanced(bgColor, lightColor, darkColor) {
  var color = (bgColor.charAt(0) === '#') ? bgColor.substring(1, 7) : bgColor;
  var r = parseInt(color.substring(0, 2), 16); // hexToR
  var g = parseInt(color.substring(2, 4), 16); // hexToG
  var b = parseInt(color.substring(4, 6), 16); // hexToB
  var uicolors = [r / 255, g / 255, b / 255];
  var c = uicolors.map((col) => {
    if (col <= 0.03928) {
      return col / 12.92;
    }
    return Math.pow((col + 0.055) / 1.055, 2.4);
  });
  var L = (0.2126 * c[0]) + (0.7152 * c[1]) + (0.0722 * c[2]);
  return (L > 0.179) ? darkColor : lightColor;
}

Para usarlos simplemente llama al:

var color = '#EEACAE' // this can be any color
pickTextColorBasedOnBgColorSimple(color, '#FFFFFF', '#000000');

Además, gracias Alxy chetstone.

SudoPlz avatar Jan 05 '2017 17:01 SudoPlz

Además de las soluciones aritméticas, también es posible utilizar una red neuronal de IA. La ventaja es que puede adaptarlo a sus propios gustos y necesidades (es decir, el texto blanquecino sobre rojos brillantes y saturados se ve bien y es tan legible como el negro).

Aquí hay una clara demostración de Javascript que ilustra el concepto. También puedes generar tu propia fórmula JS directamente en la demostración.

https://harthur.github.io/brain/

A continuación se muestran algunos gráficos que me ayudaron a comprender el problema . En el primer gráfico, la luminosidad es una constante 128, mientras que el tono y la saturación varían. En el segundo gráfico, la saturación es constante 255, mientras que el tono y la luminosidad varían.

En el primer gráfico, la luminosidad es una constante 128, mientras que el tono y la saturación varían:

La saturación es una constante de 255, mientras que el tono y la luminosidad varían:

Félix Ménard avatar Sep 28 '2017 13:09 Félix Ménard