¿Cómo es que ciertas cadenas aleatorias producen colores cuando se introducen como colores de fondo en HTML? Por ejemplo:
<body bgcolor="chucknorris"> test </body>
...produce un documento con un fondo rojo en todos los navegadores y plataformas.
Curiosamente, mientras que chucknorri
produce un fondo rojo también, chucknorr
produce un fondo amarillo.
¿Qué ocurre aquí?
Es un remanente de los días de Netscape:
Los dígitos que faltan se tratan como 0[...]. Un dígito incorrecto se interpreta simplemente como 0. Por ejemplo, los valores #F0F0F0, F0F0F0, F0F0F, #FxFxFx y FxFxFx son todos iguales.
Es de la entrada del blog A little rant about Microsoft Internet Explorer's color parsing que lo cubre con gran detalle, incluyendo las diferentes longitudes de los valores de color, etc.
Si aplicamos las reglas a su vez de la entrada del blog, obtenemos lo siguiente:
Reemplazar todos los caracteres hexadecimales no válidos por 0's
chucknorris se convierte en c00c0000000
Rellenar hasta el siguiente número total de caracteres divisible por 3 (11 -> 12)
c00c 0000 0000
Dividir en tres grupos iguales, cada uno de los cuales representa el componente cromático correspondiente de un color RGB:
RGB (c00c, 0000, 0000)
Truncar cada uno de los argumentos de la derecha hasta dos caracteres
Lo que da el siguiente resultado:
RGB (c0, 00, 00) = #C00000 or RGB(192, 0, 0)
Aquí hay un ejemplo que demuestra el atributo bgcolor
en acción, para producir esta "increíble" muestra de color:
<table>
<tr>
<td bgcolor="chucknorris" cellpadding="8" width="100" align="center">chuck norris</td>
<td bgcolor="mrt" cellpadding="8" width="100" align="center" style="color:#ffffff">Mr T</td>
<td bgcolor="ninjaturtle" cellpadding="8" width="100" align="center" style="color:#ffffff">ninjaturtle</td>
</tr>
<tr>
<td bgcolor="sick" cellpadding="8" width="100" align="center">sick</td>
<td bgcolor="crap" cellpadding="8" width="100" align="center">crap</td>
<td bgcolor="grass" cellpadding="8" width="100" align="center">grass</td>
</tr>
</table>
Esto también responde a la otra parte de la pregunta; ¿por qué bgcolor="chucknorr"
produce un color amarillo? Bueno, si aplicamos las reglas, la cadena es:
c00c00000 => c00 c00 000 => c0 c0 00 [RGB(192, 192, 0)]
Lo que da un color amarillo dorado claro. Como la cadena empieza con 9 caracteres, esta vez nos quedamos con la segunda C, por lo que acaba en el valor final del color.
Originalmente me encontré con esto cuando alguien señaló que se podía hacer color="crap"
y, bueno, sale marrón.
La mayoría de los navegadores simplemente ignorarán cualquier valor NO hexadecimal en su cadena de color, sustituyendo los dígitos no hexadecimales por ceros.
El color "ChuCknorris" se traduce en "c00c0000000". En este punto, el navegador dividirá la cadena en tres secciones iguales, indicando los valores Rojo, Verde y Azul: c00c 0000 0000
. Los bits extra en cada sección serán ignorados, lo que hace que el resultado final sea #c00000
que es un color rojizo.
Tenga en cuenta que esto no se aplica al análisis sintáctico del color de CSS, que sigue el estándar de CSS.
<p><font color='chucknorris'>Redish</font></p>
<p><font color='#c00000'>Same as above</font></p>
<p><span style="color: chucknorris">Black</span></p>
La especificación WHATWG HTML tiene el algoritmo exacto para analizar un valor de color heredado: https://html.spec.whatwg.org/multipage/infrastructure.html#rules-for-parsing-a-legacy-colour-value
El código que Netscape Classic utiliza para analizar las cadenas de color es de código abierto: https://dxr.mozilla.org/classic/source/lib/layout/layimage.c#155
Por ejemplo, observe que cada carácter es analizado como un dígito hexadecimal y luego es desplazado a un entero de 32 bits sin comprobar el desbordamiento. Sólo ocho dígitos hexadecimales caben en un entero de 32 bits, por lo que sólo se consideran los últimos 8 caracteres. Después de analizar los dígitos hexadecimales en enteros de 32 bits, se truncan en enteros de 8 bits dividiéndolos por 16 hasta que caben en 8 bits, razón por la cual se ignoran los ceros a la izquierda.
Actualización: este código no coincide exactamente con lo que se define en la especificación, pero la única diferencia son unas pocas líneas de código. Creo que son estas líneas las que se añadieron (en Netscape 4):
if (bytes_per_val > 4)
{
bytes_per_val = 4;
}