【问题标题】:Why does HTML think “chucknorris” is a color?为什么 HTML 认为“chucknorris”是一种颜色?
【发布时间】:2017-11-20 00:30:11
【问题描述】:

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

例如:

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

...在所有浏览器和平台上生成具有红色背景的文档。

另一方面,chucknorr 产生黄色背景

这是怎么回事?

【问题讨论】:

标签: html browser background-color


【解决方案1】:

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

ChuCknorris 转换为 c00c0000000。此时,浏览器会将字符串分成三个相等的部分,分别表示 RedGreenBlue 值: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>

【讨论】:

  • You might consider editing your answer, because the &lt;font&gt; element is hereby obsolete by HTML5.
【解决方案2】:

这是网景时代的遗留物:

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

来自博文A little rant about Microsoft Internet Explorer's color parsing,其中详细介绍了它,包括不同长度的颜色值等。

如果我们依次应用博文中的规则,我们会得到以下信息:

  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" 时,我最初遇到了这个问题,而且,它是棕色的。

【讨论】:

  • 有趣的事实 - 根据这个逻辑,那么 test 会给你一辆加州出租车的颜色! Netscape 的总部位于加利福尼亚州的山景城!
  • 有趣的事实 #2 - CharmeleonIvysaurSquirtle 将分别产生红色、绿色和蓝色。
  • 这里的想法是,如果您是某个未来社会的程序员,每个颜色使用 16 位,现在的浏览器会将它们截断为最重要的 8 位?
【解决方案3】:

WHATWG HTML 规范具有解析旧颜色值的准确算法: https://html.spec.whatwg.org/multipage/infrastructure.html#rules-for-parsing-a-legacy-colour-value.

用于解析颜色字符串的 Netscape Classic 代码是开源的: https://github.com/zii/netscape/blob/master/lib/layout/layimage.c#L150.

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

更新:此代码与规范中定义的不完全匹配,但唯一的区别是几行代码。我认为是 these lines 添加的(在 Netscape 中):

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

【讨论】:

    【解决方案4】:

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

    规则说明:

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

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

    • LuckyCharms
    • Luck
    • LuckBeALady
    • LuckBeALadyTonight
    • GangnamStyle

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

    【讨论】:

      【解决方案5】:

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

      1. chucknorris 中,除了 c 之外的所有内容都不是有效的十六进制值。
      2. 所以它被转换为c00c00000000
      3. 变成#c00000,一种红色。

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

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

      轻点

      Chuck Norris 不符合网络标准。网络标准符合 给他。 #BADA55

      【讨论】:

      • 我已经在 Firefox 26 上对此进行了测试,它可以工作,所以我不相信您的参考是正确的。同样从以下链接scrappy-do.blogspot.com/2004/08/… 你会看到这是从 Netscape 继承的,所以它不是 Internet Explorer 或 Opera 特有的!
      • 我是来开玩笑的 :D 谢谢!
      【解决方案6】:

      答案:

      • 浏览器将尝试将 chucknorris 转换为十六进制值。
      • 由于cchucknorris 中唯一有效的十六进制字符,该值变为:c00c000000000 表示所有无效值)。
      • 然后浏览器将结果分为 3 组:Red = c00cGreen = 0000Blue = 0000
      • 由于 html 背景的有效十六进制值仅包含每种颜色类型(rgb)的 2 位数字,最后 2每个组中的数字都被截断,留下一个 rgb 值 c00000,这是一种砖红色调。

      【讨论】:

        【解决方案7】:

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

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

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

        现在它们除以 3 得到 RGB(red, green, blue)...R: c00c, G: 0000, B:0000...

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

        所以真正的结果是:

        bgcolor="#c00000";
        

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

        【讨论】:

          【解决方案8】:

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

          因为 A、B、C、D、E 和 F 是 characters in hexadecimal

          浏览器将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

          最后,在网络浏览器中显示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>

          【讨论】:

            【解决方案9】:

            rules for parsing colors on legacy attributes 涉及的步骤比现有答案中提到的步骤多。将部分截断为 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>

            【讨论】:

              【解决方案10】:

              用简单的话回答:

              简短的回答是,HTML 渴望取悦并且基本上会接受你给它的任何东西。 HTML 是围绕故意忽略格式错误的输入而构建的。

              整体概念:

              HTML 接受非十六进制字符为 0,所以我们都知道 0-9 定义 0 到 9,然后 A-F 定义 10 到 15。所以有很多词可以是像“chucknorris”这样的深血红色。同样“stevensegal”表示绿色。

              显示意想不到的颜色: 如果您在 bgcolor 中输入包含一些十六进制字符的任何单词,那么该字符将向您显示一些您从未想象过的意想不到的颜色。它的工作原理类似于 #F00F00 等于 #FotFot。但这仅适用于 table 标记内的 bgcolor ,其他任何地方都没有。

              演示:

              <style>
                      h1 {
                          color: green;
                      }
                  </style>
              <center>
                      <h1>Why HTML thinks Chucknorris as color?</h1>
                      <p>
                        Here is the implementation...!!!
                      </p>
                      <table>
                          It is the color of:
                          <td bgcolor="chucknorris">
                            chucknorris
                          </td>
                          
                      </table>
                  </center>

              【讨论】:

                猜你喜欢
                • 2011-06-14
                • 2017-08-07
                相关资源
                最近更新 更多