Oct 12, 2007

XULのstackとCSSのopacityで嵌った

昨日XULとCSSであれこれ頑張ってみていて浮き彫りになってきた、XULとCSSのバッドノウハウいくつか。

  1. XULのstackとCSSのopacityの微妙な関係について
  2. XULのtoolbarbuttonとCSSのopacityとpositionの微妙な関係について

まず一つ目。一般的なWebページ制作では、要素同士を重ね合わせるにはCSSのポジショニングを使うのが一般的で、XULでも同じ方法を使えるんだけど、もう一つの方法として、XULにはstackという要素がある。

通常、XULではhbox(内容が横に並ぶボックス)またはvbox(内容が縦に並ぶボックス)の2つのボックスをコンテナとして使い、縦横二方向のボックスの並びだけでGUIを作る、というのが原則となっている。この原則を覆すのがstackというコンテナ要素だ。多くのXULのコンテナ要素においては、内容に含めた要素のボックスが縦または横に並ぶのに対し、stackは、内容に含めた要素のボックスが同じ座標に重ねて表示される、という特徴がある。

チュートリアルではこれを使って影付き文字を作る例を示しているけれども、これを見て当然思いつくのが、影を半透明にして背景に自然に馴染ませたいという要求だろう。


<stack>
  <description value="Shadowed"
               style="color: black; opacity: 0.5;"
               top="1" left="1"/>
  <description value="Shadowed"
               style="color: white;"/>
</stack>

ところが、この例は実際には意図通りに表示されてくれない。Geckoのバグだと思うけど、stackの中に一つでも半透明の要素があると、stack全体が半透明になってしまうのである。つまり、ここでは影だけを半透明にしたいのに、実際には前景の文字まで半透明になってしまって却って字が読みにくくなる。

で、色々試してみた結果、stackを二重にするとこの問題を回避できるっぽい、という事が分かった。


<stack>
  <stack>
    <description value="Shadowed"
                 style="color: black; opacity: 0.5;"
                 top="1" left="1"/>
  </stack>
  <description value="Shadowed"
               style="color: white;"/>
</stack>

こうすると、内側のstackは全体が半透明になってしまうけど、外側のstackにはその影響は及ばないので、影だけを半透明にできる。(ここでは影のテキストが一つだけしかないけど、実際にはText Shadowと同様の方法で複数の薄い影をずらしながら重ねたかったということなので、stackを二重にしている。)

ただ、今度は入れ替わりに、要素の重ね合わせの順番がおかしくなるという問題が起こってしまった。XULのstackは先に入っている要素ほど下に、後に入っている要素ほど上に描画されるはずなんだけど、どういうわけか、半透明にした要素は不透明の要素よりも上に強制的に描画されてしまうようだ。

(……と思ってたんだけどもしかしたらこれは勘違いかもしれない。stack内の要素はtop属性とleft属性で場所を動かせるんだけど、もしかしたら、これらの属性がある場合は強制的にその要素がposition: relativeにされてしまって、通常のposition: staticな要素の上に表示されるようになってしまった、ということだけなのかも……これはまだ検証してない。)

そこでさらに、z-indexを使って重ね合わせの順番を指定してみたところ、やっと「半透明の影の上に不透明の文字を重ねる」という結果を得ることができた。


<stack>
  <stack style="position: relative; z-index: 1;">
    <description value="Shadowed"
                 style="color: black; opacity: 0.5;"
                 top="1" left="1"/>
  </stack>
  <description value="Shadowed"
               style="color: white; position: relative; z-index: 2;"/>
</stack>

position: relative を指定しておかないとz-indexの指定が効かない(z-indexはpositionがstatic以外の要素にしか効果がない)ので、それもセットで指定してある。

これでやっと問題を解決できたか、と思ってたんだけど、あろう事か今度はまたさらに別の問題にぶち当たってしまった。というところで、話は次のエントリへ続きます。

エントリを編集します。

wikieditish message: Ready to edit this entry.











拡張機能