ある要素の上にマウスポインタがきた時、その要素に対してドロップシャドウがかかったように見えるスクリプトを作ってみた。
昔は、例えば写真やイラスト等imgタグに対してこういう処理を行いたい時は通常表示用の画像と、マウスポインタが上に乗ったときに表示する「ロールオーバーイメージ」の2つの画像を作る事で対応していた。

最近ではCSSの:hover疑似クラスを使う方が多くなったが、いずれにしても2枚の画像を作らなければならない。
写真が増えたり変更されたりした時はその度にその作業は必要になってくる。
しかも画像によって陰の大きさや濃さがバラバラになるとみっともないので作った方法はしっかりメモしておかなくては駄目だ。

今回はシャドウ用のpng画像を6枚作り、それらをCSSの'position'プロパティや'top'、'left'('bottom'、'right')プロパティを使い、適切な場所に配置して実現させている。
ソースコードは以下のような感じだ(prototype.jsが必要)。

var Shadow = Class.create();
Shadow.prototype = {
    initialize: function(width, height, top, left) {
        this.imgPixel = 8;
        this.shadowParts = [{
            position: 'absolute',
            width: width + 'px',
            height: height + 'px',
            top: top + 'px',
            left: left + 'px',
            backgroundColor: '#7f7f7f'
        },
        {
            width: width + this.imgPixel + 'px',
            height: this.imgPixel + 'px',
            top: -this.imgPixel + 'px',
            left: -this.imgPixel + 'px',
            backgroundImage: 'url("images/tl.png")'
        },
        {
            width: this.imgPixel + 'px',
            height: this.imgPixel + 'px',
            top: -this.imgPixel + 'px',
            right: -this.imgPixel + 'px',
            backgroundImage: 'url("images/tr.png")'
        },
        {
            width: this.imgPixel + 'px',
            height: height + 'px',
            top: '0px',
            left: -this.imgPixel + 'px',
            backgroundImage: 'url("images/l.png")'
        },
        {
            width: this.imgPixel + 'px',
            height: height + 'px',
            top: '0px',
            right: -this.imgPixel + 'px',
            backgroundImage: 'url("images/r.png")'
        },
        {
            width: width + this.imgPixel + 'px',
            height: this.imgPixel + 'px',
            top: height + 'px',
            left: -this.imgPixel + 'px',
            backgroundImage: 'url("images/bl.png")'
        },
        {
            width: this.imgPixel + 'px',
            height: this.imgPixel + 'px',
            top: height + 'px',
            right: -this.imgPixel + 'px',
            backgroundImage: 'url("images/br.png")'
        }];
        this.container = new Element('div');
        this.container.setStyle(this.shadowParts.shift());
        for (i = 0; i < this.shadowParts.length; i++) {
            var elem = new Element('div');
            elem.addClassName('iepngfix');
            elem.setStyle(Object.extend({position: 'absolute', backgroundRepeat: 'no-repeat'}, this.shadowParts[i]));
            this.container.insert(elem);
        }
    }
};

使い方は

var shadow = new Shadow(100, 100, 100, 100);

として高さ、横幅、X座標、Y座標を100ピクセルとした陰を作り

$$('body')[0].insert(shadow.container);

とし、ボディ要素に挿入させる。
こちらのサンプルページでは大きさの違う写真を何枚か配置し、それらにマウスポインタを持っていくとシャドウが適用されるようになっている。
ただし写真とシャドウは何も関連性を持っていないので(あくまで座標で位置をあわせているだけなので)たとえばウィンドウのリサイズや要素のドラッグ等で写真の位置が変わってもシャドウ自体はそれを追っかけてきてはくれない。
上のページだとマウスアウトすればシャドウは消えてしまうので問題ないが例えばこちらのページではウィンドウのサイズを変えて写真がレンダリングし直されてもシャドウはそのままの位置に留まってしまっている。

この場合はなんとか写真とシャドウをグルーピングして2つの要素の座標を同期させるようなコーディングが必要になってくる。

このサンプルページではそれらに対応し、写真をドラッグしてもシャドウと一緒に動くようにしている。
上のコードはオブジェクト内はコンストラクタしか存在しないが、

シャドウの大きさや座標を変えるメソッド。
それらを'setTimeout'を使いアニメーションのように見せるメソッド。

を追加する事によってこちらのサンプルページの様な効果を出す事も出来るようになる。
それぞれ

sizeAndPositionChanged: function(width, height, top, left) {
    var parts = $A(this.container.childNodes);
    parts[0].setStyle({width: width + this.imgPixel + 'px'});
    parts[2].setStyle({height: height + 'px'});
    parts[3].setStyle({height: height + 'px'});
    parts[4].setStyle({width: width + this.imgPixel + 'px', top: height + 'px'});
    parts[5].setStyle({top: height + 'px'});
    this.container.setStyle({
        width: width + 'px',
        height: height + 'px',
        top: top + 'px',
        left: left + 'px'
    });
},
moved: function(aimedWidth, aimedHeight, aimedTop, aimedLeft, frequency) {
    this.container.setOpacity(0.3);
    var that = this;
    var width = parseInt(this.container.getStyle('width'));
    var height = parseInt(this.container.getStyle('height'));
    var top = parseInt(this.container.getStyle('top'));
    var left = parseInt(this.container.getStyle('left'));
    var moveWidth = (aimedWidth - width) / frequency;
    var moveHeight = (aimedHeight - height) / frequency;
    var moveTop = allocationIsChanged((aimedTop - top), frequency);
    var moveLeft = allocationIsChanged((aimedLeft - left), frequency);
    setTimeout(function() {
        width += moveWidth;
        height += moveHeight;
        top += moveTop.shift();
        left += moveLeft.shift();
        that.sizeAndPositionChanged(width, height, top, left);
        frequency--;
        if (frequency > 0) setTimeout(arguments.callee, 15);
        else that.container.setOpacity(1.0);
    }, 15);
}

とこんな感じのコードを追加すればいい。
今回のスクリプトは画像を使うので画像ファイルのパスに注意しなければならなかったり、IE6でpng画像を表示させる為に'iepngfix.htc'が必要だったりとなにかと事前の準備が必要だが、写真を2枚ずつ作るよりは全然楽だろう。
応用すればドロップシャドウだけではなく例えば角丸なんかにも使えそうだ(またそれ用の画像ファイルが必要になるが)。

カテゴリ:

トラックバック(0)

トラックバックURL: http://blog.beanz-net.jp/beanz_mtos/mt-tb.cgi/48

コメントする