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が適用されるとなにが嬉しいのか
- 先に述べたようにFlashの上にHTML Elementを配置できる。
- Flashにfocusした状態でホイールスクロールが出来るようになる!!(Windows)
- こちらの問題も解消できた。→ 131: Flashにフォーカスがあるとメニューがスクロールしないのを修正する - alice0775のファイル置き場 別館 userChrome.js 101-
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タグのユルユルな仕様を誰か解説して下さい。