8842

Why do certain random strings produce colors when entered as background colors in HTML?

For example, bgcolor="chucknorris" produces a red background:

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

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

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

This holds true across various browsers and platforms. What’s going on here?

3
  • 137
    I had to (because how could I not) so I ran an entire dictionary through a script and rendered it out as a table - and yes, whippersnappers is absolutely a valid color code. Commented Dec 10, 2021 at 7:46
  • 4
    This question was referenced in the podcast CoRecursive, in the 2022-01 episode, at about 34 min 35 secs. Though the referenced answers and comments do not seem to be here (incl. in deleted answers). It is this question (unless there is another one with the same phrasing). Commented Jan 26, 2022 at 20:36
  • 3
    @mindplay.dk Currently fails with an endless stream of dependency errors. Commented Mar 1, 2022 at 19:02

9 Answers 9

8169
+50

It’s a holdover from the Netscape days:

Missing digits are treated as 0[...]. An incorrect digit is simply interpreted as 0. For example the values #F0F0F0, F0F0F0, F0F0F, #FxFxFx and FxFxFx are all the same.

It is from the blog post A little rant about Microsoft Internet Explorer's color parsing which covers it in great detail, including varying lengths of color values, etc.

If we apply the rules in turn from the blog post, we get the following:

  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.

Which, finally, gives the following result:

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

Here’s an example demonstrating the bgcolor attribute in action, to produce this “amazing” colour swatch:

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

This also answers the other part of the question: Why does bgcolor="chucknorr" produce a yellow colour? Well, if we apply the rules, the string is:

c00c00000 => c00 c00 000 => c0 c0 00 [RGB(192, 192, 0)]

Which gives a light yellow gold colour. As the string starts off as 9 characters, we keep the second ‘C’ this time around, hence it ends up in the final colour value.

I originally encountered this when someone pointed out that you could do color="crap" and, well, it comes out brown.

5
  • 108
    Fun fact - According to this logic then <body bgcolor="cabs"> test </body> would give you the color of a California Taxi Cab! The HQ of Netscape was in Mountain View, California!
    – WMRamadan
    Commented Apr 21, 2021 at 15:36
  • 105
    Fun fact #2 - Charmeleon, Ivysaur, and Squirtle will produce red, green, and blue colors respectively.
    – Leaf
    Commented Nov 14, 2021 at 12:55
  • 11
    Is the idea here that, if you're a programmer from some future society that uses 16 bits per color, present-day browsers will truncate them to the most significant 8 bits?
    – warmCabin
    Commented Dec 9, 2021 at 18:05
  • @warmCabin For proper colors at least I know it's possible to use more than 2 hex digits per color in modern browsers
    – mousetail
    Commented Aug 2, 2022 at 8:31
  • 3
    There's one important rule missing: If first character of all components is "0", remove that character and then start truncacting to a lenght of two. All rules for this algorithm are listed here: html.spec.whatwg.org/multipage/…
    – n.r.
    Commented Apr 27, 2023 at 7:02
1217

I'm sorry to disagree, but according to the rules for parsing a legacy color value posted by Yuhong Bao, chucknorris does not equate to #CC0000, but rather to #C00000, a very similar but slightly different hue of red. I used the Firefox ColorZilla add-on to verify this.

The rules state:

  • make the string a length that is a multiple of 3 by adding 0s: chucknorris0
  • separate the string into three equal length strings: chuc knor ris0
  • truncate each string to two characters: ch kn ri
  • keep the hex values, and add 0's where necessary: C0 00 00

I was able to use these rules to correctly interpret the following strings:

  • LuckyCharms
  • Luck
  • LuckBeALady
  • LuckBeALadyTonight
  • GangnamStyle

The original answerers who said the color was #CC0000 have since edited their answers to include the correction.

0
567

The reason is the browser can not understand it and try to somehow translate it to what it can understand and in this case into a hexadecimal value!...

chucknorris starts with c which is recognised character in hexadecimal, also it's converting all unrecognised characters into 0!

So chucknorris in hexadecimal format becomes: c00c00000000, all other characters become 0 and c remains where they are...

Now they get divided by 3 for RGB(red, green, blue)... R: c00c, G: 0000, B:0000...

But we know valid hexadecimal for RGB is just 2 characters, means R: c0, G: 00, B:00

So the real result is:

bgcolor="#c00000";

I also added the steps in the image as a quick reference for you:

Why does HTML think “chucknorris” is a colour?

0
478

Most browsers will simply ignore any non-hexadecimal values in your color string, substituting non-hexadecimal digits with zeros.

ChuCknorris translates to c00c0000000. At this point, the browser will divide the string into three equal sections, indicating Red, Green and Blue values: c00c 0000 0000. Extra bits in each section will be ignored, which makes the final result #c00000 which is a reddish color.

Note, this does not apply to CSS color parsing, which follow the CSS standard.

<p><font color='chucknorris'>Redish</font></p>
<p><font color='#c00000'>Same as above</font></p>
<p><span style="color: chucknorris">Black</span></p>

1
  • 13
    You might consider editing your answer, because the <font> element is hereby obsolete by HTML5. Commented May 8, 2021 at 20:53
403

The browser is trying to convert chucknorris into a hexadecimal color code because it’s not a valid value.

  1. In chucknorris, everything except c is not a valid hexadecimal value.
  2. So it gets converted to c00c00000000.
  3. This is split into groups of 3, R G B (pad 0's at the end if not multiple of 3)
  4. Of each group only two characters are picked as that is what's allowed.
  5. It finally becomes #c00000, a shade of red.

This seems to be an issue primarily with Internet  Explorer and Opera (12) as both Chrome (31) and Firefox (26) just ignore this.

P.S. The numbers in brackets are the browser versions I tested on.

Similarly, Rajnikanth (Indian Chuck Noris) converse to a shade of black:

0a00 00a0 0000 => #0a0000

On a lighter note

Chuck Norris doesn’t conform to web standards. Web standards conform to him. #BADA55

1
  • 1
    I have tested this on Firefox 26 and it works so I don't believe your reference is correct. Also from the following link scrappy-do.blogspot.com/2004/08/… you will see that this was inherited from Netscape so it is not specific to Internet Explorer or Opera!
    – WMRamadan
    Commented Apr 21, 2021 at 15:52
266

The WHATWG HTML specification has the exact algorithm for parsing a legacy color value.

The code Netscape Classic used for parsing color strings is open source: netscape/lib/layout/layimage.c.

For example, notice that each character is parsed as a hex digit and then is shifted into a 32-bit integer without checking for overflow. Only eight hex digits fit into a 32-bit integer, which is why only the last 8 characters are considered. After parsing the hex digits into 32-bit integers, they are then truncated into 8-bit integers by dividing them by 16 until they fit into 8-bit, which is why leading zeros are ignored.

This code does not exactly match what is defined in the spec, but the only difference there is a few lines of code. I think it is these lines that were added (in Netscape 4):

if (bytes_per_val > 4)
{
    bytes_per_val = 4;
}
2
  • The first link is (effectively) broken. There doesn't seem to be a section with a headline of "Rules for parsing a legacy colour value" (or similar). Though there is a similar page anchor, "legacy-extract-an-encoding" Commented Nov 30, 2022 at 22:23
  • This is probably the correct link: html.spec.whatwg.org/multipage/…
    – n.r.
    Commented Apr 27, 2023 at 6:48
240
  • The browser will try to convert chucknorris into a hexadecimal value.
  • Since c is the only valid hex character in chucknorris, the value turns into: c00c00000000(0 for all values that were invalid).
  • The browser then divides the result into three groupds: Red = c00c, Green = 0000, Blue = 0000.
  • Since valid hex values for HTML backgrounds only contain two digits for each color type (r, g, b), the last two digits are truncated from each group, leaving an RGB value of c00000 which is a brick-reddish toned color.
0
69

chucknorris starts with c, and the browser reads it into a hexadecimal value.

Because A, B, C, D, E, and F are characters in hexadecimal.

The browser converts chucknorris to a hexadecimal value, C00C00000000.

Then the C00C00000000 hexadecimal value is converted to RGB format (divided by 3):

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

The browser needs only two digits to indicate the colour:

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

Finally, show bgcolor = C00000 in the web browser.

Here's an example demonstrating it:

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

0
55

The rules for parsing colors on legacy attributes involves additional steps than those mentioned in existing answers. The truncate component to 2 digits part is described as:

  1. Discard all characters except the last 8
  2. Discard leading zeros one by one as long as all components have a leading zero
  3. Discard all characters except the first 2

Some examples:

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

Below is a partial implementation of the algorithm. It does not handle errors or cases where the user enters a valid color.

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>

Not the answer you're looking for? Browse other questions tagged or ask your own question.