TECH BOX

Technology blog from Web Engineer

この記事は最終更新日から6年以上経過しているため正確ではないかもしれません

Google Material Design Lite風ボタンアクション

Google Material Designはここ数年盛り上がっている話題ですが、そのGoogle Material Designをテンプレートとして利用できるGoogle Material Design Liteというのがあります。

その中のボタンアクションを見るとWith rippleだとクリックした所から薄いレイヤーが伸びてくるのが気になったので模倣してみた。

See the Pen Button Action by Nobuyuki Kondo (@artprojectteam) on CodePen.0

CSSは解析が簡単でしたが、JSは解析するのに時間かかりそうだったのでオリジナルです。
Promiseとか使ってスッキリさせれば良かったのですが、そこは改善の余地がまだまだあるということで。

どんなアクションなのか

Google Material Design Lite(以下、GMDL)のボタンアクションは下記のようになります

  • マウスクリックをした所から白いレイヤーが大きくなる
  • マウスクリックから離れる(mouseup)と白いレイヤーは透過になる

HTML

ボタンの構造はテキストとレイヤーを別々に作ります

<button class="button circle jsClick-Action" type="button">
  <span class="button-text">+</span>
  <span class="button-layer">
    <span class="button-layer-contents jsLayer"></span>
  </span>
</button>

CSS

レイヤーはabsoluteにしておきます。
※実際にはもっといろんなことを書きますが必要なことだけ抜き出しています

.button {
  overflow: hidden;
  position: relative;
  border: none;
  z-index: 10;
}

.button-layer {
  position: absolute;
  top: 0;
  left: 0;
  overflow: hidden;
  z-index: 0;
  display: block;
}

.button-layer-contents {
  border-radius: 50%;
  position: absolute;
  top: 0;
  left: 0;
  -webkit-transform: translate(-50%, -50%);
          transform: translate(-50%, -50%);
  overflow: hidden;
  opacity: 0;
  background: #fff;
  pointer-events: none;
}

これで表示側の準備はできたので、挙動がどうなっているのかを説明します。

Java Script

クリック時に表示する白いレイヤーはどう作ってるのか

マウスクリックをしたらそのボタンの大きさとセンター位置を取得し、ボタンの大きい方を基準に2倍のレイヤーを生成。

$('xxx').on({
  'mousedown': function(e){
    this._self = $(e.currentTarget);

    // button size
    let button_w = this._self.width();
    let button_h = this._self.height();

    // layer size
    let scale = 2;
    let new_size = Math.max(button_w, button_h);
    let w = new_size * scale;
    let h = new_size * scale;
  }
});

これで、十分な大きさのレイヤーを確保しました。

クリック時のレイヤーの位置決め

次にボタンクリックした所からレイヤーがでてこなければいけないので、位置を決めます。
ここでそもそもやっておく必要があるのがレイヤー自体はあらかじめCSSでtranslate(-50%,-50%)しておくということ(もちろんabsoluteも必要です)

なぜ、これが必要かというとこの値でレイヤーがボタンの右端に位置するようになるからです。

ボタンに関する情報を取得

クリックされたボタンのサイズと座標を取得し、ボタン内から何pxのところにいるかを計算。

// button size
let button_w = this._self.width();
let button_h = this._self.height();
let center_x = button_w / 2;
let center_y = button_h / 2;

// button position
let offset = this._self.offset();
let button_x = offset.left - e.pageX;
let button_y = offset.top - e.pageY;

レイヤーのx,y座標を調整する

ボタン自体の中心値とクリック座標を元に何px戻すかを計算

// layer position
let x = center_x - (center_x + button_x);
let y = center_y - (center_y + button_y);

これでレイヤーの準備は整ったのでアニメーションさせる

アニメーション前準備

  1. 軽くopacityを掛ける(0.3くらい)
  2. アニメーションのイージングをリセットする
  3. width/heightとtransformをセットする

1と2に関してはクラスの付替えで対応する
3に関しては下記のようにする

hoge.css({
  width: w,
  height: h,
  transform: 'translate(-50%,-50%) translate(' + x + 'px, ' + y + 'px) scale(0.0001, 0.0001)'
})

ここではscaleを使ってレイヤーを小さくしておきます。

setTimeoutを使って実行を段階的に行う

すぐに実行するとうまくいかないので150ms後くらいにopacity:0.3とイージングのクラスを付与。
さらにその50ms後くらいにscaleを削除。

setTimeout(function(){
  hoge.addClass('doAnimate isVisible');   // このクラスがopacityとイージングを定義しているクラス

  setTimeout(function(){
    hoge.css({
      transform: 'translate(-50%,-50%) translate(' + x + 'px, ' + y + 'px)'
    });
  }, 50);
}, 150);

これでレイヤーの白い円がクリックした位置から大きくなります。

クリック終了でレイヤーを透過させる

指を離すと透過させる処理をしますが、その時もsetTimeoutで少しずらします。

$('xxx').on({
  'mouseup': function(){
    setTimeout(function(){
      hoge.removeClass('isVisible');
    }, 150);
  }
});

これで、GMDL風のアクションを実装することが出来ました。
ソースコードはCode Penでそのまま確認できるので、詳しくはそれを確認して下さい。

See the Pen Button Action by Nobuyuki Kondo (@artprojectteam) on CodePen.0