ちいつる

ボタン・クリック演出

リップル波紋ボタン

クリックした位置から波紋が広がる。Material Designでおなじみの「押した手応え」。

ENGLISH

Ripple Effect

  • JS
36ボタン・クリック演出 の一覧 →

プレビュー

クリック

操作クリック/タップで動きます。

使いどころ

押した瞬間に「効いた」と伝えたいボタン全般に向く。とくにフォームの送信ボタンやモバイルの主要アクションのように、押してから結果が出るまでに一瞬の間があるUIで効果が大きい。波紋はタップ位置から広がるので、指で隠れて見えないモバイルでも「自分が触った場所が認識された」という手応えを返せる。逆に、テーブルの行やリスト項目のように一画面に何十個も並ぶ要素へ付けると、スクロール中の誤タップごとに波紋が走って画面が騒がしくなるため向かない。また、押した直後に画面全体が切り替わる遷移ボタンでは、波紋が広がりきる前に消えて演出が中途半端になる。その場合は波紋ではなく、遷移先のローディング表示に投資した方が体験がよくなる。

仕組み

仕組みは「クリック位置に円を1つ置いて、transform: scale() で拡大しながら opacity を0に落とす」だけ。ボタンに position: relative と overflow: hidden を与え、生成した span を絶対配置することで、円がボタンの角丸からはみ出さずに切り取られる。円の中心をクリック位置に合わせるには、getBoundingClientRect() でボタンの位置を取り、event.clientX から差を引いて座標を出す。半径はボタンの対角線の長さを基準にすると、どの位置を押しても端まで波紋が届く。アニメーション対象を width/height ではなく transform に限定するのが要点で、transform と opacity はコンポジタだけで処理できるためレイアウトの再計算が起きない。終了後は animationend か setTimeout で span を削除し、DOMに要素が積み残らないようにする。

実装の注意

最も多い失敗は overflow: hidden の付け忘れで、波紋が四角く飛び出してボタンの形が崩れる。次に多いのが span の削除漏れ。連打されるとDOMに数百個の空要素が残り、長時間開いたままの画面で少しずつ重くなる。連打対策としては、既存の波紋を消してから新しい波紋を出すか、同時に存在できる数を1〜2個に制限する。波紋の色はボタンの背景色に対して十分なコントラストが必要で、濃い背景に濃い波紋を置くと動いていることがわからない。白の透明度20〜40%あたりが無難だが、明るい背景のボタンでは黒系の半透明にする。iframe のプレビューでは親ページのスクロール位置が影響しないが、実ページで position: fixed の要素の中に置く場合は座標計算の基準がずれることがあるので、必ず getBoundingClientRect() の値を使い、offsetLeft のような累積値に頼らない。

アクセシビリティ

波紋は装飾なので、支援技術に読ませる必要はない。生成する span には aria-hidden="true" を付け、ボタンのラベルが波紋の要素で汚れないようにする。重要なのは prefers-reduced-motion への対応で、動きに酔いやすいユーザーの設定を尊重して @media (prefers-reduced-motion: reduce) では波紋を出さない(もしくは拡大せず一瞬の色変化だけにする)。このとき「押した手応え」がゼロになると困るので、代わりに背景色をわずかに変える:active スタイルを必ず用意しておく。また、キーボードで操作するユーザーはクリック座標を持たないため、Enter や Space で発火したときは中心から波紋を出す分岐が必要になる。:focus-visible のアウトラインを波紋の演出で消してしまわないことも忘れないでほしい。

調整して使う

触る値は3つ。波紋の持続時間(0.6秒が既定。長くすると余韻が出るが連打に弱くなるので0.4〜0.8秒の範囲)、波紋の色と透明度(明るい背景のボタンなら rgba(0,0,0,.15)、濃い背景なら rgba(255,255,255,.35) から調整)、そして最終的な拡大率(ボタンの対角線を基準に2〜2.5倍あれば端まで届く)。落ち着いた印象にしたいときは、拡大しきる前に opacity を0へ向かわせるのではなく、拡大の終盤で一気に消す ease-out 寄りのイージングにすると上品になる。ブランドカラーを波紋に使うと押した瞬間だけ色が差し込む表現になり、テキストボタンのような装飾の少ないボタンでも存在感を出せる。

コード(コピーして使えます)

<button class="ripple-btn">クリックしてみて</button>

タグ

関連パーツ