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

Why does HTML think “chucknorris” is a color?

提问人:user456584 提问时间:11/30/2011 最后编辑:Mateen Ulhaquser456584 更新时间:2/22/2023 访问量:744771

问:

为什么某些随机字符串在 HTML 中作为背景颜色输入时会产生颜色?

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

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

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

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

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

HTML 浏览器 背景颜色

评论

97赞 mindplay.dk 12/10/2021
我不得不这样做(因为我怎么能不这样做),所以我通过脚本运行了一整本字典并将其呈现为表格 - 是的,这绝对是一个有效的颜色代码。whippersnappers
2赞 Peter Mortensen 1/27/2022
这个问题在 2022-01 年的播客 CoRecursive 中被引用,大约在 34 分 35 秒。虽然引用的答案和评论似乎在这里(包括删除的答案)。就是这个问题(除非有另一个措辞相同的问题)。
2赞 Hashim Aziz 3/2/2022
@mindplay.dk 目前失败,出现无穷无尽的依赖项错误。
1赞 tdelaney 9/9/2023
需要明确的是,查克·诺里斯(Chuck Norris)的圆屋将颜色踢到了屏幕上。

答:

472赞 Mike Christensen 11/30/2011 #1

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

ChuCknorris转换为 .此时,浏览器会将字符串分成三个相等的部分,分别表示红色绿色蓝色值:.每个部分中多余的位将被忽略,这使得最终结果呈红色。c00c0000000c00c 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赞 idk wut to put here 5/9/2021
You might consider editing your answer, because the <font> element is hereby obsolete by HTML5.
8067赞 dash 12/1/2011 #2

这是 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"

评论

84赞 WMRamadan 4/21/2021
有趣的事实 - 根据这个逻辑,那么 <body bgcolor=“cabs”>测试</body>会给你加州出租车的颜色!Netscape 的总部位于加利福尼亚州山景城!
73赞 Leaf 11/14/2021
有趣的事实 #2 - , , 将分别产生红色、绿色和蓝色。CharmeleonIvysaurSquirtle
7赞 warmCabin 12/10/2021
这里的想法是,如果你是来自某个未来社会的程序员,每种颜色使用 16 位,现在的浏览器会将它们截断到最高有效的 8 位?
0赞 mousetail 8/2/2022
@warmCabin 至少我知道在现代浏览器中每种颜色可以使用超过 2 个十六进制数字来获得正确的颜色
2赞 n.r. 4/27/2023
缺少一条重要规则:如果所有组件的第一个字符都是“0”,则删除该字符,然后开始截断为两个长度。此处列出了此算法的所有规则:html.spec.whatwg.org/multipage/...
263赞 Yuhong Bao 9/28/2012 #3

WHATWG HTML 规范具有用于解析传统颜色值的确切算法。

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

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

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

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

评论

0赞 Peter Mortensen 12/1/2022
第一个链接(实际上)被破坏了。似乎没有一个部分的标题为“解析旧颜色值的规则”(或类似)。虽然有一个类似的页面锚点,”legacy-extract-an-encoding"
0赞 n.r. 4/27/2023
这可能是正确的链接:html.spec.whatwg.org/multipage/...
1192赞 Jeremy Goodell 10/18/2012 #4

很抱歉不同意,但根据Yuhong Bao发布的传统颜色值的解析规则,并不等同于,而是等同于,一种非常相似但略有不同的红色色调。我使用Firefox ColorZilla插件来验证这一点。chucknorris#CC0000#C00000

规则规定:

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

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

  • LuckyCharms
  • Luck
  • LuckBeALady
  • LuckBeALadyTonight
  • GangnamStyle

说颜色 #CC0000 的原始回答者已经编辑了他们的答案以包括更正。

395赞 aWebDeveloper 11/30/2013 #5

浏览器正在尝试转换为十六进制颜色代码,因为它不是有效值。chucknorris

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

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

P.S. 括号中的数字是我测试过的浏览器版本。

同样,拉杰尼坎特(印第安人查克·诺里斯)对着黑色的阴影说话:

0a00 00a0 0000 => #0a0000

在更轻松的音符上

查克·诺里斯(Chuck Norris)不符合网络标准。符合 Web 标准 给他。#BADA55

评论

1赞 WMRamadan 4/21/2021
我已经在 Firefox 26 上对此进行了测试,它可以工作,所以我不相信您的参考是正确的。同样从以下链接 scrappy-do.blogspot.com/2004/08/...您将看到它是从 Netscape 继承的,因此它不是特定于 Internet Explorer 或 Opera 的!
234赞 Webeng 5/24/2016 #6
  • 浏览器将尝试将 chucknorris 转换为十六进制值。
  • 由于是 chucknorris 中唯一有效的十六进制字符,因此该值将变为:(对于所有无效的值,为 0)。cc00c00000000
  • 然后,浏览器将结果分为三组:、、。Red = c00cGreen = 0000Blue = 0000
  • 由于 HTML 背景的有效十六进制值仅包含每种颜色类型(rgb)的两个数字,因此每个组的最后两位数字将被截断,留下一个 RGB 值,其 RGB 值是砖红色调的颜色。c00000
539赞 Alireza 7/1/2017 #7

原因是浏览器无法理解它,并试图以某种方式将其转换为它可以理解的内容,在这种情况下是十六进制值...

chucknorris以十六进制中可识别的字符开头,同时将所有无法识别的字符转换为!c0

因此,在十六进制格式中变为:,所有其他字符都成为并保留在原地......chucknorrisc00c000000000c

现在它们被除以 3 表示(红色、绿色、蓝色)......RGBR: c00c, G: 0000, B:0000

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

所以真正的结果是:

bgcolor="#c00000";

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

Why does HTML think “chucknorris” is a colour?

64赞 sameera lakshitha 4/18/2018 #8

ChucknorrisC 开头,浏览器将其读取为十六进制值。

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

浏览器将转换为十六进制值 。chucknorrisC00C00000000

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

C00C00000000R:C00C, G:0000, B:0000

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

R:C00C, G:0000, B:0000⇒ ⇒R: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>

49赞 Salman A 10/17/2018 #9

解析旧属性颜色的规则涉及比现有答案中提到的步骤更多的步骤。截断分量为 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>