Chrome で背景色が描画されない

Chromium 系ブラウザの Comodo Dragon で、CSSbackground-color が画面に反映されないバグに遭遇した。

環境

再現した環境は以下の通り。

  • CPU: Celeron(R) Dual-Core CPU T3100 @ 1.90GHz
  • メモリ: 888MB
  • OS: Windows XP Professional 32bit SP3
  • ブラウザ: Comodo Dragon 26.2.2.0

再現コード

再現する HTML は以下の通り。

ファイル: http://0mg.github.io/etc/2013/chcssbug.html

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style>
#parent {
  position: absolute;
}
.foo {
  position: absolute;
  background-color: yellow;
  color: blue;
}
.bar {
  background-color: aqua;
  color: red;
}
</style>
<title>background-color not work in chrome</title>
</head>
<body>
<div><button id="button">add and change className</button></div>
<ul id="parent"></ul>
<script>
document.getElementById("button").onclick = function() {
  var parent = document.getElementById("parent");
  var child = document.createElement("li");
  var text = document.createTextNode("");

  // append child to document
  child.appendChild(text);
  parent.appendChild(child);

  // change className and text
  child.className = "foo";
  text.nodeValue = child.className;

  // change className and text
  setTimeout(function() {
    child.className = "bar";
    text.nodeValue = child.className;
  }, 300);
};
</script>
</body>
</html>

バグの概要

バグの概要を説明する。

上記の HTML を開くと、ボタンが表示されるが、これを押すと、JavaScript によって「foo」と書かれたリストアイテムが画面上に追加される。

「foo」には class 属性が設定されており、その値は "foo" である。

ステップ 1 (add)

.foo の CSS スタイルは以下の通り。

.foo {
  position: absolute;
  background-color: yellow;
  color: blue;
}

黄色い背景に、青い文字で「foo」と表示されるのが、正しいレンダリングである。

ナイスでーす

Comodo Dragon 上で確認すると、正常に CSS が反映されていることが分かる。

ステップ 2 (change)

「foo」の表示から、0.3 秒後に、その文字が「bar」に変化する。その際、class 属性の値も "foo" から "bar" へと書き換えられる。

.bar の CSS スタイルは以下のように定義してある。

.bar {
  background-color: aqua;
  color: red;
}

水色の背景に、赤い文字で「bar」と表示されれば成功だが……。

あらぁ!?

赤い文字で「bar」と正しく表示されている一方で、背景が水色になっていない。

他のブラウザでは正しい

今度は Firefox で確認してみる。

  1. いいぞっ
  2. 歪みねぇな

期待通り、水色の背景と赤い文字で表示された。

IE8 と Opera においても、Firefox と同様、「bar」は水色に浸る。

分析

当バグの再現条件は、5 つの要因が組み合わさって成り立っている。

  • 「foo」追加先の親要素が position: absolute などによって、絶対配置されている
  • 「foo」も同様の方法によって絶対配置されている
  • 「bar」は絶対配置されていない
  • 「bar」のテキストは、「foo」のテキストと異なっている
  • 「foo」から「bar」への変化は、setTimeout などによって、非同期のタイミングで行われている

たとえば、以下のようにコメントアウトすることで、Comodo Dragon においても、背景が水色になることが確認できる。

#parent {
  /* position: absolute; */
}

あるいは、以下。

.foo {
  /* position: absolute; */
  background-color: yellow;
  color: blue;
}

これでも水色になる。

// setTimeout(function() {
  child.className = "bar";
  text.nodeValue = child.className;
// }, 300);

真相

CSS では背景色を水色に指定しているのに、どうして、画面上では、水色で表示されないのだろうか。

デベロッパーツールで調査したところ、実は、「bar」の width が 0px であることが判明した。

おぉ!?

幅がゼロであるということは、背景色が塗られる面積もゼロであるから、当然、視認することはできない。

次のように CSS を変更してみる。

.bar {
  width: 10px;
  background-color: aqua;
  color: red;
}

やっぱりな

.bar に width: 10px を追加したことによって、部分的に水色に染まることが確認できた。

おわり

今回の現象は、background-color のバグではなく、まれな条件下で要素の width が 0px になるという謎の振る舞いなのであった。