Firefox3でFlashにwmode属性を追加して透明な画像をマスクする

Windows環境のFirefox3でFlashの上にレイヤーとしてimgをかぶせたいときに参考になるであろうエントリー。


以前、はてな市民にもなったことだし、群衆の叡智を使ってみる このエントリーではてなーに疑問をぶつけてみたんだけどまったく反応がなくてそのまま放置されていた問題に再び挑戦してみたところ解決した!

どんな問題かおさらい

http://www.radio-i.co.jp/ このページの このFlashの上にimgを貼り付けてリンクさせ、ポップアップのページを新しいタブに開きたい。
以前のエントリーはimgをenbedよりも前に挿入してposition:absoluteにしても、imgがFlashの下側に潜ってしまってクリックできない。という状況であった。

問題を解決できたソース

var link = document.createElement('a');
link.target = "_blank";
link.href ='http://www.radio-i.co.jp/NOAView/cgi-bin/NOAData.Now?id=0469';
var img = document.createElement('img');
img.src = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAABnRSTlMA%2FwD%2FAP83WBt9AAAADElEQVR4nGP4%2F%2F8%2FAAX%2BAv4N70a4AAAAAElFTkSuQmCC';
img.style.cssText="position:absolute; width:297px; height:95px;"
link.appendChild(img);

var p = document.evaluate('id("nowPlayTop")//embed', document, null, 7, null);
p.snapshotItem(0).setAttribute('wmode','transparent');
//マスクをembedよりも前の位置に挿入。またこの処理によりwmodeが適用される。
p.snapshotItem(0).parentNode.parentNode.insertBefore(link, p.snapshotItem(0).parentNode.parentNode.firstChild);

ソース解説

マスク(レイヤーもどき)作成

  • Flashの上にかぶせたいリンクは、dataスキームで1px×1pxの透明なpngを作ってそれをかぶせるFlashの大きさに引き伸ばしている。


重要な処理は以下の2つ

  • embedタグよりも前の位置にマスクとなるimgを挿入する。
  • wmodeを適用させるにはsetAttributeしただけでは足りない。insertBeforeなどでレンダリング(?)し直すとwmode適用される。詳しくは→wmodeを動的に設定する方法
これ以降はwmode適用条件を知らないときに書いたので参考にならない。embedの仕様の適当さがうかがえるだけ。

処理の順番を変えて失敗の例

//DOMを変えてからwmodeを設定しても効果なしの例
var link = document.createElement('a');
link.target = "_blank";
link.href ='http://www.radio-i.co.jp/NOAView/cgi-bin/NOAData.Now?id=0469';
var img = document.createElement('img');
img.src = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAABnRSTlMA%2FwD%2FAP83WBt9AAAADElEQVR4nGP4%2F%2F8%2FAAX%2BAv4N70a4AAAAAElFTkSuQmCC';
img.style.cssText="position:absolute; width:297px; height:95px;"
link.appendChild(img);

var p = document.evaluate('id("nowPlayTop")//embed', document, null, 7, null);
p.snapshotItem(0).parentNode.parentNode.replaceChild(p.snapshotItem(0), p.snapshotItem(0).parentNode);
p.snapshotItem(0).setAttribute('wmode','transparent');
p.snapshotItem(0).parentNode.insertBefore(link, p.snapshotItem(0).parentNode.firstChild);

Firebugでembedにwmode属性が追加されたのを確認しても、見かけだけで、うまく適用されていない。

Firefox2では異なる挙動

Firefox 2.0.0.18 で試したところ、以下のコードで出来た。前半のレイヤー作成は同じで、後半の処理を変えている。

var link = document.createElement('a');
link.target = "_blank";
link.href ='http://www.radio-i.co.jp/NOAView/cgi-bin/NOAData.Now?id=0469';
var img = document.createElement('img');
img.src = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAABnRSTlMA%2FwD%2FAP83WBt9AAAADElEQVR4nGP4%2F%2F8%2FAAX%2BAv4N70a4AAAAAElFTkSuQmCC';
img.style.cssText="position:absolute; width:297px; height:95px;"
link.appendChild(img);

var p = document.evaluate('id("nowPlayTop")//embed', document, null, 7, null);
p.snapshotItem(0).parentNode.insertBefore(link, p.snapshotItem(0).parentNode.firstChild);
p.snapshotItem(0).setAttribute('wmode','transparent');

embedタグにwmode:transparentを設定するだけでいけた。objectタグの除去や処理の順番は関係なかった。Firefox2のほうが正しい動作をしている(と思う)。

まとめ

今回わかったことは、Windows環境においてFirefox3でFlashにwmode属性を追加する際はDOMを変化させる前に行うこと。
Windows×Firefox×Flashレンダリングタイミング(以前のエントリーで述べた)などの癖もあるので注意すること。