最近やたらと画像が大量に貼り付けられているブログをみると、ページを読み込むだけでとんでもない容量がダウンロードされてしまい、パケットの無駄使いもたいがいにして欲しいサイトがあります。
どこのサイトかは言いませんが・・・
そんなサイトのHTMLヘッダに貼り付けておくだけで、画像を遅延読み込みしてくれて、サーバーにも、閲覧している人にも、やさしいプログラムを作ってみました。
遅延読み込みとは?
HTMLの構造を簡単に説明すると、WEBページでは、HTMLソースというテキストがブラウザにダウンロードされて、ブラウザが各タグやCSSにそってレンダリングを行う。
この際に特殊な動きをするものとして、Aリンクタグ、IMG画像タグ、HTML5の機能でもある、CANVASタグ、などがある。
Aリンクは言わずと知れた文字が青色になり、リンクするとURLアドレスを切り替えてくれる動作を追加してくれるもので、IMGタグは、JPEGやGIF、PNGと言った、WEBフォーマットの画像をブラウザに表示する仕事をします。
この時、画像は、ブラウザに一旦読み込まれてしまうので、ページ内に存在する画像は全てブラウザキャッシュに貯まるとともに、メモリにも展開されます。
そうです、画像が100枚書かれているページは100枚分の画像がブラウザに一気に読み込まれてしまうのです。
画像貼り付け掲示板などをみると、読み込みの際に非常に遅く感じるのはこのためです。
そこで、IMG画像タグのsrc属性を操作することで、初回の読み込みを高速化し、その後画像が画面に入ってきた段階でそれぞれの画像を読み込むようにしてみようと思います。
画像効率化はキャッシュでも有効
どのページでも同じ画像が使われる場合は、同じURLでセットしましょう。
サーバーリソースの無駄使いでもあるし、ユーザーのキャッシュの無駄使いにもなります。
キャッシュは、一度ダウンロードした画像ファイルを、同じURLをの画像であれば、キャッシュの有効期限までは再利用するという仕組みです。
ダウンロードしたら、自分のパソコン内に画像があるので、いちいちURLを見に行かずにローカルのパソコン内の画像を表示するという機能なんですね。
304機能という事で、ブラウザで確認することもできます。
lazyLoad.js
サンプルページを見てもらうと、動きがわかると思いますが、デバッグツールの「ネットワーク」をみてスクロールする度に画像が読み込まれることを確認しましょう。
※PCブラウザが確認しやすいです。スマホブラウザは開発ツールがないので、わかりにくいと思います。
サンプルページ
実際に使ってみたい人の為に
1.まず下記ライブラリをダウンロードします。
https://mynt-blog-tools.netlify.app/lazyload/lazyLoad.js
2.自分のページに設置し、以下のタグをheadタグ内に貼り付けます。
<script type="text/javascript" src="lazyLoad.js"></script>
JSのパスはそれぞれの環境に合わせてください。
注意
初回のバージョンでは、ページ内の全てのIMGタグを遅延読み込みするので、デザイン構成で画像を使っていたりすると、loading画像が読み込まれるまではページが崩れた表示になることがあります。
その場合は、下記の記述の箇所を適時変更して使ってください。
var imgs = document.getElementsByTagName("img");
## 特定のエレメント以下の画像だけにする場合
var imgs = document.getElementById("hoge").getElementsByTagName("img");
また、imgsのfor文の中に、特定のclass名やIDについて、除外(continue)処理をすると、ページに合った、遅延処理を行うことができます。
他にもloadingアニメ画像として読み込んでいるのは
imgs[i].src = "http://31.media.tumblr.com/6121c420e052ff53782d40806f0dc7d4/tumblr_nh1mchoRUh1sqqx06o1_500.gif";
の箇所になるのですが、他のサイトの画像を直リンクでそのまま使っているので、ご自身のサイトに著作権無料のアニメ画像をDLをしてお使いください。
基本的にはjQueryを使って同じような処理をすることも可能ですが、本プログラムはかなり軽量化してあるので、使い勝手はいいと思います。
また、読み込み座標などは、気に入らない場合は好きに書き換えてお使いください。
ソースコード
最後に、今回のライブラリのソースコードを載せておきます。
/**
* LazyLoad
**/
(function(){
var $$={};
//page-load-start
$$.start=function(){
$$.LIB.eventAdd(document,"DOMContentLoaded",$$.store);
$$.LIB.eventAdd(window,"scroll",$$.areaLoad);
setTimeout($$.areaLoad,1000);
};
//It sets loading-gif-animation for all images.
$$.store=function(){
var imgs = document.getElementsByTagName("img");
for(var i=0;i<imgs.length;i++){
imgs[i].setAttribute("data-img-src",imgs[i].src);
//loading-image
imgs[i].src = "http://31.media.tumblr.com/6121c420e052ff53782d40806f0dc7d4/tumblr_nh1mchoRUh1sqqx06o1_500.gif";
}
};
//It load inner-area-images.
$$.areaLoad=function(){
var win = $$.LIB.getBrowser();
var imgs = document.getElementsByTagName("img");
for(var i=0;i<imgs.length;i++){
var attr = imgs[i].getAttribute("data-img-src");
if(!attr){continue}
//check position
var pos = $$.LIB.pos(imgs[i]);
var size = $$.LIB.size(imgs[i]);
//console.log(win.size.y+"/"+(win.scroll.y + win.size.y *2) +">="+ (pos.y + size.y));
//console.log(pos.y+"/"+size.y+"/"+(win.scroll.y + win.size.y *2) +">="+ (pos.y + size.y));
if(win.scroll.x + win.size.x *2 >= pos.x + size.x
&& win.scroll.x - win.size.x <= pos.x
&& win.scroll.y + win.size.y *2 >= pos.y + size.y
&& win.scroll.y - win.size.y <= pos.y
){
//set image.
imgs[i].src = attr;
imgs[i].setAttribute("data-img-src","");
}
}
};
$$.LIB={
//event-library [$$.eventAdd(window,"load",$$.set);]
eventAdd:function(t, m, f){
//other Browser
if (t.addEventListener){t.addEventListener(m, f, false);}
//IE
else{
if(m=='load'){
var d = document.body;
if(typeof(d)!='undefined'){d = window;}
if((typeof(onload)!='undefined' && typeof(d.onload)!='undefined' && onload == d.onload) || typeof(eval(onload))=='object'){
t.attachEvent('on' + m, function() { f.call(t , window.event); });
}
else{f.call(t, window.event)}
}
else{t.attachEvent('on' + m, function() { f.call(t , window.event); });}
}
},
pos:function(e,t){
//エレメント確認処理
if(!e){return;}
//途中指定のエレメントチェック(指定がない場合はbody)
if(typeof(t)=='undefined' || t==null){
t = document.body;
}
//デフォルト座標
var pos={x:0,y:0};
do{
//指定エレメントでストップする。
if(e == t){break}
//対象エレメントが存在しない場合はその辞典で終了
if(typeof(e)=='undefined' || e==null){return pos;}
//座標を足し込む
pos.x += e.offsetLeft;
pos.y += e.offsetTop;
}
//上位エレメントを参照する
while(e = e.offsetParent);
//最終座標を返す
return pos;
},
size:function(e){
return{
x:e.offsetWidth,
y:e.offsetHeight
};
},
getBrowser:function(){
var scroll={x:0,y:0};
if(navigator.userAgent.indexOf("safari")!=-1){
scroll.x = window.scrollX,
scroll.y = window.scrollY
}
else if(window.pageXOffset!=undefined){
scroll.x = window.pageXOffset,
scroll.y = window.pageYOffset
}
else if(document.compatMode=='BackCompat'){
scroll.x = document.body.scrollLeft,
scroll.y = document.body.scrollTop
}
else{
scroll.x = document.documentElement.scrollLeft,
scroll.y = document.documentElement.scrollTop
}
return {
all:{
x:document.body.offsetWidth,
y:document.body.offsetHeight
},
size:{
x:window.innerWidth,
y:window.innerHeight
},
scroll:scroll
};
}
};
$$.start();
window.$$lazyLoad = $$;
return $$;
})();
0 件のコメント:
コメントを投稿