为什么HTML认为“chucknorris”是一种颜色?

8732
为什么在 HTML 中,输入某些随机字符串作为背景颜色时会产生颜色?
例如,bgcolor="chucknorris" 会产生 红色背景

<body bgcolor="chucknorris"> test </body>

相反,bgcolor="chucknorr"会产生黄色背景

<body bgcolor="chucknorr"> test </body>

这一点在各种不同的浏览器和平台上都是适用的。到底发生了什么?


97
我不得不这样做(因为我怎么能不这样),所以我通过脚本运行了一整本字典,并将其呈现为表格 - 是的,whippersnappers 绝对是一个有效的颜色代码。 - mindplay.dk
2
这个问题被提及在 CoRecursive 的播客中,在 2022-01 episode 的第34分35秒左右。尽管参考的答案和评论似乎不在这里(包括已删除的答案)。这就是这个问题(除非有另一个使用相同措辞的问题)。 - Peter Mortensen
2
@mindplay.dk 目前出现了无尽的依赖错误。 - Hashim Aziz
1
说清楚一点,查克·诺里斯用回旋踢把颜色踢到了你的屏幕上。 - undefined
9个回答

8067

这是从网景时代延续下来的:

缺少数字被视为0[...]。不正确的数字仅被解释为0。例如,值#F0F0F0、F0F0F0、F0F0F、#FxFxFx和FxFxFx都是相同的。

这来自于博客文章微软Internet Explorer颜色解析的小抱怨,该文章详细介绍了它,包括颜色值的不同长度等。

如果我们按照博客文章中的规则依次应用,我们得到以下结果:

  1. Replace all nonvalid hexadecimal characters with 0’s:

    chucknorris becomes c00c0000000
    
  2. Pad out to the next total number of characters divisible by 3 (11 → 12):

    c00c 0000 0000
    
  3. Split into three equal groups, with each component representing the corresponding colour component of an RGB colour:

    RGB (c00c, 0000, 0000)
    
  4. Truncate each of the arguments from the right down to two characters.

最终,得到以下结果:

RGB (c0, 00, 00) = #C00000 or RGB(192, 0, 0)

这里有一个例子展示了bgcolor属性的作用,生成这个“惊人”的颜色样本:

<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>

这也回答了问题的另一部分:为什么bgcolor="chucknorr"会产生黄色?好吧,如果我们应用规则,那么字符串就是:
c00c00000 => c00 c00 000 => c0 c0 00 [RGB(192, 192, 0)]

这会产生一种浅黄金色。由于字符串最初有9个字符,这次我们保留第二个'C',因此它最终以颜色值的形式出现。
我最初遇到这个问题是因为有人指出你可以使用color="crap",结果就是棕色。

84
有趣的事实-按照这个逻辑,<body bgcolor="cabs"> test </body>将给你加州出租车的颜色!Netscape的总部位于加利福尼亚州的山景城! - WMRamadan
73
有趣的事实 #2 - 火龙妙蛙草杰尼龟 分别会产生红色、绿色和蓝色。 - Leaf
7
这里的想法是,如果你来自一个使用每种颜色16位的未来社会,并在现今的浏览器中运行程序,那么浏览器将会截断其余的8位,只保留最重要的8位。 - warmCabin
@warmCabin 对于正确的颜色,至少我知道在现代浏览器中可以使用每个颜色超过2个十六进制数字。 - mousetail
2
有一个重要的规则缺失:如果所有组件的第一个字符都是“0”,则删除该字符,然后开始截断为长度为两个字符。此算法的所有规则均列在此处: https://html.spec.whatwg.org/multipage/common-microsyntaxes.html#colours - n.r.

1192
抱歉我不同意,根据Yuhong Bao张贴的传统颜色值解析规则,chucknorris并不等于#CC0000,而是等于#C00000,这是一种非常相似但略有不同的红色。我使用了Firefox ColorZilla add-on验证了这一点。
规则如下:
  • 通过添加0使字符串长度成为3的倍数:chucknorris0
  • 将字符串分成三个等长的字符串:chuc knor ris0
  • 截取每个字符串的两个字符:ch kn ri
  • 保留十六进制值,并在必要时添加0:C0 00 00

我能够使用这些规则正确解释以下字符串:

  • 幸运符号
  • 运气
  • 女士,今晚好运降临
  • 女士,今晚好运降临
  • 江南Style

最初回答者说颜色是#CC0000,后来编辑了他们的回答以包含更正。


538

原因是浏览器不理解它,尝试将其翻译为它能理解的内容,这种情况下是一个十六进制值!...

chucknorrisc 开头,这是十六进制中被识别的字符,同时将所有无法识别的字符转换为 0

因此,chucknorris 的十六进制格式变为:c00c00000000,所有其他字符都变为 0,而 c 保持不变...

现在它们被3整除 用于 RGB(红色,绿色,蓝色)... R: c00c, G: 0000, B:0000...

但我们知道,RGB的有效十六进制只有2个字符,意味着 R: c0, G: 00, B:00

所以真正的结果是:

bgcolor="#c00000";

我还在这张图片中添加了步骤,供你快速参考:

为什么HTML认为“chucknorris”是颜色?


472
大多数浏览器会忽略颜色字符串中的任何非十六进制数值,并将非十六进制数字替换为零。"ChuCknorris" 转换成 "c00c0000000"。此时,浏览器将字符串分为三个相等的部分,表示红、绿和蓝的值:"c00c 0000 0000"。每个部分中多余的位将被忽略,最终结果是 "#c00000",它是一种略带红色的颜色。请注意,这不适用于 CSS 颜色解析,因为它遵循 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>


10
你可以考虑编辑你的回答,因为在HTML5中,<font>元素已经过时了。 - Someone_who_likes_SE

395
浏览器试图将chucknorris转换为十六进制颜色代码,因为它不是有效值。
  1. chucknorris中,除了c之外的所有内容都不是有效的十六进制值。
  2. 所以它被转换为c00c00000000
  3. 这被分成三组,R G B(如果不是3的倍数,则在结尾处填充0)
  4. 从每个组中只选择两个字符,因为这是允许的。
  5. 最终变成#c00000,一种红色的色调。
这似乎主要是Internet Explorer和Opera(12)的问题,因为Chrome(31)和Firefox(26)都会忽略这个问题。

类似地,Rajnikanth(印度Chuck Noris)变成黑色阴影:

0a00 00a0 0000 => #0a0000

0a00 00a0 0000 => #0a0000

说句轻松的话

查克·诺里斯不遵守Web标准。Web标准符合他。#BADA55


1
我已在Firefox 26上进行了测试,它可以正常工作,因此我不相信你的参考资料是正确的。另外,从以下链接http://scrappy-do.blogspot.com/2004/08/little-rant-about-microsoft-internet.html中,你会看到这是从Netscape继承而来的,因此它不仅适用于Internet Explorer或Opera! - WMRamadan

263

WHATWG HTML规范给出了解析传统颜色值的确切算法

Netscape Classic用于解析颜色字符串的代码是开源的:netscape/lib/layout/layimage.c

例如,注意每个字符被解析为十六进制数字,然后移位到32位整数中,没有检查溢出。只有八个十六进制数字适合32位整数,这就是为什么只考虑最后8个字符的原因。在将十六进制数字解析为32位整数之后,通过将它们除以16直到它们适合于8位来将它们截断为8位整数,这就是为什么忽略前导零的原因。

这段代码与规范中定义的内容不完全匹配,但唯一的区别是少了几行代码。我认为这是在Netscape 4中添加的这些行

if (bytes_per_val > 4)
{
    bytes_per_val = 4;
}

第一个链接(实际上)已经失效。似乎没有一个标题为“解析传统颜色值的规则”(或类似标题)的部分。虽然有一个类似的页面锚点,“legacy-extract-an-encoding”。 - Peter Mortensen
这可能是正确的链接:https://html.spec.whatwg.org/multipage/common-microsyntaxes.html#colours - n.r.

234
  • 浏览器会尝试将 chucknorris 转换为十六进制值。
  • 由于 chucknorris 中只有 c 是有效的十六进制字符,所以该值变成了:c00c00000000所有无效值都变成了 0)。
  • 浏览器然后将结果分成三组:红色 = c00c绿色 = 0000蓝色 = 0000
  • 由于 HTML 背景的有效十六进制值每种颜色类型(rgb)只包含两个数字,因此从每个组中截取掉最后两个数字,留下 RGB 值为 c00000,这是一种砖红色调的颜色。

64

chucknorrisc开头,浏览器将其读入十六进制值。

因为A、B、C、D、E和F是十六进制字符

浏览器将chucknorris转换为十六进制值C00C00000000

然后将C00C00000000十六进制值转换为RGB格式(除以3):

C00C00000000 ⇒ R:C00C, G:0000, B:0000

浏览器只需要两个数字来表示颜色:

R:C00C, G:0000, B:0000 ⇒ R:C0, G:00, B:00 ⇒ C00000

最后,在Web浏览器中显示bgcolor = C00000

以下是一个演示例子:

<table>
  <tr>
    <td bgcolor="chucknorris" cellpadding="10" width="150" align="center">chucknorris</td>
    <td bgcolor="c00c00000000" cellpadding="10" width="150" align="center">c00c00000000</td>
    <td bgcolor="c00000" cellpadding="10" width="150" align="center">c00000</td>
  </tr>
</table>


49

解析遗留属性的颜色规则与现有答案中提到的步骤不同,额外涉及一些步骤。其中截取组件至2位数的部分描述如下:

  1. 舍弃除最后8个字符以外的所有字符
  2. 只要所有组件都有前导零,就逐个舍弃前导零
  3. 舍弃除前2个字符以外的所有字符

以下是一些示例:

oooFoooFoooF
000F 000F 000F                <- replace, pad and chunk
0F 0F 0F                      <- leading zeros truncated
0F 0F 0F                      <- truncated to 2 characters from right

oooFooFFoFFF
000F 00FF 0FFF                <- replace, pad and chunk
00F 0FF FFF                   <- leading zeros truncated
00 0F FF                      <- truncated to 2 characters from right

ABCooooooABCooooooABCoooooo
ABC000000 ABC000000 ABC000000 <- replace, pad and chunk
BC000000 BC000000 BC000000    <- truncated to 8 characters from left
BC BC BC                      <- truncated to 2 characters from right

AoCooooooAoCooooooAoCoooooo
A0C000000 A0C000000 A0C000000 <- replace, pad and chunk
0C000000 0C000000 0C000000    <- truncated to 8 characters from left
C000000 C000000 C000000       <- leading zeros truncated
C0 C0 C0                      <- truncated to 2 characters from right

以下是该算法的部分实现。它不处理错误或用户输入有效颜色的情况。

function parseColor(input) {
  // todo: return error if input is ""
  input = input.trim();
  // todo: return error if input is "transparent"
  // todo: return corresponding #rrggbb if input is a named color
  // todo: return #rrggbb if input matches #rgb
  // todo: replace unicode code points greater than U+FFFF with 00
  if (input.length > 128) {
    input = input.slice(0, 128);
  }
  if (input.charAt(0) === "#") {
    input = input.slice(1);
  }
  input = input.replace(/[^0-9A-Fa-f]/g, "0");
  while (input.length === 0 || input.length % 3 > 0) {
    input += "0";
  }
  var r = input.slice(0, input.length / 3);
  var g = input.slice(input.length / 3, input.length * 2 / 3);
  var b = input.slice(input.length * 2 / 3);
  if (r.length > 8) {
    r = r.slice(-8);
    g = g.slice(-8);
    b = b.slice(-8);
  }
  while (r.length > 2 && r.charAt(0) === "0" && g.charAt(0) === "0" && b.charAt(0) === "0") {
    r = r.slice(1);
    g = g.slice(1);
    b = b.slice(1);
  }
  if (r.length > 2) {
    r = r.slice(0, 2);
    g = g.slice(0, 2);
    b = b.slice(0, 2);
  }
  return "#" + r.padStart(2, "0") + g.padStart(2, "0") + b.padStart(2, "0");
}

$(function() {
  $("#input").on("change", function() {
    var input = $(this).val();
    var color = parseColor(input);
    var $cells = $("#result tbody td");
    $cells.eq(0).attr("bgcolor", input);
    $cells.eq(1).attr("bgcolor", color);

    var color1 = $cells.eq(0).css("background-color");
    var color2 = $cells.eq(1).css("background-color");
    $cells.eq(2).empty().append("bgcolor: " + input, "<br>", "getComputedStyle: " + color1);
    $cells.eq(3).empty().append("bgcolor: " + color, "<br>", "getComputedStyle: " + color2);
  });
});
body { font: medium monospace; }
input { width: 20em; }
table { table-layout: fixed; width: 100%; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>

<p><input id="input" placeholder="Enter color e.g. chucknorris"></p>
<table id="result">
  <thead>
    <tr>
      <th>Left Color</th>
      <th>Right Color</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
    </tr>
    <tr>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
    </tr>
  </tbody>
</table>


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接