【jQuery】画像のloadイベントがIE8で動作しない時の解決法

jquery

よく画像を読み込む時にローディングの時にプログレスバーを設置する事もあると思います。
画像を読み込むイベントはloadイベントがありますが、なぜかIE8とIE9でloadイベントが動作しないで途中で止まる自体に陥りました。

いろいろ調べてみるとIE8とIE9ではやはり問題があるらしく画像読み込む時にloadイベントが動かない事があるようなので、今回はその解決した方法をメモしていくことにします。
また参考コードは画像が複数枚読み込まれる事を想定したコードの記述になります。

IEで画像を読み込む時のloadイベントのデモ

まずは、IEで画像を読み込む時のloadイベントがどういった挙動が起きるのかデモを作成しました。IE8かIE9で見ていただくとよいと思います。
確認方法はIE11であればツール→F12開発者ツールからIE8やIE9での表示方法が確認できます。またデモに関しては

  • IEでloadイベントが動作せず画像が読み込まれない例
  • src属性をloadイベント後に設定する
  • 画像のキャッシュ自体をロードさせない方法

の3パターンを用意していて「src属性をloadイベント後に設定する」「画像のキャッシュ自体をロードさせない方法」は解決パターンになります。

IEでloadイベントが動作せず画像が読み込まれない例

上記のサンプルをIE8で見ていただくと、プログレスバーが途中で止まってloadイベントが動作しなくなるはずです。
IE9に関してはリロードするとloadイベントが動作してプログレスバーが100%までちゃんとアニメーションしたり、1枚だけ読み込んでそれ以上は止まってしまったりムラがあるように感じました。

ソースコードを見ていただくと分かるのですが、単純に画像オブジェクトを取得してロードイベントを設定しているだけです。

htmlのソースコード

ローディング時のプログレスバーのdivと画像を並べてるだけです。必要なコードだけ載せておきます。




jQueryのソースコード

loadイベントに関してはone()で処理していますが、bindで指定してもloadで直接処理しても構いません。


var all_img = jQuery("img"); //すべての画像
var loaded_counter = 0; //読み込み完了のカウンター

all_img.one("load",function(){
	loaded_counter++;
});

//もしくは下記のパターン
all_img.load(function(){
       //読み込み後の処理
 });

loadイベントが動作しない原因は?

キャッシュから画像がロードされる

このようにIE8やIE9でlaodイベントの挙動がおかしいのは、どうやらhtmlに画像を埋め込であるとsrc属性に設定してある画像が読み込まれブラウザにキャッシュされます。その為画像がブラウザにキャッシュされているとimg要素のonloadイベントが動作しないという現象が起こるようです。

loadイベントの前にsrc属性を設定する

こちらもキャッシュが原因になるのですが、img要素を作成してsrc属性を設定してloadさせる方法を取ることがあると思います。*下記参照


//画像要素を作成
var img=$("");

//src属性にURLを指定
img.attr("src","画像パス");

//loadイベントの設定
img.bind("laod",function(){
	//読み込み後の処理
});

});

上記の方法のようにloadイベントを付与する前にsrcで画像パスを指定してしまうと、そちらが先に読み込まれる為loadイベントが動作しなくなってしまう。

loadイベントを動作させる為の対策

それでは、loadイベントが動作しなくなる挙動を回避する方法をいくつか載せていきます。

src属性をloadイベント後に設定する

img要素を生成してsrc属性の設定をloadイベントの後に設定してあげるとloadイベントが動作します。

下記の例はhtmlにある画像の総数分新しいimg要素を作成して、それぞれにloadイベントを設定しています。
その後にattr()で元々取得しておいた画像オブジェクトの配列(all_img)からsrcに指定してある画像URLを取得してそのまま新しいimg要素のsrc属性に指定しています。


var all_img = jQuery("img"); //すべての画像

for (var i = 0; i < all_img.length; i++) {
     
	 //img要素を作成してloadイベントを設定
	$("").one('load',function(){
		
		//読み込み後の処理
		
	}).attr("src",jQuery(all_img[i]).attr("src"));
       
}

画像のキャッシュ自体をロードさせない方法

画像のキャッシュ自体を読み込ませない方法としては、よくあるパターンですが読み込み時に画像のURLの末尾に「?」でつなげて現在時刻を加える事です。
この方法であれば読み込まれる度に画像URLの末尾に現在時刻に加わることでキャッシュに残ってる画像パスと一致しないので毎回違う画像と認識されるので、キャッシュから読み込もうとせずに毎回loadイベントが実施されます。


var all_img = jQuery("img"); //すべての画像

for (var i = 0; i < img_len; i++) {
	
//新しい画像オブジェクト作成
var img=jQuery('');

//現在時刻を取得
var date=new Date().getTime();

//htmlにある画像からパスを取得
var path=jQuery(all_img[i]).attr("src");

//画像オブジェクトに画像パスと現在時刻をつなげたURLを指定する
img.attr("src",path+"?"+date);

//loadイベント
img.one("load",function(){
  //読み込み後の処理
});
			

}

まとめ

このようにIE8とIE9では画像の読み込み時にloadイベントが動作しないというバグ?がありましたが、原因はブラウザのキャッシュでした。
キャッシュによりすでに画像が読み込まれてるためloadイベントが動作しないという事で、上記の方法で私自身も対処しました。

今回はイメージスライダーを作成している時に起こったバグだったのですが、こういった読み込み処理って大抵画像を複数枚読み込む時の処理が多いと思います。
画像のキャッシュを防く為に画像パスに現在時刻を付ける方法は、あまり枚数が多いと速度が遅くなった時などに時間がかかったりするのでお勧めできない方法ですね。