ハードウェアが特定の条件下ではIEでfilter:alpha(opacity=N)が適用されない

  • 2011年3月 7日 01:10
  • css

CSSでDOM要素に対してアルファフィルターを適用させたいときは、クロスブラウザを意識すると次のような記述になると思います。 もうすこし古いMozilla系ブラウザを対象にするなら-moz-opacityの定義も追加してあげるとことになりますが、 今回はIEに絞った話のため、そのあたりは割愛します。

#element {
  filter: alpha(opacity=0); /* IE */
  opacity: 0; /* その他のモダンブラウザ */
}

さて、普段は特に何も考えずにfilter:alpha~と記述していたのですが、 実はIEはある条件下によってまったくfilterが効かない場合があります。

ActiveXが無効

そもそもの話ですが、filterはActiveXを利用したレンダリングを行っています。 そのため、そもそもセキュリティの設定などでActiveXを無効にされていると、filterが効かず想定したようなレンダリングがされません。

たとえば、「インターネットオプション」の「セキュリティ」でセキュリティのレベルを「高」にする、ActiveXの設定を個別でOFFにする、 などの設定を行うなどでfilterを無効にすることができます。

インターネットオプション

ただし、この場合は当然ながらFlashも見ることはできませんし、セキュリティを気にするユーザはそもそもIE以外のモダンブラウザを利用することの方が多いでしょうし、 標準的なユーザがこの条件下でfilterが効かない、という話はほぼ無いと考えてもいいと思います。実は次の問題が厄介です。

2048pxを超えるような巨大な要素がfilterの対象

実は今回この事例にずばりハマってたのですが、

  • IE7,8(6は未確認)
  • Windows Vista, 7(XPは未確認)
  • filter対象要素が2048pxを超えるような巨大なもの
  • ATI(AMD), NVidiaのグラフィックカード

な条件下において、filterが適用されないことを確認しています。(参考文献 "filter-alpha-opacity fails if the element is taller than 2048px, IE7 Vista")

上記のActiveX無効の場合はJavaScriptでActiveXが有効/無効を判断できるので、何らかの対応をすることはできるのですが、 この場合はハードウェアの話が絡んでくるので、実質的な回避方法はありません。後で詳しく述べますが、今回は

  • filter対象要素が2048pxを超えるような巨大なもの

をやめて、filter対象要素の面積を可能なかぎり小さくすることができたので、回避しました。

巨大な要素にfilterをかける必要性

そもそも、なんでそんな巨大な要素にfilterをかける必要があるのかという話になるのですが、今回はファイルアップロードのUIをゼロから作ったことに起因します。 ファイルアップロードの際には、<input type="file" name="uploader" />なんかでファイル選択ダイアログを表示し、対象ファイルを選択することになります。 ところが、これはブラウザ標準のUIになるので、「もっと凝ったことしたい!画像など任意に要素クリックでこの選択ダイアログを表示させたい!」などとなると、途端に話は面倒くさくなり、

  1. Flashで実装
  2. JavaScript/CSSで巧みに実装

の選択を迫られることになります。

Flashで実装をとるという方法もあったのですが、カスタマイズ性や毎回publishすることの実装コストを考慮して、JS/CSSでの実装を選択することにしました。 たとえば画像クリックでファイル選択ダイアログを表示させたい場合、次のような構成になります。

img要素の上に大きめのinput要素を重ねあわせ、filterでalpha=0に指定します。これで画像をクリックしようとするとinput要素をクリックすることになり、結果的にダイアログを表示することができます。 そのあとはinput要素のchangeイベントに対してハンドラを設定し、formを送信なりなんなりとしてあげると完了です。

ところが、ここで1つマウスカーソルの問題があります。ただ単純にinput要素を重ねただけだと、画像の上にカーソルを重ねたときに

な形状になり、クリックできそうなことを連想できません。そこで、input要素に対して

cursor: pointer;

な、スタイルを設定する必要があります。これでカーソルの形状が

になり、解決しました。。と、言いたいのですが、実はこれでもまだ完璧ではなく、Firefoxではカーソルは変わりません。

どうもこれはFirefoxの仕様のようで、いくらcursor指定をしても変わることがありませんでした。では、Firefoxだけ残念な形になっちゃうのか。。と思いきやそうでもなく、先ほどの画像とinput要素の重ね方を工夫するともうすこし頑張れます。結果から言うとこう配置します。

分かりづらいですが、最初の例では画像に対してinput要素も{ left:0, top:0 }で配置していたのに比べて、2つ目の例ではinput要素をサイズを巨大なものにして、{ right:0, top:0 }で配置します。(大きさはfont-size:で調整します) このとき、要素のサイズを巨大にして「選択」ボタンを画像に重ねることがポイントです。「選択」ボタンを画像にうまく重ねることで、画像のマウスオーバー時に

と、することができ、最初の状態と比べて「クリックできそう感」が改善されます。ちなみにこのマニアックな手法はいろんなファイルアップロードライブラリを見ても、 Flash実装じゃないものは全部この仕様になってあり、Firefoxのマウスカーソル問題はここが妥協ポイントのようです。(例:file-uploader

話をfilterに戻す

大きく脱線しましたが、ようやく最初のfilterの話に戻します。

ここまできてようやく「Flashで実装しない場合に、ファイルアップロードを実装する場合において、カーソルの形状の最適化のためにfilter対象要素を十分に大きくする必要がある」という話になりました。実際にこれを実装してみるとわかるのですが、画像と選択ボタンを合わせるためにはinput要素を相当巨大なものにする必要があり、 結果的に{数千px × 数百px}の巨大な面積の要素にfilterをかけることになります。

で、HWスペックが十分なマシンだとIEだと問題なくレンダリングされるのですが、冒頭の条件であったりレンダリングスペックが十分でない場合、filterに失敗して 表示が崩れる、という問題が起こります。 この場合、セキュリティ設定やActitiveXなどOS、ブラウザの設定を操作することなくfilterが無効になるので、気づかない間にユーザが不便を被ることになるので非常に厄介です。

さて、ではどう対策をすればいいかというと、話を振り返るとそもそもinput要素を巨大にしたり右寄せにしたり面倒なことをしているのはFirefoxのマウスカーソルを いい感じに見せるためだけであって、IEはそもそもこの対応をしなくともcursor: pointer;だけしておけば表示位置はどこに設定してもOKなので、 IEだけレンダリング要素を最小化しておけば大丈夫という最初で述べた結論に帰着するのです。(長い!)

と、いうわけでここまでまとめるとたとえば130x130なサイズの画象にinput要素をかぶせるときは次のようなスタイルを設定します。サイズは各環境によって微調整をしてください。

right: 0;
top: 0;
position: absolute;
cursor: pointer;
opacity: 0; /* IE以外の最新ブラウザはこれでOK */
filter: alpha(opacity=0); /* IE */
font-size: 460px;

/* StarHackを使ってIEだけ適用。要素を必要十分なサイズで最小化。 */
*font-size: 32px;
*width: 130px;

z-index: 1;
height: 130px;

結論

CSSコーディングでグラフィックカードの特性を意識しないのは素人!

ところで

今回はたまたまレンダリング要素のサイズ変更で回避できましたが、本質的な解決にはなっていません。あと動的なサイズの要素の場合、回避は不可能そうです。どなたかこの問題について詳しい方はいないでしょうかね??

関連広告

Trackbacks:0

TrackBack URL for this entry
http://blog.katsuma.tv/mt-tb.cgi/228
Listed below are links to weblogs that reference
ハードウェアが特定の条件下ではIEでfilter:alpha(opacity=N)が適用されない from blog.katsuma.tv

Home > css > ハードウェアが特定の条件下ではIEでfilter:alpha(opacity=N)が適用されない

Search
Feeds

Return to page top