2013/11/28

jquery.imagecrossfade.jp

jQueryを 1.7.x から 2.0.x に、jQueryUIを 1.8.xから 1.10.xにそれぞれ移行中。どちらも ver. 1.9からいろいろなメソッドやらプロパティやらが廃止・統合されている。プラグインとして利用しているスクリプトが動かなくなることが多く、大概は最新版でなんとかなるが、既にサポートされていないスクリプトがやっかい。

その中の一つ、Image Cross Fade。これはオンマウスの時にクロスフェードで画像を入れ替える機能。このなかで廃止されたbrowserというプロパティを使っている。同等機能を提供するプラグインがないか探したりした。jQueryUIでも tabsウィジェットから rotate機能が廃止されたが、これはjQuery-UI-Tabs-Rotateというプラグインを追加してなんとかした。しかし、browserプロパティは今後もメンテナンスが必要になるかもしれないと思い、Image Cross Fadeに代わる別のプラグインを探そうと思ったのだが、幸いソースが割と短くて、自分で何とかできそうだったので、javascriptを思い出すためにもやってみた。

このスクリプトが何をやっているかを確認。切り替え後の画像を <img src="foreimage" class="fade" style="background-image: url(backimage);">中の style (css) から background-imageを抜き出す。
var target = $$.css('backgroundImage').replace(/^url|[\(\)'"]/g, '');
<img src="foreimage" class="fade" ...>に<span>を被せて、さらにそのspanの子(<img src="foreimage" class="fade" ... >の兄弟)として先ほど抜き出した background-image (target) を追加する。
$$.wrap('')
  .parent()
  .prepend('')
  .find(':first-child')
  .attr('src', target);
これで見かけ上のhtmlは

  
  

となった。この状態だと2つのimg が横に並んだ状態なので、重ね合わせるために一方のimgに絶対位置(position: absolute)を指定し、<span>からの距離 top/leftを指定する。このとき、topの解釈がブラウザ毎に違うらしく、browserプロパティで指定を振り分けている。
if ($.browser.msie || $.browser.mozilla) {
  $$.css({ 'position' : 'absolute', 'left' : 0, 'background' : '', 'top' : this.offsetTop });
} else if ($.browser.opera && $.browser.version < 9.5) {
  $$.css({ 'position' : 'absolute', 'left' : 0, 'background' : '', 'top' : "0" });
} else { // Safari
  $$.css({ 'position' : 'absolute', 'left' : 0, 'background' : '' });
}
最後に imgの hoverに animateで opacityを調節するメソッドを追加し、実際に <img src="foreimage" class="fade" ... />にマウスが乗ると、前部にある画像が透けていき、後部にある画像が浮き上がってくるという算段。

で、最初は browerメソッドの代わりにユーザーエージェントを云々と考えるが、どのブラウザのどのバージョンがどんな挙動をするのかなんて、これまでの物もこれからの物もわからない。ならばどうしようと、要は position: absolute なんかを使わなければ良いわけである。

2枚の画像を重ね合わせる方法として、以前に使った方法を思い出し、wrapした spanの背景にする。こうすればブラウザが勝手に重ね合わせてくれる。早速 spanの背景に画像を指定するが、spanはインライン用素なためちゃんと幅と高さを計算してくれないみたいでずれてしまった。ならば最初からブロック要素の divに。おぉ。

ソースの変更は、先の $$.wrap('<span style="position: relative;"></span>')から browser判定分までごっそり削除し、
$$.wrap('
');
という文を追加。これで見かけ上の htmlは
コメントを省略した最終的なソース
(function ($) {
  $.fn.cross = function (options) {
    return this.each(function (i) {
      var $$ = $(this);
      var target = $$.css('backgroundImage').replace(/^url|[\(\)'"]/g, '');
      $$.wrap('
'); $$.hover(function () { $$.stop().animate({ opacity: 0 }, 250); }, function () { $$.stop().animate({ opacity: 1 }, 250); }); }); }; })(jQuery); $(window).bind('load', function () { $('img.fade').cross(); });
作者のページをよく見直してみた。すると、ここで問題になっていたブラウザ毎の振り分けロジックは入ってなかった。どうやら別の人が改造した物を使っていた様子。まぁ、根本的な解決ができたと思って良しとしよう。background-imageに問題がないと言うことを祈りつつ。

0 件のコメント:

色々な画像ファイル形式をhtmlに埋め込む(PHP)

画像をhtmlに埋め込む際、単一の場合は img/src、複数の拡張子を指定すると img/source/srcsetに展開してくれる便利関数。また、単一拡張子のみが指定されている場合は、ブラウザのサポート状況に応じ、avifやwebpの拡張子を持つ同名のファイルがある場合は[a...