多重クリック防止の重要性
Webフォームやボタンで最も起こりやすいトラブルの一つが「多重送信」です。ユーザーがボタンを連続してクリックしてしまうと、同じデータが複数回送信されてしまう可能性があります。
この問題を視覚的に解決するのが、クリック位置から氷が広がって凍結するボタンエフェクトです。ユーザーに「処理中」であることを直感的に伝え、多重クリックを防ぎます。単なる無効化ではなく、氷で凍らせるという遊び心のある演出で、ユーザー体験を楽しくします。
作成した多重クリック防止ボタン
HTML
<button class="btn" id="btn-center">
<span>送信</span>
</button> CSS
.btn {
position: relative;
padding: 1rem 1.5rem;
width: 200px;
font-size: 1.125rem;
border: none;
border-radius: 12px;
cursor: pointer;
transition: all 0.3s ease;
overflow: hidden;
font-family: inherit;
background: #e5e7eb;
color: #111827;
}
.btn::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-image: url('https://pa-tu.work/storage/img/templates/ice.jpg');
background-size: cover;
background-position: center;
clip-path: circle(0% at 50% 50%);
z-index: 1;
}
.btn.frozen::before {
animation: expandIce 2s cubic-bezier(0.165, 0.84, 0.44, 1) forwards;
}
@keyframes expandIce {
0% {
clip-path: circle(0% at var(--click-x, 50%) var(--click-y, 50%));
opacity: 0.7;
}
50% {
opacity: 0.95;
}
100% {
clip-path: circle(150% at var(--click-x, 50%) var(--click-y, 50%));
opacity: 1;
}
}
.btn.frozen {
cursor: not-allowed;
color: #ffffff;
text-shadow: 0 1px 6px rgba(0, 0, 0, 0.25);
}
.btn span {
position: relative;
z-index: 1;
} JavaScript
const btn = document.getElementById('btn-center');
btn.addEventListener('click', function(e) {
const rect = this.getBoundingClientRect();
const clickPercentX = ((e.clientX - rect.left) / rect.width) * 100;
const clickPercentY = ((e.clientY - rect.top) / rect.height) * 100;
if (this.classList.contains('frozen')) {
this.classList.remove('frozen');
this.disabled = false;
this.style.removeProperty('--click-x');
this.style.removeProperty('--click-y');
} else {
this.style.setProperty('--click-x', clickPercentX + '%');
this.style.setProperty('--click-y', clickPercentY + '%');
this.classList.add('frozen');
this.disabled = true;
}
}); このボタンの特徴
- クリック位置検知 マウスのクリック位置を正確に取得し、その場所から氷のエフェクトが広がります
- リアルな氷テクスチャ 背景画像に氷の質感を使用し、視覚的に「凍結」を表現
- 円形の広がりアニメーション
clip-pathを使って、クリック位置から円形に広がるエフェクトを実装 - 多重クリック防止 凍結中はボタンが無効化され、再度クリックすることで解除される仕様
- 視覚的フィードバック カーソルが
not-allowedに変わり、処理中であることを明示
コードのポイント
クリック位置の検出:
const rect = this.getBoundingClientRect();
const clickPercentX = ((e.clientX - rect.left) / rect.width) * 100;
const clickPercentY = ((e.clientY - rect.top) / rect.height) * 100;
this.style.setProperty('--click-x', clickPercentX + '%');
this.style.setProperty('--click-y', clickPercentY + '%'); - ボタンの位置とサイズを
getBoundingClientRect()で取得 - クリック座標をパーセント値に変換し、CSS変数として設定
- CSS側で
var(--click-x),var(--click-y)として使用
円形の広がりアニメーション:
@keyframes expandIce {
0% {
clip-path: circle(0% at var(--click-x, 50%) var(--click-y, 50%));
opacity: 0.7;
}
100% {
clip-path: circle(150% at var(--click-x, 50%) var(--click-y, 50%));
opacity: 1;
}
} clip-path: circle()で円形のマスクを作成- JavaScript側で設定した
--click-x,--click-yをアニメーションの中心点として使用 - 0%から150%まで円を拡大することで、ボタン全体を覆うエフェクトを実現
トグル機能の実装:
if (this.classList.contains('frozen')) {
this.classList.remove('frozen');
this.disabled = false;
} else {
this.classList.add('frozen');
this.disabled = true;
} frozenクラスの有無で状態を管理disabledプロパティでボタンの有効/無効を切り替え- 再度クリックすることで凍結を解除できる仕様
まとめ
クリック位置から氷が広がって凍結するボタンは、多重送信を防ぐ実用的な機能と、ユーザーを楽しませる遊び心を兼ね備えたパーツです。JavaScriptでクリック位置を検出し、CSS変数とアニメーションを組み合わせることで、このような動的なエフェクトを実現できます。
多重クリック防止ボタン作成のポイント
- 視覚的フィードバック 氷が広がるエフェクトで「処理中」を直感的に伝える
- クリック位置の活用 JavaScriptでクリック位置を検出し、CSS変数経由でアニメーションに反映
- 円形マスクの活用
clip-path: circle()で自然な広がりを表現 - トグル機能 凍結と解除を切り替えられる設計で、テストやデモに便利
- 実用性 フォーム送信や決済ボタンなど、多重クリックを防ぎたい場面で活用可能