wmodeを動的に設定する方法

最近Windosw+Firefox3でFlashのwmodeに関して実験していたんだけど、http://b.hatena.ne.jp/js/Hatena/Bookmark/LetLoader.js に答えがあった。

var els = document.getElementsByTagName('embed');
for (var i = 0;  i < els.length; i++) {
  var el = els[i];
  // none にして block にすると、wmode が適用される
  el.setAttribute('wmode', 'opaque');
  el.style.display = 'none';
  el.style.display = 'block';
}

このコードは、はてなブックマークブックマークレットを呼び出したときに表示されるパネル(タグやコメントを入力して追加ボタンを押すやつ)がwmodeを設定してないFlashの上にある場合、Flashが手前に表示されるのを防ぐ為のもの。

要は「embedタグを捕まえてsetAttributeでwmodeを追加しただけでは適用されず、displayを使って改めてレンダリング(?)することでブラウザがwmodeを認識する。」ということがわかったのだ。Firebugで観察してwmodeがあるからといって安心してはいけない。


このコードを見つける前にdisplayとは別の方法を発見していた。以下で条件を探る。

適用条件調査

wmodeが適用されていれば、Flashの上にgoogle画像がマスクされるサンプルを用意した。YouTubeニコニコ動画などで試してみて下さい。


この実験まちがってるや。display、appendChild、insertBeforeでwmode適用されなくても(適用されるんだけど)、imgをinsertするところでwmodeになるわ。要はsetAttribute('wmode'した後、display(none/block)するか、insertBeforeなどをしてDOMを書き換えることによりwmodeが適用される。

display編
var els = document.getElementsByTagName('embed');
for (var i = 0;  i < els.length; i++) {
  var el = els[i];
  el.setAttribute('wmode', 'opaque');
  el.style.display = 'none';  //<-ココと
  el.style.display = 'block'; //<-ココを書き換えればてwmode適用の条件を探る実験ができる

  var img = document.createElement('img');
  img.src = 'http://www.google.co.jp/intl/ja_jp/images/logo.gif';
  img.style.position = 'absolute';
  el.parentNode.insertBefore(img, el.parentNode.firstChild);
}

実はdisplayだとswf周りのレイアウトが崩れるケースがある。後述。

appendChild編
var els = document.getElementsByTagName('embed');
for (var i = 0;  i < els.length; i++) {
  var el = els[i], ep = el.parentNode;
  el.setAttribute('wmode', 'opaque');
  ep.removeChild(el);
  ep.appendChild(el);

  var img = document.createElement('img');
  img.src = 'http://www.google.co.jp/intl/ja_jp/images/logo.gif';
  img.style.position = 'absolute';
  el.parentNode.insertBefore(img, el.parentNode.firstChild);
}

(実験には関係無いけど、epを参照型にしているのがミソか。)

insertBefore編
var els = document.getElementsByTagName('embed');
for (var i = 0;  i < els.length; i++) {
  var el = els[i], ep = el.parentNode;
  el.setAttribute('wmode', 'opaque');
  ep.insertBefore(el, el.nextSibling);

  var img = document.createElement('img');
  img.src = 'http://www.google.co.jp/intl/ja_jp/images/logo.gif';
  img.style.position = 'absolute';
  el.parentNode.insertBefore(img, el.parentNode.firstChild);
}

元々いた位置にinsertしている。


一旦表示が外れる処理をすればいいのかと思ったが、visibilityでは効果が無かった。

wmodeが適用されるとなにが嬉しいのか

wmodeを適用すると発生する不具合

上のサンプルを使わなくても、はてなブックマークブックマークレットを読み出すことでも再現ができる。(displayのnone/block切り替えの手法に限定された再現になるけど)

//はてなブックマークのブックマークレット
javascript:(function(){var%20d=(new%20Date);var%20s=document.createElement('script');s.charset='UTF-8';s.src='http://b.hatena.ne.jp/js/Hatena/Bookmark/let.js?'+d.getFullYear()+d.getMonth()+d.getDate();(document.getElementsByTagName('head')[0]||document.body).appendChild(s);})();

ニコニコ動画の再生ページを開いて、はてブブックマークレットを呼び出すとホイールスクロールも可能になるが日本語入力が出来なくなっている。こちらのページでも確認ができます→graffiti-blog - wmodeのクセ

  • displayでnone/block切り替えを使うとswfまわりのレイアウトが崩れることがある。

試すには http://www.radio-i.co.jp/ このページではてブブックマークレットを呼び出せばわかる。右上のON AIR曲目検索のFlashの配置がすこしずれる。

まとめ

これでYouTubeニコニコ動画Flashの上でホイールスクロールが可能になるグリモンが書ける。→http://d.hatena.ne.jp/Cherenkov/20090410/p2
embedタグのユルユルな仕様を誰か解説して下さい。