ウインドウサイズの変化に伴い、テキストエリアのサイズを変更するというコードで問題が起きました。現象としては、一定時間フリーズしテキストエリアの大きさがやけに大きくなってしまったり、逆にサイズが変わらなかったり。これは私がよく使っているコードだったので不可解に感じ、はまってしまいました。
以下が問題の発生するコードです。発生時の元のコードがHTAだったので拡張子をhtaとしていますが、内容はそのままで拡張子をhtmlにしても同じ現象を確認できます。掲載は、現象を起こさせる為の最小限のコードにしぼりました。
(1)resizeTest-001.hta
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <title>onresize問題テスト001</title> <script type="text/javascript"> function init() { // 幅, 高さ resizeTo(500, 200); } var count = 0; function resizetest() { var textAreaWidth = document.body.clientWidth - 20; if (textAreaWidth > 100) { document.getElementById("textarea1").style.width = textAreaWidth; } var baseHeight = document.body.clientHeight; if (baseHeight > 20) { document.getElementById("textarea1").style.height = baseHeight; } } </script> </head> <body onresize="resizetest()" onload="init()"> <textarea id="textarea1"></textarea> </body> </html> (2)resizeTest-002.hta
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <title>onresize問題テスト002</title> <script type="text/javascript"> function init() { // 幅, 高さ resizeTo(300, 200); } var count = 0; function resizetest() { var textAreaWidth = document.body.clientWidth - 20; if (textAreaWidth > 100) { document.getElementById("textarea1").style.width = textAreaWidth; } var baseHeight = document.body.clientHeight - 35; if (baseHeight > 20) { document.getElementById("textarea1").style.height = baseHeight; } } </script> </head> <body onresize="resizetest()" onload="init()"> <textarea id="textarea1"></textarea> </body> </html> (1)を実行するとhtaが一定時間高負荷状態になりフリーズしたような状態になります。
(私の環境では30秒強程度、initをなくすと5分弱フリーズします)
そしてテキストエリアが期待以上に大きなサイズになっています。
(2)を実行すると、幅の調整はうまくいくのですが、高さの調整が全く効きません。
(1)と(2)の違いは赤字部分の高さを微調整している数値のみです。どちらも期待通りの動きをしてくれません。
googleで検索すると同様の問題で悩んでいるという書き込みをいくつか見つけました。しかしそのいずれも根本原因の特定や根本的な問題解決には至っていませんでした。
その中で、私が最も参考になったのはInternet Explorer フォーラムでの書き込みです。
2009年の2月の書き込みで、以下の情報を得ることが出来ました。
※このサイトの書込みでは、問題の発生するコードを全部公開してくれていたため、容易に再現させることが出来ました。
結局解決策は書いていなかったのですが、(特に最後の)内容からヒントを得て「もしかしたらアレか?」とひらめき、以下のコードに修正して試してみました。
(3)resizeTest-003.hta
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>onresize問題テスト003</title> <script type="text/javascript"> function init() { // 幅, 高さ resizeTo(300, 200); } var count = 0; function resizetest() { var textAreaWidth = document.body.clientWidth - 20; if (textAreaWidth > 100) { document.getElementById("textarea1").style.width = textAreaWidth; } var baseHeight = document.body.clientHeight - 35; if (baseHeight > 20) { document.getElementById("textarea1").style.height = baseHeight; } } </script> </head> <body onresize="resizetest()" onload="init()"> <textarea id="textarea1"></textarea> </body> </html> (3)にしたことで期待通りに正常に動くようになりました!
何が違うかわかりますでしょうか?先入観を持ってコードを読もうとすると、何が違うか見つけにくいと思います。実は(2)と比較するとJavaScriptの内容は何も変わっていません…。
実は1行目のDTD宣言のURL部分をはずしただけです。Internet Explorer フォーラムの書き込みのサンプルについても、DTD宣言の行そのものを削除することで問題が解決しました。
私は過去に、特定のDTDを指定しレンダリング描画仕様を強制したことによって、IE独自拡張の仕様が使えず不都合が発生した経験がありました。この経験以来、onresizeをはじめIE独自拡張を使用することが多かった私は、onresizeなどが使用できないDTDを明示的に記述しない方針を採ることが多くなっていました。今回の場合はどこかから流用したソースにDTD宣言が書いてあり、何も考えずにDTD宣言を書いていたことが最大の問題でした。
この記事を書くにあたり、DTDの内容もきちんと読んでみました。今回問題が発生した(1)と、IEフォーラムで掲げられていたコード中のDTDの両方を精査しました。
PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd" PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd" すると、この2つのDTDではどちらでも「onresize」など定められていないことがわかりました。つまり、自分で明示的にDTDを指定しておきながら指定したDTDに即していない、IE独自拡張を含む不正なコーディングを行っていたことが最大の問題と言えます。
IEの場合、複数のレンダリングエンジンとスクリプトエンジンを備えており、DTD宣言やSCRIPT要素のLANGUAGE属性の設定などによって使い分けられます(他のブラウザは知りません)。DTD宣言がなければ、相当大雑把に寛大に解釈してくれ、IE独自の要素や属性も正しく解釈してくれます。しかしDTDを指定すれば当然、指定されたDTDに即した描画を行おうとします。IE独自の要素や属性などどう扱われるか保障されないでしょう。
簡単に表現すれば、IE独自拡張のonresizeなどを使いたい場合には、それが使えないDTD宣言を書くべきではないし、DTD宣言を書くのであればDTD宣言に即した記述をすべき、ということです。
「飲んだら乗るな、乗るなら飲むな」のようなものです。
コーディングを行う者は、まずDTDが本当に必要なのかはきちんと考えるべきだと思います。そしてDTDの仕様をきちんと理解すべきです。DTDの意味を理解し、バージョンごとの仕様を理解しDTDに則した正いコードを書けばIEでも問題は発生しません。
もちろん、onresizeが中途半端に動いてしまうことにも問題があるといえると思います。しかし、だからといって不正なコードを書いておきながらそれが動かない原因をすべてをIEのせいにしてしまうのはあまりにも無責任に感じます。ネット上の情報では、IEのバグと決め付けているサイトをいくつか見かけました。大変残念なことです。
結論としては、こんな感じでしょうか。
余談ですが、(おそらくDTDを使用したまま)問題を回避しようとしているサイトがありました。問題の発生するコード全文がなく部分切り抜きなので確かなことは言え無いのですが、おそらくはDTD宣言を書いてしまっていることにより問題が発生したのではないかと思います。冷やかすわけでは無いのですが、興味深い取り組みだと思いました。ですのでリンクを張っておきます。
|
エラーと対処方法 >