<button type="button" class="bnto-ripple" data-bnto-ripple> クリックしてみて </button>
.bnto-ripple { --c1: hsl(202 73% 50%); /* ボタン色 */ position: relative; overflow: hidden; padding: 13px 28px; border: none; border-radius: 12px; background: var(--c1); color: #fff; font: inherit; font-weight: 800; cursor: pointer; } /* JSが生成する波紋。終わったら自動削除される */ .bnto-ripple .rp { position: absolute; border-radius: 50%; background: rgba(255,255,255,.45); transform: scale(0); animation: bnto-rip .6s ease-out forwards; pointer-events: none; } @keyframes bnto-rip { to { transform: scale(2.6); opacity: 0; } }
// クリック位置から波紋を生成 → animationend で自動削除 (function () { var reduced = window.matchMedia('(prefers-reduced-motion: reduce)').matches; document.querySelectorAll('[data-bnto-ripple]').forEach(function (btn) { if (btn.dataset.bntoInit) return; btn.dataset.bntoInit = '1'; btn.addEventListener('click', function (e) { if (reduced) return; // 動きを減らす設定では演出をスキップ var r = btn.getBoundingClientRect(); var size = Math.max(r.width, r.height); var x = e.clientX ? e.clientX - r.left : r.width / 2; var y = e.clientY ? e.clientY - r.top : r.height / 2; var rp = document.createElement('span'); rp.className = 'rp'; rp.style.width = rp.style.height = size + 'px'; rp.style.left = (x - size / 2) + 'px'; rp.style.top = (y - size / 2) + 'px'; btn.appendChild(rp); rp.addEventListener('animationend', function () { rp.remove(); }); }); }); })();
使い方のコツ
Material Design でおなじみの「押した感」演出です。波紋の色は .rp の background で調整できます。明るい色のボタンなら rgba(0,0,0,.15) の黒波紋も自然です。親要素の overflow: hidden が波紋のはみ出し防止に必須です。