jqueryのanimateでbackground-positionを動かそう

この記事はだいぶ前に書かれたものなので情報が古いかもしれません

※この記事の内容で動かすことが赦されるのは、小学生までだよね~……じゃなくって、ここに書いてあることは、jqueryのバージョンが1.7以下の場合に有効なようです。バージョン1.8以降を使ってる人は、こっちの記事(jquery1.8にしたらanimateでbackground-positionを動かせなくなったって人は挙手をどうぞ)をよろしくよろしこ。

(11月8日追記)






jqueryのおかげで様々なアニメーションを簡単に実装できるようになった。

一昔前はflashを埋め込まないと実現できなかったような動きもjqueryのおかげで、flashを知らない、phpとjavascriptくらいしか知らない僕みたいなプログラマでも実現できるようになった。

また、jqueryの普及に伴いプラグインの数も大量に増えたため、かなり複雑な動きでもほんの1、2行コードを書くだけでできるようになった。

便利な世の中になったものだ。

今回はそんなアニメーションの動きをちょっと補足するためのプラグインを紹介しておこうと思う。具体的にはタイトルにもある通り、背景画像を動かすためのプラグインである。



基本的なアニメーション

てなわけで、明日のためのその1。

やはりまずはアニメーションを見ておきましょうか。

$('#div1').click(function(){
  $(this).animate({
    width:'500px',
    height:'300px',
    opacity:'0.5'
  });
});

例えばこんな風に書くと、div1というidを持った要素をクリックしたときに要素がアニメーションします。

サンプル1

まあすげーざっくりなサンプルですが、一応動きが確認できます。試しにクリックしてみてください。

要はあれですね。cssで指定されている数値を離散的ではなく滑らか~に動かすことができるってことですね。


cssには背景の位置を指定するbackground-positionというのがありますが、じゃあこれもアニメーションで滑らかに動かせたらちょっとしたワンアクセントがつけちゃえるんじゃね? それってイケてね? とか、ちょっとjqueryを触った人なら誰でも一度は思うじゃないですか。思いますよね? 俺は思いました。

実際、あかつきのお宿もヘッダー……というかサイドメニューみたいなやつにマウスのカーソルを当てると、何か白い帯がにゅっと動いてるじゃないですか。あれはまさにアニメーションで背景画像の位置を動かしているのです。

と・こ・ろ・が。



background-positionには効かない?

やってみれば分かるんですけど、上の例と同じようにanimate()でbackground-positionを指定しても、上手く動いてくれないみたいです。

$('#div2').click(function(){
  $(this).animate({
    backgroundPosition:'200px 0px',
    opacity:'0.3'
  });
});

何でかはサンプル3の方で述べるので、今はちょっと置いときましょう。

とりあえず動かないんです。サンプル2をクリックしてみれば分かります。IEにいたってはエラーが発生してopacityすらアニメートしない。まあ、IEは元々デフォルトじゃ透過ができないんですけど。

サンプル2

jqueryのバージョンが古い頃は動いていたような気がしなくもないんですけど、気のせいだったのかな。

まあ何にしてもこのままじゃ望む動きは得られないので、何とかしてみましょう。



x軸だけを動かしたいのなら

解決方法は大きく分けて2つあるのですが、そのうちの一つ『x軸だけ動かせれば良い場合』の解決法は、わりと簡単です。

$('#div3').click(function(){
  $(this).animate({
    backgroundPosition:'200px',
    opacity:'0.3'
  });
});

『200px 0px』って書いてあるところを『200px』だけにすればオッケーです。

サンプル3

どうやらanimate()のcssプロパティは1つの数字しか受け付けないようになっているらしいので、値を1つだけ指定してやれば問題なく動くわけですね。

実際、サンプル3は動いてると思います。

でもこれだと、x軸方向にしか動きが実装できない。あかつきのお宿もそうですが、横にしか動かさない仕様であればそれでも良いと思うんですけど、横が動かせんなら縦も行きたいだろ普通って思う人もいるかもしれません。



プラグインの導入

こちらの楽しければいいのです。さんのページでも紹介されているのですが、background-positionを動かすためのjqueryプラグインというのがあるようです。

名前もそのままbackgroundPositionみたいですね。

これを入れるだけで、jqueryのアニメーションにbackground-positionが使えるようになります。

ちなみにコードの中身はこんなんです。わりと短い。

$.extend($.fx.step,{
  backgroundPosition: function(fx) {
    if (fx.state === 0 && typeof fx.end == 'string') {
      var start = $.curCSS(fx.elem,'backgroundPosition');
        start = toArray(start);
        fx.start = [start[0],start[2]];
        var end = toArray(fx.end);
        fx.end = [end[0],end[2]];
        fx.unit = [end[1],end[3]];
      }
      var nowPosX = [];
      nowPosX[0] = ((fx.end[0] - fx.start[0]) * fx.pos) + fx.start[0] + fx.unit[0];
      nowPosX[1] = ((fx.end[1] - fx.start[1]) * fx.pos) + fx.start[1] + fx.unit[1];           
      fx.elem.style.backgroundPosition = nowPosX[0]+' '+nowPosX[1];
        
     function toArray(strg){
       strg = strg.replace(/left|top/g,'0px');
       strg = strg.replace(/right|bottom/g,'100%');
       strg = strg.replace(/([0-9\.]+)(\s|\)|$)/g,"$1px$2");
       var res = strg.match(/(-?[0-9\.]+)(px|\%|em|pt)\s(-?[0-9\.]+)(px|\%|em|pt)/);
       return [parseFloat(res[1],10),res[2],parseFloat(res[3],10),res[4]];
     }
  }
});

これを入れておくと、サンプル2みたいな書き方でbackground-positionを動かすことができます。

サンプル4、5、6。

4は横方向だけ。5は縦方向だけ。6は両方を動かしてます。

$('#div4').click(function(){
  $(this).animate({
    backgroundPosition:'200px 0px',
    opacity:'0.3'
  });
});

$('#div5').click(function(){
  $(this).animate({
    backgroundPosition:'0px 200px',
    opacity:'0.3'
  });
});

$('#div6').click(function(){
  $(this).animate({
    backgroundPosition:'200px 100px',
    opacity:'0.3'
  });
});

これで背景を変幻自在に動かせます。やったね!

……と、思いきや。



暗躍するIE

やはりと言うべきか、こういうときに立ちはだかって来やがりますのがIEというブラウザでして……相変わらずディフェンスに定評がありますね。

実際、サンプル4、5、6をIEで見れば分かるんですが、動きません。クリックするとjavascriptエラーが出ます。

プラグインのコードの4行目を見てほしいんですが、『var start = $.curCss・・・』みたいなコードがありますよね。

この$.curCssってのはcssの属性値を取って来るメソッドらしくて、つまりここではエレメントのbackground-positionを取ろうとしてるわけなんですが、IEだとこれが上手く取れていないらしくて、startをアラートしてみれば分かるんですが、『undefined』が帰って来てます。つまり取得できてないってことですね。他のブラウザでは『200px 0px』みたいな値が返って来ます。

たぶんなんですけど、このcurCssってやつはIEだと単一の値しか取れないのかな……? きちんと検証したわけじゃないんですけど。

でも逆に言えば単一の値なら取れるわけでして、だから4行目をこんな感じに書き換えると、上手く値が取れるようになります。

//書き換え前
var start = $.curCSS(fx.elem,'backgroundPosition');

//書き換え後
var x = $.curCSS(fx.elem,'backgroundPositionX');
var y = $.curCSS(fx.elem,'backgroundPositionY');
var start = x+' '+y;

要はbackground-positionのxとyのそれぞれを別個に取得して、自分で『200px 0px』みたいな値を作ってあげるってことですね。

これだとIEでも動くようになります。

今度こそやったね!!

……と、見せかけて。



今度は火狐さんが……

というわけでですね。

書き換えた後は今度はfirefoxで動かなくなりまして……参っちゃいますねぇ、ほんとに。

safariやchromeはどっちの状態でも大丈夫みたいなんですが、このままだとIEかfirefoxのどちらかを切り捨てなければならない。「ならIE捨てればぁ?」って言われたら「うん、そうだね!」って満面の笑顔で返したいとこなんですけど、一応あかつきのお宿は7は捨てましたが8は捨てなかったので、一応頑張ることにします。

結論だけ書くと、最終的にこうしました。

if($.browser.msie) {
  var x = $.curCSS(fx.elem,'backgroundPositionX');
  var y = $.curCSS(fx.elem,'backgroundPositionY');
  var start = x+' '+y;
} else {
  var start = $.curCSS(fx.elem,'backgroundPosition');
}

IEだったら別個に取る方式に変えるって感じですね。まあ、やってることはそれだけです。

これだとあまりスマートではないかもしれないけど、一応IEでもfirefoxでも動く。

サンプル7、8、9

$.browserは今は推奨されてなかったような気もするけど……まあそれは良いことにしましょう。



このプラグイン、なかなか素敵なんで使ってる人もいると思うんですけど、実はこっそりIE7や8だと動いてなかったりするので、注意が必要っす☆

前回の記事でブラウザチェックはやった方がいいぞ~的なことを言いましたけど、早速その必要性を感じる話が出て来ましたね。

やっぱり必要なんすよ、うん。



あ、そうそう

言い忘れてましたが、今回のサンプルみたいに背景に単一な色の画像を当てるようなときは、background-repeatはなしでお願いします。

x方向にアニメーションしたい場合はrepeat-xをやっちゃうと、y方向にアニメーションしたい場合はrepeat-yをやっちゃうと、動かない……というか、動いてはいると思うんですけど、背景画像がリピートしちゃってるので、動いてるように見えないのです。

実際サンプルページではbackgroundはno-repeatにしてます。

あ3 2013年11月07日 02:50:12
勉強になりました!
これからもブログ更新たのしみにしてます
まっち~(管理人) 2013年11月09日 11:30:06
>あ3さん
ありがとうございます!
そう言っていただけるとすごく励みになります。
もしかしたら何か関連しているかも?