♪NAI NAI NAI IEじゃない (c) シブがき隊
IE11はIEであってIEじゃない、IEとして扱おうとすると…♪そこが危NAI
IE11から削除されたdocument.createStyleSheetによる不具合例|Web制作 W3Gの補遺。
件のW3Gさんの記事では、どんなことをするとIE11でトラブルを引き起こすのか、そのバグ自体が明示されていなかったので書き添えておくと(リンク先を参照せよということだと思うけど)、IE11では
document.styleSheets[0].cssText += "div { color: yellow; }";
のように、スタイルシート・オブジェクトのcssTextに、文字列としてCSSルールを動的に追加すると、既存の@-ms-viewportや@keyframesでの指定を壊してしまう(無効化される)。
もう1点。
- これまでIE専用だった
document.createStyleSheet()
関数がIE11より削除された- IE11に
document.createStyleSheet()
関数が存在しなくなったことで、各種スクリプト側でフォールバックとして用意されているコードが走ることになる- フォールバック用のコードの中でIE11の既存のスタイルオブジェクト(キーフレームアニメーションや@-ms-viewport)を破壊する(cssTextプロパティに文字列としてCSSを追加している)コードが実行されている場合があり、IE11では既存のスタイルオブジェクト(キーフレームアニメーションや@-ms-viewport)を認識できなくなる不具合が発生する
それはその通りなのだが、その根本的な原因は、FBなどのスクリプトではIE11をこれまでのIEと同様のブラウザとして扱っている点にあると思う。
FBのスクリプトの一部をIE11 bug with dynamic CSS stylesから再掲すると
Code snippet (from the minified src code of that SDK):
... if(!j.ie()){ var ea=document.createElement('style'); ea.type='text/css'; ea.textContent=z; document.getElementsByTagName('head')[0].appendChild(ea); } else try { document.createStyleSheet().cssText=z; } catch(fa) { if(document.styleSheets[0]) document.styleSheets[0].cssText+=z; } ...
この処理に典型的な、「IEかIEじゃないか」で振り分けるという形。 このような方法はIE11が出た今となってはさっさとやめた方がいいと思う。
IE11 の互換性の変更点 (Windows)にあるように、IE11で削除されたMS独自実装のメソッドやプロパティは何もdocument.createStyleSheetに限らず
- attachEvent
- window.execScript
- window.doScroll
- document.all
- document.fileSize、img.fileSize
- script.onreadystatechange と script.readyState
- document.selection
- document.createStyleSheet
- style.styleSheet
- window.createPopup
- バイナリ ビヘイビアー
- 従来のデータ バインディング
…と、結構多い。
ついでに言うと、
<!--[if ie]>
(IE向けのコードやスタイルシートへのリンクなど)
<[endif]-->
といったMS独自実装のコンディショナルコメントも、たとえドキュメントモードをIE8とかにしてもIE11は認識しないでコメントとして無視するようになっている。
IE11におけるコンディショナル・コメントの振る舞いについては別記事をたてましたのであわせてご参照を
つまり、IE11はIEであっても最早IEじゃない。
document.createStyleSheetに限らず、これらのMS独自実装をIE11でも適用しようとすると、今回のように思わぬトラブルが発生する可能性は十分にある。 以前、IE11はたったの1行では判別できなくなる!?という記事やあんたのお名前何ァんてェの (c)トニー谷なんて記事も公開しているので、掌を返すようだがw、むしろ、IE判別してIE11もこれまでのIEと同じように扱おうとするのは大いに問題あり、ということである。
で、その解決方法は何も難しいことではなく(スクリプトを修正するのは手間かもしれないがw)、MS自身が言っているように、Web標準の使いたいメソッドやプロパティをサポートしているかどうか、で振り分ければいいだけの話。
先の処理もちょっと変えて
if(document.createElement) {
var ea=document.createElement('style');
ea.type='text/css';
ea.textContent=z;
document.getElementsByTagName('head')[0].appendChild(ea);
}
else {
try {
document.createStyleSheet().cssText=z;
} catch(fa) {
if(document.styleSheets[0])
document.styleSheets[0].cssText+=z;
}
}
とすれば問題はなくなるはず(もうちょっとまともな(丁寧な)書き方ができるとは思うけど、そこは置いておくw)。
FBなど外部ライブラリはともかく、少なくとも自サイトに置いているJavaScriptを、この際、見直してみたらいかがかと。 …ということで、結論。
♪ジタバタするなよ 世紀末が来るぜ (まともな動作が)欲しけりゃ 今すぐ (Web標準に)すがりつけ~
…なんつーてw
補遺の補遺
ところで、IE11 bug with dynamic CSS stylesのコメント欄で提示されている回避策だが、よくよく見ると多少問題ありかもしれない。
というのも、回避策のコードではstyle要素を生成してURLがあったらhrefを足しているけど、そもそもstyle要素にhref属性はないので実際にCSSファイルへのURLが渡されてもそれは反映されない(URLが渡された場合には、本来ならばstyle要素ではなくlink要素を生成すべき)。
また、MSのドキュメントを見ると、第1引数にはCSSファイルへのURLだけではなく、例えば、
document.createStyleSheet(document.body.style.backgroundColor = 'blue');
を渡せる、というなかなか豪快な仕様になっている。
さらに、document.createStyleSheet()の第2引数には、
styleSheetsコレクションの中で挿入される位置を整数で指定する
ための値も渡せるらしい。
CSSは後から書かれた指定で上書きするので、なぜ新たに生成したスタイルシートをわざわざスタイルシート・コレクションの「途中」に挿入するのか、その意味が自分にはさっぱりわからないけど…。
いずれにせよ、彼の回避策コードは、FB対策としては問題は表面化しないけど、ほかのライブラリ等でIE11にcreateStyleSheet()が適用された場合に不具合が出る可能性がある。
そこでちょっと発想を変えて、いっそdocument.createStyleSheet()をWeb標準で再定義してIEに適用しちゃった方が♪ぴたりあっちゃうかもね(ってこれは別の歌かw)と考えて、屋上屋を架してみた。 テストケース。
…と思ったけど、あれこれ追試してみたら色々と不都合が出てきそうな感じだったので、結局はIE11のみに適用することにした。 やはりMS謹製ソフトは一筋縄ではいかなかった…orz
/*
* Redefine document.createStyleSheet() in IE11
* Free and unencumbered, released into the public domain.
*/
(function(d) {
'use strict';
d.documentMode === 11 && (d.createStyleSheet = function(s, i) {
var o = d.createElement('style'), x;
s && (x = new XMLHttpRequest(), x.onreadystatechange = function() {
x.readyState === 4 && x.status === 200 && (o = d.createElement('link'), o.setAttribute('rel', 'stylesheet'), o.setAttribute('href', s));
}, x.open('GET', s, false), x.send(null));
i && (x = d.styleSheets, x[i]) ? (x = x[i].ownerNode, x.parentNode.insertBefore(o, x)) : d.querySelector('head').appendChild(o);
return o.sheet;
});
})(document);
適用対象はIE11のみに限定。
なお、第2引数のindex値(i)に関しては、0から始まるのか、それとも1から始まるのか、はたまた-1が指定された場合はどうなるのか、など全く情報がないので、とりあえずの実装となっている。
ただし、こんなもの作っておいてまたまた掌を返すようでアレですが…w
harrihaさんが示した回避策を使うにせよ、今回私が作ったものを使うにせよ、当面(FBのスクリプトが更新されるまでとか)の使用にとどめておいた方がいいとは思う。(一応FBのスクリプトが更新された後でも問題がでないように作ったつもりだけど)
http://connect.facebook.net/ja_JP/all.js を確認してみたら、いつ改修されたのかはしらないが、今はこのようになっていた。
if(h.ie()<11){ try{ document.createStyleSheet().cssText=z; } catch(ea){ if(document.styleSheets[0])document.styleSheets[0].cssText+=z; } }else{ var fa=document.createElement('style'); fa.type='text/css'; fa.textContent=z; document.getElementsByTagName('head')[0].appendChild(fa); }
ということで、FBに関しては上記のポリフィルはもう不要です。
"♪NAI NAI NAI IEじゃない (c) シブがき隊"へのTwitter上でのコメントやRT
18件のツイートがあります。
ツイート 1
asamuzaK.jp : ♪NAI NAI NAI IEじゃない (c) シブがき隊 / IE11はIEであってIEじゃない、IEとして扱おうとすると…♪そこが危NAI http://t.co/ihn6UNbVLI
ツイート 2
歌詞の引用部分を改変した場合のマークアップって何がいいんだろう? 改変部分の意味合いとしてはemの反対で弱めたいんだけどそんな要素ないので今はi要素にしてる でも、挿入だからやっぱりins? それともmarkかな?/ http://t.co/ihn6UNbVLI
ツイート 3
<ins><i></i></ins>にしてみた / http://t.co/ihn6UNbVLI
ツイート 4
@w3gjp フォローアップの記事を挙げてありますのでご一読いただけると幸いです asamuzaK.jp : ♪NAI NAI NAI IEじゃない (c) シブがき隊 http://t.co/ihn6UNbVLI
ツイート 5
補遺の補遺(オマケ的なネタ)を追記 asamuzaK.jp : ♪NAI NAI NAI IEじゃない (c) シブがき隊 / IE11はIEであってIEじゃない、IEとして扱おうとすると…♪そこが危NAI http://t.co/ihn6UMUSJI
ツイート 6
ありゃりゃ、IE8はownerNodeには未対応だったか…orz http://t.co/RPp2IwKBS3 http://t.co/ihn6UMUSJI
ツイート 7
IE8対応なんて考える気がしないので、適用対象をIE9~IE11に絞り混むかな…w http://t.co/ihn6UMUSJI
ツイート 8
あれこれ追試していたらIE8のみならずIE9でも妙な挙動がいくつか出てきた…orz で、結局、IE11のみに適用することにしたorz http://t.co/ihn6UMUSJI
ツイート 9
IE11にしか適用しないとなると単なるバグ回避的なコードなのでパブリック・ドメインにした http://t.co/ihn6UMUSJI
ツイート 10
FBや他のライブラリ向けの回避策の件でコメントとソースコードつけておいた https://t.co/UfSFGjGIZQ / http://t.co/ihn6UMUSJI
ツイート 11
@w3gjp 補遺の補遺にて、harrihaさんの回避コードでは、FBで問題が顕在化しないものの、他のライブラリでは問題が出る可能性がある旨、指摘するとともに、代替コードを掲載しています。 ご参考まで http://t.co/ihn6UMUSJI
ツイート 12
コンディショナル・コメントに関して追記しておいた http://t.co/ihn6UMUSJI
ツイート 13
@pecoegg あと、こちらにも「追記」という形で簡単に今回の件をまとめてますのでご参照下さい http://t.co/ihn6UMUSJI
ツイート 14
なお、IE11がFBのボタンでバグを引き起こしている原因や解決法については下記にまとめてあります http://t.co/ihn6UMUSJI
ツイート 15
IE11ェ・・・ / “asamuzaK.jp : ♪NAI NAI NAI IEじゃない (c) シブがき隊” http://t.co/VTX67HYxHk
ツイート 16
.@LIG_J http://t.co/4bxnhnhZ5X 記事内にてW3Gさんが当サイトから引用したJSソースを孫引きして掲載してますが、引用の形をとらずまたソースの出典も示されてないことについてご説明願いますか 当サイトの記事は http://t.co/ihn6UMUSJI
ツイート 17
ってなっていて、もうバグはさすがに取り除かれていた ということで、 http://t.co/ihn6UNbVLI のポリフィルは不要
ツイート 18
本文にも一応追記しておいた asamuzaK.jp : ♪NAI NAI NAI IEじゃない (c) シブがき隊 ~ IE11はIEであってIEじゃない、IEとして扱おうとすると…♪そこが危NAI http://t.co/ihn6UNbVLI