Chrome で背景色が描画されない
Chromium 系ブラウザの Comodo Dragon で、CSS の background-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 で確認してみる。
期待通り、水色の背景と赤い文字で表示された。
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 になるという謎の振る舞いなのであった。