角丸幅可変ボタンでクロスフェードをする

角丸幅可変ボタン

角丸の幅可変ボタンを作ろうと思うと割と面倒くさいんですけど
さらにクロスフェードさせたい(実質クロスフェードではないんですが)
という欲望に負けてやってみました。

完成サンプル
サンプルファイルのダウンロード

とりあえずMacでしか確認してないのでIEとかどうなるかわかりません。
IE6で崩れてたのでCSSを修正しました。

角丸可変ボタンのHTML

そもそも角丸幅可変のボタンを作ろうと思うと要素の入れ子は避けられません。
下のような感じになります。


SUBMIT

ムダな要素はJSで…
でもいいですけど、ここはデザインに直接影響するところなので
HTML+CSSだけでやったほうがいいです。
中のSPANはあきらめてください。僕は気にしてません。

角丸可変ボタンのCSS

これにCSSを書いていくと
たぶん以下みたいな感じになると思います。
ボタンは2つ以上並ぶ事も想定します。

使う画像は次の2つです。

ボタン左 ボタン右


p.btn {
  overflow: hidden;
}

  p.btn a {
    float: left;
    padding-left: 5px;
    color: #fff;
    background: url(../../img/btn_left.gif) no-repeat left top;
    text-decoration: none;
  }

    p.btn a span {
      padding: 0 20px 0 15px;
      display: block;
      height: 35px;
      background: url(../../img/btn_right.gif) no-repeat right top;
      line-height: 35px;
      cursor: pointer; /* for IE */
    }

最近は結構普通にinline-block使ってます。
floatで書きなおしました。

クロスフェードを実現するには

問題はここからですが
クロスフェードをさせるとなると、背景画像を2枚重ねていないとできません。
背景画像を入れ替えれば…CSS Spriteを使ってたらそういうわけにもいきません。

元々あるボタンの下にフェード後のボタンを配置して
mouseover時に上のボタンをフェードアウトさせればうまくいきそうです。

構造としては
- フェード後のボタン
- 元々あるボタン
を並列に並べて、
フェード後のボタンが元々あるボタンの下にくるようにする必要があるので
2つのボタンをグループ化して、
フェード後のボタンを絶対配置でグループの左上に配置します。

具体的には下のHTMLのようになります。



  
    
      SUBMIT
    
  
  
    SUBMIT
  

jQueryを使って構造を変える

さすがにこれは汚いので、jQueryで構造を変更しましょう。
グループを識別するためにidを割り当ててます。


$("a","p.btn").each(function(){
  $(this).replaceWith("");
  // 既存のボタンをグループと置き換える
  $("span#cfG"+i)
    .append(""+$(this).text()+"")
    .append($(this).clone());
    // フェード後のボタンを追加したのち
    // 既存のボタンをその後ろに追加する
});

CSSを追記する

さらにCSSを追記します。


p.btn span.cfGroup {
  float: left;
  position: relative;
}

  p.btn span.cfGroup span.cfGM {
    position: absolute;
    top: 0;
    left: 0;
    z-index: 10;
  }

    p.btn span.cfGroup span.cfGLeft {
      float: left;
      padding-left: 5px;
      color: #fff;
      background: url(../../img/btn_left.gif) no-repeat left -35px;
      text-decoration: none;
    }

      p.btn span.cfGroup span.cfGLeft span.cfGRight {
        padding: 0 20px 0 15px;
        display: block;
        height: 35px;
        background: url(../../img/btn_right.gif) no-repeat right -35px;
        line-height: 35px;
      }

さらにこのままだと、
既存のボタンとフェード後のボタンの重なりが逆になるので
z-indexを大きい数値にしておきます。
z-indexを使う場合は、position: relativeにする必要があります。


p.btn a {
  float: left;
  padding-left: 5px;
  position: relative;
  z-index: 100;
  color: #fff;
  background: url(../../img/btn_left.gif) no-repeat left top;
  text-decoration: none;
}

上のボタンをフェードさせて実現する

ここまでくればあとは、
hover時に上に乗ってるボタンをフェードアウトさせるだけです。


$("a","p.btn").each(function(){
  $(this).replaceWith("");
  $("span#cfG"+i)
    .append(""+$(this).text()+"")
    .append($(this).clone());

  // ここから下がフェード
  $("a","span#cfG"+i).hover(function(){
    $(this).fadeTo("normal",0);
  },function(){
    $(this).fadeTo("normal",1);
  });
});

ポイント

フェードさせるときの注意がひとつだけあって
fadeOutにすると、最終的にdisplay: noneになるので
グループの幅と高さがなくなって、下にある要素が上に詰まります。
なので、ここではfadeToでOpacityのみを操作しています。

ここまでのサンプル

連続でホバーさせたときに動作が…

A要素にhoverするとfadeToが呼び出されて
フェードアニメーションが実行されますが連続でhoverさせると
アニメーションキューがたまっていって、ぴかぴかします。

これを解決するにはfade実行時に
直前のアニメーションキューを削除すればいいので


// ここから下がフェード
$("a","span#cfG"+i).hover(function(){
  $(this).queue([]).fadeTo("normal",0);
},function(){
  $(this).queue([]).fadeTo("normal",1);
});

queue([])でアニメーションキューを空にすればぴかぴかしなくなります。

完成サンプル
サンプルファイルのダウンロード

あ、、

このサンプルなら画像を2つに分ける必要はなかったですね…

何か役に立つことがあったらシェアしてみてください

このエントリーをはてなブックマークに追加

Comments: 1 - Leave a comment

  1. Hi! I like your srticle and I would like very much to read some more information on this issue. Will you post some more?

Leave a comment

Trackbacks: 0

Trackback URL for this entry
Listed below are links to weblogs that reference
角丸幅可変ボタンでクロスフェードをする from 5509

Author

nori
nori
- UI Engineer
Location
- ,