AI先生のロボットキャラクター
第1章 - セクション8

多重クリック防止!氷が広がるボタン

クリック位置から氷が広がって凍結するボタンエフェクト。多重送信を防止します。

多重クリック防止の重要性

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()で自然な広がりを表現
  • トグル機能 凍結と解除を切り替えられる設計で、テストやデモに便利
  • 実用性 フォーム送信や決済ボタンなど、多重クリックを防ぎたい場面で活用可能

学習チェック

このレッスンを理解できたら「完了」をクリックしてください。
後で見直したい場合は「未完了に戻す」で進捗をリセットできます。

レッスン完了!🎉

お疲れさまでした!