为什么超文本标记语言认为“chucknorris”是一种颜色?

为什么某些随机字符串在超文本标记语言中作为背景色输入时会产生颜色?

例如,bgcolor="chucknorris"产生红色背景

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

Conversely, bgcolor="chucknorr" produces a yellow background:

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

这适用于各种浏览器和平台。这是怎么回事?

726752 次浏览

大多数浏览器会简单地忽略颜色字符串中的任何十六进制值,用零替换非十六进制数字。

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>

这是来自Netscape天的保留:

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

它来自博客文章关于Microsoft Internet Explorer颜色解析的一点咆哮,详细介绍了它,包括不同长度的颜色值等。

如果我们从博客文章中依次应用规则,我们会得到以下内容:

  1. 将所有无效的十六进制字符替换为0:

    chucknorris becomes c00c0000000
  2. 填充到下一个可被3整除的字符总数(11→12):

    c00c 0000 0000
  3. 分成三个相等的组,每个分量代表RGB颜色的相应颜色分量:

    RGB (c00c, 0000, 0000)
  4. 将每个参数从右向下截断为两个字符。

最后,给出以下结果:

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",嗯,它是棕色的。

用于解析旧颜色值的WHATWG超文本标记语言规范具有精确的算法

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

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

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

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

很抱歉,我不同意,但是根据解析传统颜色值发表者:YuhongBag的规则,chucknorris不要等于#CC0000,而等于#C00000,一种非常相似但略有不同的红色色调。我用Firefox Color Zilla插件来验证这一点。

规则规定:

  • 通过添加0使字符串的长度为3的倍数:chucknorris0
  • 将字符串分成三个长度相等的字符串:chuc knor ris0
  • 将每个字符串截断为两个字符:ch kn ri
  • 保留十六进制值,并在必要时添加0:C0 00 00

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

  • LuckyCharms
  • Luck
  • LuckBeALady
  • LuckBeALadyTonight
  • GangnamStyle

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

浏览器试图将chucknorris转换为十六进制颜色代码,因为它不是一个有效的值。

  1. chucknorris中,除了#1之外的所有内容都不是有效的十六进制值。
  2. 所以它被转换为#0
  3. 这被分成3组,R G B(如果不是3的倍数,则在末尾垫0)
  4. 每组中只有两个字符被选为允许的字符。
  5. 它最终变成了#c00000,一种红色。

这似乎主要是Internet ExplorerOpera(12)的问题,因为Chrome(31)和Firefox(26)都忽略了这一点。

附注:括号中的数字是我测试的浏览器版本。

类似地,rajnikanth(印度人Chuck Noris)与黑色的阴影交谈:

0a00 00a0 0000=>#0a0000

在一个轻松的音符

Chuck Norris不符合Web标准。Web标准符合#BADA55

  • 浏览器将尝试将chucknorris转换为十六进制值。
  • 由于cchucknorris中唯一有效的十六进制字符,因此值变成:c00c000000000表示所有无效的值)。
  • 然后浏览器将结果分为三组:Red = c00cGreen = 0000Blue = 0000
  • 由于超文本标记语言背景的有效十六进制值仅包含每个颜色类型(rgb)的两位数字,因此最后两位数字将从每个组中截断,留下RGB值c00000,这是砖红色色调。

原因是浏览器可以不明白它并尝试以某种方式将其转换为它可以理解的内容,在这种情况下转换为十六进制值!…

chucknorrisc开头,这是十六进制中可识别的字符,它也将所有未识别的字符转换为0

所以十六进制格式的chucknorris变成:c00c00000000,所有其他字符变成0c保持原样…

现在他们被3除以RGB(红色,绿色,蓝色)…R: c00c, G: 0000, B:0000

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

所以真正的结果是:

bgcolor="#c00000";

我还添加了图像中的步骤作为快速参考:

为什么超文本标记语言认为

#0#1开始,浏览器将其读入十六进制值。

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

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

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

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

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

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

最后,在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>

在遗留属性上解析颜色的规则涉及比现有答案中提到的更多步骤。将组件截断为2位部分描述为:

  1. 丢弃除最后8个字符以外的所有字符
  2. 丢弃前导零一个接一个只要所有组件都有一个前导零
  3. 丢弃除前2个字符外的所有字符

一些例子:

oooFoooFoooF000F 000F 000F                <- replace, pad and chunk0F 0F 0F                      <- leading zeros truncated0F 0F 0F                      <- truncated to 2 characters from right
oooFooFFoFFF000F 00FF 0FFF                <- replace, pad and chunk00F 0FF FFF                   <- leading zeros truncated00 0F FF                      <- truncated to 2 characters from right
ABCooooooABCooooooABCooooooABC000000 ABC000000 ABC000000 <- replace, pad and chunkBC000000 BC000000 BC000000    <- truncated to 8 characters from leftBC BC BC                      <- truncated to 2 characters from right
AoCooooooAoCooooooAoCooooooA0C000000 A0C000000 A0C000000 <- replace, pad and chunk0C000000 0C000000 0C000000    <- truncated to 8 characters from leftC000000 C000000 C000000       <- leading zeros truncatedC0 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 00if (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>