IEのImage.src.width(height)の値はどこから来るのか?
theater.js作成開始当初から、不思議に思っていることがあります。IEのImageオブジェクトの振る舞いについてです。
theater.jsは、画像を画像ボックスに合わせて縮小して表示するため、画像の幅・高さをImage.src.width(height)で取得しています。これを元に表示サイズを算出し、IMGタグに幅・高さを設定して画像を表示します。
サンプルHTMLは以下です。
<html> <head> <title></title> <script language="javascript"> <!-- //画像オブジェクト配列 var images = [new Image(), new Image()]; //画像先読み images[0].src = "./sample9.gif"; //最初の画像 images[1].src = "./sample10.gif"; //次の画像 //ページ読み込み完了時実行関数 function init(){ changeImage(document.getElementById("img"), 0); } //画像変更 function changeImage(imgElem, index){ //画像そのものの幅・高さのポップアップ alert("images[" + index + "].width : " + images[index].width); alert("images[" + index + "].height : " + images[index].height); //IMGタグの幅・高さのポップアップ alert("imgElem.width : " + imgElem.width); alert("imgElem.height : " + imgElem.height ); //IMGタグのサイズ(表示サイズ)を画像サイズに合わせる imgElem.height = images[index].height; imgElem.width = images[index].width; //画像表示 imgElem.src = images[index].src; } //--> </script> </head> <body bgcolor="blue" onload="init();/*読み込み時に最初の画像を設定*/"> <img id="img" onclick="changeImage(this, 1);/*クリック時に次の画像を設定*/"/> </body> </html>
サンプル画像 sample9.gif sample10.gif
上のHTMLをIEで開くと、最初の画像が表示されます。画像をクリックすると、次の画像が表示されます。ここでは、取得した画像の幅・高さを、IMGタグにそのまま設定しています。
ここまでは問題ありません。問題が発生するのは、画像の名前(アドレス)を変えずに幅・高さを変えた場合です。ペイント等でsample10.gifの幅・高さを変更してください。(色を塗ると後で分かりやすいです) その後、IEでHTMLを開きなおし、画像をクリックしてください。すると、画像は変わっているのに幅、高さが変わっていません。リロードしても、キャッシュをクリアしても、ブラウザの落とし上げをしてもダメです・・・。
これは、ポップアップを見ると分かるのですが、Image.src.width(height)が前の画像の情報を保持しているために、そのサイズで表示し続けてしまうからです。なぜ保持しているのかは分かりません。また、どこに保持しているのかも分かりません。
当事象は、IE以外のブラウザでは確認できていません。どうも、IEがプログラムで情報を保持しているような気がするのですが・・・。今のところの対策としては、画像の名前・アドレスを変えるくらいしか思いつきません。申し訳ないです・・・。
この件について何かご存知の方がいらっしゃいましたら、コメントいただけるとありがたいです。(Questionを出すことも検討しています)
○コメントにて↓より簡単な対処法を教えて頂きました。最後の追記を参照してください。○
2006/12/12 追記。
↑とか言っておきながらすっかり忘れてたら、他の方がはてなで質問してくれました^^;
http://q.hatena.ne.jp/1165179638
で、改めて考えてみたら、対策がみつかったので回答しました。
回答に書いたとおりですが、いまだ原因は不明、しかし以下で対応できそうです。
- 一度、style visibility:hidden; position:absolute;なimg要素のsrcプロパティにImageオブジェクトをセットする。(width、heightは無指定)
- その後、上記img要素のoffsetHeight、offsetWidthを使用する。
これを共通関数化してみました。
【参考】Imageオブジェクト 幅・高さ 取得関数 function getImageDimensions(image){ var wk = document.createElement('img'); wk.style.position = 'absolute'; wk.style.visibility = 'hidden'; wk.style.top = '0px'; wk.style.left = '0px'; document.body.appendChild(wk); wk.src = image.src; var width = wk.offsetWidth; var height = wk.offsetHeight; wk.parentNode.removeChild(wk); return {width:width, height:height}; }
引数はImageオブジェクト、返却値は{width:(幅), height:(高さ)}形式のカスタムオブジェクトです。注意として、document.body.appendChildする都合上、ページonload後でないと使用できません。
・・・ブラウザ判定はパス^^; 必要であれば各自でお願いします。。。
【例】 <html> <head> <title></title> <script language="javascript"> <!-- //画像オブジェクト配列 var images = []; var index = 0; function addImage(src){ var image = new Image(); image.src = src; images.push(image); } //画像先読み addImage("./sample9.gif"); //最初の画像 addImage("./sample10.gif"); //次の画像 addImage("./sample9.gif"); //次の画像 //画像変更 function changeImage(imgElem){ if(index >= images.length) return; var str = ""; str += "Imageオブジェクトのwidth, height<br/>"; str += "images[" + index + "].width : " + images[index].width + "<br/>"; str += "images[" + index + "].height : " + images[index].height + "<br/>"; var dimentions = getImageDimensions(images[index]); var width = dimentions.width; var height = dimentions.height; str += "IMGタグに設定した後のoffsetWidth, offsetHeight<br/>"; str += "width : " + width + "<br/>"; str += "height : " + height + "<br/>"; //IMGタグのサイズ(表示サイズ)を画像サイズにあわせる imgElem.height = height; imgElem.width = width; //画像表示 imgElem.src = images[index].src; document.getElementById("test").innerHTML = str; index++; } function getImageDimensions(image){ var wk = document.createElement('img'); wk.style.position = 'absolute'; wk.style.visibility = 'hidden'; wk.style.top = '0px'; wk.style.left = '0px'; document.body.appendChild(wk); wk.src = image.src; var width = wk.offsetWidth; var height = wk.offsetHeight; wk.parentNode.removeChild(wk); return {width:width, height:height}; } //--> </script> </head> <body bgcolor="blue" onload="changeImage(document.getElementById('img'));"> <div id="test" style="color:white;"></div> <img id="img" onclick="changeImage(this);"/> </body> </html>
2011/05/02 追記。
白兎仙人さん、コメント頂いていたのに気がつかなくてすみません。。。
srcにイメージのURLを代入する直前に、srcに空文字('')を代入すると正しい画像サイズが取得できるようになりました(image.src='';)。
私のほうでも試してみました(Xp+IE8)。確かにそれでうまくいきそうですね^^
てか、まだコレ直ってないんですねorz メインPCがXpなのでまだIE8でしか試してませんが。IE9ではいい加減直っていてくれ><;
<html> <head> <title></title> <script language="javascript"> <!-- //画像オブジェクト配列 var images = [new Image(), new Image()]; //画像先読み images[0].src = ""; //★空文字を代入★ images[0].src = "./sample9.gif"; //最初の画像 images[1].src = ""; //★空文字を代入★ images[1].src = "./sample10.gif"; //次の画像 //ページ読み込み完了時実行関数 function init(){ changeImage(document.getElementById("img"), 0); } //画像変更 function changeImage(imgElem, index){ //画像そのものの幅・高さのポップアップ alert("images[" + index + "].width : " + images[index].width); alert("images[" + index + "].height : " + images[index].height); //IMGタグの幅・高さのポップアップ alert("imgElem.width : " + imgElem.width); alert("imgElem.height : " + imgElem.height ); //IMGタグのサイズ(表示サイズ)を画像サイズに合わせる imgElem.height = images[index].height; imgElem.width = images[index].width; //画像表示 imgElem.src = images[index].src; } //--> </script> </head> <body bgcolor="blue" onload="init();/*読み込み時に最初の画像を設定*/"> <img id="img" onclick="changeImage(this, 1);/*クリック時に次の画像を設定*/"/> </body> </html>
サンプル画像 sample9.gif sample10.gif