はじめに
CSSでボタンを実装していると、
- hoverした瞬間にボタンが少し動く
- ボタンの位置がズレる
- アニメーションがカクカク見える
という現象に遭遇することがあります。
私も実務でボタンのホバーアニメーションを実装していた際に、
border: 1px solid;
をhover時に追加したことで、ボタンがガタッと動いてしまい原因調査に時間を使いました。
結論から言うと、hover時にborderを追加すると要素のサイズが変わるためです。
今回は実際の画面録画を使いながら、
- NGパターン
- OKパターン
を比較して解説します。
この記事を読めば5分で解決できます。
⏬実際の現象
現象の説明
今回の現象は以下です。
hover前
border: なし
↓
hover後
border: 2px solid #333;
hover時だけborderを追加すると、要素サイズが変化します。
その結果、
- ボタンが大きくなる
- 周囲のレイアウトが押される
- ガタついて見える
という問題が発生します。
エラーメッセージは表示されません。
しかし画面上では次のような状態になります。
.btn:hover {
border: 2px solid #333;
}
見た目では小さな変化ですが、実際のUIではかなり目立ちます。
結論(先に知りたい人向け)
hover時にborderを追加するのではなく、最初から透明なborderを用意してください。
.btn {
border: 2px solid transparent;
}
.btn:hover {
border-color: #333;
}
これだけで解決します。
NG例(NG例(hover時にborder追加))
hoverした瞬間にボタンが少し大きくなっている様子。周囲のレイアウトもわずかに動いている状態。
OK例(透明border方式)
■透明border方式のコード
.btn {
border: 2px solid transparent;
}
.btn:hover {
border-color: #333;
}
比較動画
原因の詳細
CSSのborderは要素サイズに含まれます。
例えば、
通常状態
width: 200px;
border: none;
hover後
width: 200px;
border: 2px solid;
になると、
実際には
200px + 左2px + 右2px
になります。
つまりサイズが変わります。
その結果、
- ボタンが広がる
- 周囲を押す
- レイアウトが動く
という流れになります。
NGコード
実際によく見るコードです。
.btn {
background: #333;
color: #fff;
}
.btn:hover {
background: #fff;
color: #333;
border: 2px
solid #333;
}
なぜダメなのか
hover前
border: none;
hover後
border: 2px solid #333;
要素サイズが変わります。
そのため、
- 横幅が変わる
- 高さが変わる
- レイアウトがズレる
結果としてカクつきが発生します。
解決方法
■修正前コード
.btn {
background: #333;
color: #fff;
padding: 16px 24px;
transition: all .3s ease;
}
.btn:hover {
background: #fff;
color: #333;
border: 2px solid #333;
}
この書き方だと、hoverした瞬間に border の分だけボタンサイズが変わります。
■修正後コード
通常時から透明な border を用意します。
.btn {
background: #333;
color: #fff;
padding: 16px 24px;
border: 2px solid transparent;
transition: all .3s ease;
}
.btn:hover {
background: #fff;
color: #333;
border-color: #333;
}
修正後は、hover時に border を追加するのではなく、border-color だけを変更しています。
今回のポイントまとめ
CSS hover時にボタンがカクつくときは、次を確認します。
- hover時だけborderを追加していないか
- 通常時にborderがない状態になっていないか
border: 1px solid transparent;を使っているか- hover時は
border-colorだけ変えているか - ボタン周りの要素がズレていないか

一言
hoverのカクつきは小さな不具合ですが、ユーザーは意外と敏感に感じます。
実務では「borderを後から追加していないか」を最初に疑うと、かなり早く原因を特定できます。