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

ソーシャルボタンのホバーエフェクト3選

SNSシェアボタンに動きのあるホバーエフェクトを追加。ツールチップ、横展開、アイコンズームの3パターンを実装します

男子生徒のアイコン

ソーシャルボタンって、どのサイトにもありますよね。普通のボタンとどう違うんですか?

AI先生のアイコン

SNSのアイコンを使ったボタンのことだね。FacebookやX(旧Twitter)、Instagramなどへのリンクボタンとして使われるよ。今回は、ホバー時に動きのあるエフェクトを3パターン作成して、それぞれの特徴を学んでいこう。

作成した3つのソーシャルボタン

今回は、同じSNSボタンでも、ホバー時の演出が異なる3つのパターンを作成します。それぞれ異なる視覚効果で、ユーザーの注意を引きつけます。

パターン1:ツールチップポップアップ

ホバー時にSNS名がツールチップとして上部に表示されます。

HTML
<div class="social-buttons">
    <div class="social-button x">
        <i class="fab fa-x-twitter"></i>
        <span class="label">X</span>
    </div>
    <div class="social-button facebook">
        <i class="fab fa-facebook-f"></i>
        <span class="label">Facebook</span>
    </div>
    <div class="social-button instagram">
        <i class="fab fa-instagram"></i>
        <span class="label">Instagram</span>
    </div>
    <div class="social-button line">
        <i class="fab fa-line"></i>
        <span class="label">LINE</span>
    </div>
</div>
CSS
* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

body {
    min-height: 100vh;
    display: flex;
    align-items: center;
    justify-content: center;
    background: #f5f5f5;
    font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
    padding: 2rem;
}

.social-buttons {
    display: flex;
    gap: 1.5rem;
    flex-wrap: wrap;
    justify-content: center;
}

.social-button {
    position: relative;
    width: 60px;
    height: 60px;
    border-radius: 15px;
    display: flex;
    align-items: center;
    justify-content: center;
    background: #f5f5f5;
    cursor: pointer;
    transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
    overflow: visible;
    box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2);
}

.social-button:hover {
    transform: translateY(-5px);
    box-shadow: 0 8px 25px rgba(0, 0, 0, 0.3);
}

.social-button i {
    font-size: 1.8rem;
    color: white;
    z-index: 1;
    position: relative;
}

.social-button .label {
    position: absolute;
    top: -50px;
    left: 50%;
    transform: translateX(-50%) translateY(20px) scale(0.8);
    background: white;
    color: #333;
    padding: 0.5rem 1rem;
    border-radius: 8px;
    font-size: 0.9rem;
    font-weight: 600;
    white-space: nowrap;
    opacity: 0;
    pointer-events: none;
    transition: all 0.4s cubic-bezier(0.34, 1.56, 0.64, 1);
    box-shadow: 0 4px 15px rgba(0, 0, 0, 0.15);
}

.social-button .label::after {
    content: '';
    position: absolute;
    bottom: -6px;
    left: 50%;
    transform: translateX(-50%);
    width: 0;
    height: 0;
    border-left: 6px solid transparent;
    border-right: 6px solid transparent;
    border-top: 6px solid white;
}

.social-button:hover .label {
    opacity: 1;
    transform: translateX(-50%) translateY(0) scale(1);
}

.social-button.x {
    background: linear-gradient(135deg, #14171a 0%, #000000 100%);
}

.social-button.facebook {
    background: linear-gradient(135deg, #1877f2 0%, #0e5fc1 100%);
}

.social-button.instagram {
    background: linear-gradient(135deg, #e1306c 0%, #c13584 50%, #833ab4 100%);
}

.social-button.line {
    background: linear-gradient(135deg, #00b900 0%, #00a000 100%);
}

AIへのプロンプト例

以下のようなプロンプトをAIに送信します:

4つのSNSボタン(X、Facebook、Instagram、LINE)を作成してください。

### 初期状態
- それぞれのSNSブランドカラーのグラデーション背景
- 白いアイコン
- 角丸で柔らかい影

### ホバー時
- ボタンが少し上に浮き上がる
- SNS名がツールチップとして上部に表示される
- ツールチップは下向きの三角形の矢印付き
- 滑らかにフェードインしながら上から出現

このボタンの特徴

  • 非破壊的な表示 ボタン自体は変形せず、ツールチップが追加表示される
  • 三角形の矢印 CSS三角形テクニックで視覚的な関連性を強調
  • バウンス効果 cubic-bezierでツールチップが弾むように出現
  • シンプルな実装 JavaScriptなしで:hoverのみで完結

コードのポイント

ツールチップの配置:
.social-button .label {
    position: absolute;
    top: -50px; /* ボタンの上に配置 */
    left: 50%; /* 水平中央揃え */
    transform: translateX(-50%) translateY(20px) scale(0.8); /* 初期状態 */
    opacity: 0;
}

.social-button:hover .label {
    opacity: 1;
    transform: translateX(-50%) translateY(0) scale(1); /* 最終状態 */
}
  • position: absoluteで通常のレイアウトフローから外し、自由に配置
  • left: 50%translateX(-50%)で水平方向に完全中央配置
  • 初期状態ではtranslateY(20px)で下に、scale(0.8)で小さく
  • ホバー時にtranslateY(0)scale(1)で元の位置とサイズに
CSS三角形の作成:
.social-button .label::after {
    content: '';
    position: absolute;
    bottom: -6px; /* ツールチップの下端に配置 */
    left: 50%;
    transform: translateX(-50%);
    width: 0;
    height: 0;
    border-left: 6px solid transparent;
    border-right: 6px solid transparent;
    border-top: 6px solid white; /* 下向きの三角形 */
}
  • width: 0; height: 0でボックスのサイズをゼロに
  • borderを使って三角形を描画(上のborderだけ色を付ける)
  • border-leftborder-rightを透明にすることで、下向きの三角形を作成
バウンス効果のイージング:
.social-button .label {
    transition: all 0.4s cubic-bezier(0.34, 1.56, 0.64, 1);
}
  • cubic-bezier(0.34, 1.56, 0.64, 1): 第2引数が1を超えるバウンス曲線
  • オーバーシュート効果で、ツールチップが勢いよく出現して少し戻る動き
  • 視覚的に活き活きとした印象を与える

パターン2:横展開エフェクト

ホバーしたボタンが横に展開し、SNS名が表示されます。他のボタンは縮小します。

HTML
<div class="social-buttons">
    <div class="social-button x" data-label="X">
        <i class="fab fa-x-twitter"></i>
    </div>
    <div class="social-button facebook" data-label="Facebook">
        <i class="fab fa-facebook-f"></i>
    </div>
    <div class="social-button instagram" data-label="Instagram">
        <i class="fab fa-instagram"></i>
    </div>
    <div class="social-button line" data-label="LINE">
        <i class="fab fa-line"></i>
    </div>
</div>

<script>
    const buttonsContainer = document.querySelector('.social-buttons');
    const buttons = document.querySelectorAll('.social-button');

    buttons.forEach((button, index) => {
        button.addEventListener('mouseenter', function() {
            buttons.forEach(btn => {
                btn.classList.remove('expand', 'shrink');
                const existingLabel = btn.querySelector('.label');
                if (existingLabel) {
                    existingLabel.remove();
                }
            });

            const gridTemplate = [];
            for (let i = 0; i < buttons.length; i++) {
                gridTemplate.push(i === index ? '3fr' : '0.6fr');
            }
            buttonsContainer.style.gridTemplateColumns = gridTemplate.join(' ');

            this.classList.add('expand');
            const label = document.createElement('span');
            label.className = 'label';
            label.textContent = this.dataset.label;
            this.appendChild(label);

            buttons.forEach(btn => {
                if (btn !== this) btn.classList.add('shrink');
            });
        });
    });

    buttonsContainer.addEventListener('mouseleave', function() {
        buttonsContainer.style.gridTemplateColumns = '1fr 1fr 1fr 1fr';
        buttons.forEach(btn => {
            btn.classList.remove('expand', 'shrink');
            const label = btn.querySelector('.label');
            if (label) label.remove();
        });
    });
</script>
CSS
* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

body {
    min-height: 100vh;
    display: flex;
    align-items: center;
    justify-content: center;
    background: #f5f5f5;
    font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
    padding: 2rem;
}

.social-buttons {
    display: grid;
    grid-template-columns: 1fr 1fr 1fr 1fr;
    gap: 1rem;
    width: 300px;
    margin: 0 auto;
    transition: grid-template-columns 0.4s cubic-bezier(0.4, 0, 0.2, 1);
}

.social-button {
    position: relative;
    height: 60px;
    width: 100%;
    border-radius: 15px;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    overflow: hidden;
    box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2);
    transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
}

.social-button.shrink {
    opacity: 0.6;
}

.social-button.expand {
    justify-content: flex-start;
    padding-left: 20px;
}

.social-button i {
    font-size: 1.8rem;
    color: white;
    transition: transform 0.3s ease;
}

.social-button .label {
    color: white;
    font-size: 1rem;
    font-weight: 600;
    margin-left: 15px;
    white-space: nowrap;
    opacity: 0;
    transform: translateX(-20px);
    transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
}

.social-button.expand .label {
    opacity: 1;
    transform: translateX(0);
}

.social-button.x {
    background: linear-gradient(135deg, #14171a 0%, #000000 100%);
}

.social-button.facebook {
    background: linear-gradient(135deg, #1877f2 0%, #0e5fc1 100%);
}

.social-button.instagram {
    background: linear-gradient(135deg, #e1306c 0%, #c13584 50%, #833ab4 100%);
}

.social-button.line {
    background: linear-gradient(135deg, #00b900 0%, #00a000 100%);
}

AIへのプロンプト例

以下のようなプロンプトをAIに送信します:

4つのSNSボタン(X、Facebook、Instagram、LINE)を作成してください。

### 初期状態
- 4つのボタンが均等に並んでいる
- それぞれのSNSブランドカラーのグラデーション背景
- 白いアイコン
- 角丸で柔らかい影

### ホバー時
- ホバーしたボタンが横に展開
- ボタンの左側にアイコン、右側にSNS名が表示される
- 他のボタンは縮小して薄くなる

### コンテナから離れたとき
- すべてのボタンが元の状態に戻る

このボタンの特徴

  • 動的レイアウト CSS Gridの列幅をJavaScriptで動的に変更
  • 視覚的フィードバック ホバーしていないボタンは縮小・透明化して注目を促す
  • ラベルの遅延表示 transformとopacityでラベルが滑らかに出現
  • 状態管理 クラスとDOM操作で拡張・縮小状態を制御

コードのポイント

Grid列の動的変更:
.social-buttons {
    display: grid;
    grid-template-columns: 1fr 1fr 1fr 1fr; /* 初期状態 */
    transition: grid-template-columns 0.4s cubic-bezier(0.4, 0, 0.2, 1);
}
// ホバー時に列幅を変更
const gridTemplate = [];
for (let i = 0; i < buttons.length; i++) {
    gridTemplate.push(i === index ? '3fr' : '0.6fr'); // 3fr : 0.6fr の比率
}
buttonsContainer.style.gridTemplateColumns = gridTemplate.join(' ');
  • grid-template-columnstransitionを適用して滑らかに列幅を変更
  • ホバーしたボタンは3fr(3倍)、他は0.6fr(0.6倍)に設定
  • fr単位を使うことで、全体の幅に対する比率で制御
ラベルの動的生成と表示:
// ラベルを動的に追加
const label = document.createElement('span');
label.className = 'label';
label.textContent = this.dataset.label;
this.appendChild(label);
.social-button .label {
    opacity: 0;
    transform: translateX(-20px); /* 左から出現 */
    transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
}

.social-button.expand .label {
    opacity: 1;
    transform: translateX(0); /* 元の位置へ */
}
  • JavaScriptで<span>要素を動的に生成・追加
  • CSSでopacitytranslateXを使って左からフェードイン
  • expandクラスが付いたときに表示アニメーション実行

パターン3:アイコンズーム

ホバー時にアイコンが大きく拡大し、ゆっくり元のサイズに戻ります。

HTML
<div class="social-buttons">
    <div class="social-button x">
        <i class="fab fa-x-twitter"></i>
        <span class="label">X</span>
    </div>
    <div class="social-button facebook">
        <i class="fab fa-facebook-f"></i>
        <span class="label">Facebook</span>
    </div>
    <div class="social-button instagram">
        <i class="fab fa-instagram"></i>
        <span class="label">Instagram</span>
    </div>
    <div class="social-button line">
        <i class="fab fa-line"></i>
        <span class="label">LINE</span>
    </div>
</div>
CSS
* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

body {
    min-height: 100vh;
    display: flex;
    align-items: center;
    justify-content: center;
    background: #f5f5f5;
    font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
    padding: 2rem;
}

.social-buttons {
    display: flex;
    gap: 1.5rem;
    flex-wrap: wrap;
    justify-content: center;
}

.social-button {
    position: relative;
    width: 60px;
    height: 60px;
    border-radius: 15px;
    display: flex;
    align-items: center;
    justify-content: center;
    background: #f5f5f5;
    cursor: pointer;
    transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
    overflow: visible;
    box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2);
}

.social-button:hover {
    transform: translateY(-5px);
    box-shadow: 0 8px 25px rgba(0, 0, 0, 0.3);
}

.social-button i {
    font-size: 1.8rem;
    color: white;
    z-index: 1;
    position: relative;
    transition: none;
}

.social-button:hover i {
    animation: iconZoom 2s cubic-bezier(0.34, 1.56, 0.64, 1) forwards;
}

.social-button .label {
    display: none;
}

@keyframes iconZoom {
    0% {
        transform: scale(1);
    }
    20% {
        transform: scale(5);
    }
    100% {
        transform: scale(1);
    }
}

.social-button.x {
    background: linear-gradient(135deg, #14171a 0%, #000000 100%);
}

.social-button.facebook {
    background: linear-gradient(135deg, #1877f2 0%, #0e5fc1 100%);
}

.social-button.instagram {
    background: linear-gradient(135deg, #e1306c 0%, #c13584 50%, #833ab4 100%);
}

.social-button.line {
    background: linear-gradient(135deg, #00b900 0%, #00a000 100%);
}

AIへのプロンプト例

以下のようなプロンプトをAIに送信します:

4つのSNSボタン(X、Facebook、Instagram、LINE)を作成してください。

### 初期状態
- それぞれのSNSブランドカラーのグラデーション背景
- 白いアイコン
- 角丸で柔らかい影

### ホバー時
- ボタンが少し上に浮き上がる
- アイコンが瞬間的に大きく拡大
- その後、ゆっくりと元のサイズに戻る
- 拡大時はバウンス効果を持たせる

このボタンの特徴

  • ドラマチックな演出 アイコンが5倍まで瞬間拡大してから元に戻る
  • バウンス効果 cubic-bezierでオーバーシュートする動き
  • 長めのアニメーション 2秒かけてゆっくり変化し、印象に残る
  • シンプルな構造 JavaScriptを使わずCSSアニメーションのみで実装

コードのポイント

キーフレームアニメーション:
@keyframes iconZoom {
    0% {
        transform: scale(1); /* 初期サイズ */
    }
    20% {
        transform: scale(5); /* 0.4秒で5倍に拡大 */
    }
    100% {
        transform: scale(1); /* 残り1.6秒で元に戻る */
    }
}
  • 0%から20%(0.4秒)で一気に5倍に拡大
  • 20%から100%(1.6秒)でゆっくり元のサイズに戻る
  • 急激な拡大と緩やかな縮小でインパクトのある演出
バウンス効果のイージング:
.social-button:hover i {
    animation: iconZoom 2s cubic-bezier(0.34, 1.56, 0.64, 1) forwards;
}
  • cubic-bezier(0.34, 1.56, 0.64, 1): バウンス効果のあるイージング
  • 第2引数1.56が1を超えることで、オーバーシュート(行き過ぎて戻る)動きを実現
  • forwardsで、アニメーション終了後も最終状態(scale(1))を維持
transition無効化:
.social-button i {
    transition: none; /* transitionを無効化 */
}
  • transition: noneでtransitionによる自動補間を無効化
  • アニメーションの動きをキーフレームで完全に制御
  • 意図しない動きの混在を防ぐ
女子生徒のアイコン

3つのパターン、それぞれ印象が全然違いますね!ツールチップは情報表示に便利で、横展開はダイナミック、アイコンズームはインパクトがあります!

AI先生のアイコン

その通り!それぞれに適した場面があるんだ。ツールチップは情報を邪魔せずに伝えられ、横展開は他を目立たなくして注目を集める。アイコンズームは楽しさや驚きを演出できる。

まとめ

男子生徒のアイコン

同じSNSボタンでも、アニメーション次第でこんなに雰囲気が変わるんですね!ツールチップはposition: absolute、横展開はCSS Gridの動的変更、アイコンズームは@keyframes。それぞれ全然違うテクニックですね。

AI先生のアイコン

よく気づいたね!同じ目的でも、アプローチの仕方を変えることで、まったく違った体験を提供できる。これがWebデザインの面白いところだよ。次は、さらに高度なインタラクティブ要素に挑戦してみよう!

ソーシャルボタン実装のポイント
  • ツールチップパターン absolute配置、CSS三角形、バウンスイージングで情報を非破壊的に表示
  • 横展開パターン JavaScriptでGridのfr単位を動的に変更し、視線を誘導
  • アイコンズームパターン キーフレームアニメーションで瞬間的な拡大と緩やかな縮小を演出
  • SNSブランドカラー 各SNSの公式カラーグラデーションで統一感とブランド認識を向上
  • 用途に応じた使い分け 情報提示、注目誘導、エンターテインメント性など目的に合わせて選択

次回は、より複雑なインタラクティブ要素について学んでいきます。

学習チェック

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

レッスン完了!🎉

お疲れさまでした!