CSSの「transition」は、ホバー時の色変更やメニューの展開など、Webサイトに滑らかなアニメーションを手軽に加えるプロパティです。
本記事では、基本の書き方から「効かない」トラブルの解決策、実務で使えるUI別のコピペ用サンプルを解説します。
また、CSSに関するカテゴリーページから学びたい内容を決めたい人は、以下のCSSページをご確認ください。
transitionの使い方とanimationとの違い
Webサイトに滑らかな動きを加え、ユーザーの操作を向上するのに欠かせないのが「transition」です。
transitionとは、「ある状態から別の状態への変化を時間をかけてアニメーションさせる」機能です。
ここでは、実務で必須となるtransitionの使い方や各種パラメーターの基本、animationやtransformとの違いについて解説します。
transitionプロパティとは:書き方と種類animationやtransformとの違い・使い分け
transitionプロパティとは:書き方と種類
transitionは、マウスを乗せた時(:hover)やクラスが切り替わった時など、瞬時に切り替わるのではなく「指定した時間をかけてジワッと変化させる」プロパティです。
主なパラメーターは以下の4つです。
transition-property
変化させるプロパティ(background-colorやallなど)transition-duration
変化にかかる時間(0.3sなど)transition-timing-function
変化のスピードの緩急(easeやlinearなど)transition-delay
変化が始まるまでの遅延時間(0sなど)
※実務はまとめてtransition: all 0.3s ease;のように1行で記述するのが一般的です。
transitionプロパティは、「変化する前(通常時・ベースライン)」のクラスに記述してください。
ベース側に書いておけば、ホバーした時も、ホバーを外して元に戻る時も滑らかなアニメーションになります。
※ボタンにマウスを乗せて、そして「離した時の戻り方」に注目してください。
.btn-wrong {
background-color: #0d6efd;
}
.btn-wrong:hover {
background-color: #dc3545;
transition: all 0.3s ease; /* 💡 離した瞬間に無効になる */
}
/* ⭕️ プロの鉄則:通常時(ベース)に書く */
.btn-correct {
background-color: #0d6efd;
transition: all 0.3s ease; /* 💡 行きも帰りも滑らかに */
}
.btn-correct:hover {
background-color: #198754;
}
HTMLコード表示
<div class="trs-sec1-wrapper">
<div class="trs-sec1-demo-area">
<div class="trs-sec1-box">
<div class="trs-sec1-label">⏱ transitionの正しい指定場所(ホバー時の挙動)</div>
<div class="trs-sec1-visual">
<p style="font-size:12px; color:#555; margin-bottom:15px; text-align:center;">
※ボタンにマウスを乗せて、そして「離した時の戻り方」に注目してください。
</p>
<div class="trs-sec1-item">
<button class="trs-sec1-btn trs-sec1-wrong">
❌ 失敗(マウスを離すとパッと戻る)
</button>
</div>
<div class="trs-sec1-item">
<button class="trs-sec1-btn trs-sec1-correct">
⭕️ 正解(マウスを離してもフワッと戻る)
</button>
</div>
</div>
<div class="trs-sec1-code">
/* ❌ ホバー側に書いてしまう */<br>
<span class="trs-hl-blue">.btn-wrong</span> {<br>
<span class="trs-hl-green">background-color: #0d6efd;</span><br>
}<br>
<span class="trs-hl-blue">.btn-wrong:hover</span> {<br>
<span class="trs-hl-green">background-color: #dc3545;</span><br>
<span class="trs-hl-red">transition: all 0.3s ease;</span> /* 💡 離した瞬間に無効になる */<br>
}<br><br>
/* ⭕️ 通常時(ベース)に書く */<br>
<span class="trs-hl-blue">.btn-correct</span> {<br>
<span class="trs-hl-green">background-color: #0d6efd;</span><br>
<span class="trs-hl-red">transition: all 0.3s ease;</span> /* 💡 行きも帰りも滑らかに */<br>
}<br>
<span class="trs-hl-blue">.btn-correct:hover</span> {<br>
<span class="trs-hl-green">background-color: #198754;</span><br>
}
</div>
</div>
</div>
</div>CSSコード表示
.trs-sec1-wrapper {
background-color: #f8f9fa;
padding: 20px;
border: 1px solid #dee2e6;
border-radius: 4px;
font-family: sans-serif;
}
.trs-sec1-demo-area {
display: flex;
justify-content: center;
}
.trs-sec1-box {
background-color: #ffffff;
border: 2px dashed #adb5bd;
padding: 25px;
width: 100%;
max-width: 600px;
border-radius: 4px;
}
.trs-sec1-label {
font-size: 15px;
font-weight: bold;
margin-bottom: 20px;
color: #333;
}
.trs-sec1-visual {
background-color: #f1f3f5;
padding: 30px 20px;
border-radius: 8px;
margin-bottom: 20px;
border: 1px solid #dee2e6;
display: flex;
flex-direction: column;
gap: 20px;
align-items: center;
}
.trs-sec1-btn {
color: #fff;
border: none;
padding: 15px 30px;
border-radius: 50px;
font-weight: bold;
cursor: pointer;
font-size: 14px;
}
/* ❌ 失敗例 */
.trs-sec1-wrong {
background-color: #6c757d;
}
.trs-sec1-wrong:hover {
background-color: #dc3545;
/* ホバー時のみに指定しているため戻りが一瞬になる */
transition: all 0.5s ease;
}
/* ⭕️ 成功例 */
.trs-sec1-correct {
background-color: #6c757d;
/* 💡 ベースに指定しているため両方向とも滑らか */
transition: all 0.5s ease;
}
.trs-sec1-correct:hover {
background-color: #198754;
}
.trs-sec1-code {
background-color: #282c34;
color: #abb2bf;
padding: 15px;
font-family: monospace;
font-size: 13px;
border-radius: 4px;
line-height: 1.6;
border-left: 4px solid #0d6efd;
}
.trs-hl-green {
color: #98c379;
font-weight: bold;
}
.trs-hl-blue {
color: #61afef;
font-weight: bold;
}
.trs-hl-red {
color: #e06c75;
font-weight: bold;
}animationやtransformとの違い・使い分け
CSSには動きをつけるプロパティが複数あり、animationやtransformといった違いで混乱する人がいます。
これらは対立するものではなく、役割が異なります。
transform(変形)
「何をどう変えるか(移動・拡大・回転など)」を指定するプロパティです。
アニメーション機能自体は持っていません。transition(変化の補間)
「AからBへ変化する時の時間とスピード」を指定します。
ホバーなどの「きっかけ」が必要です。animation(キーフレームアニメ)@keyframesを使い、「A→B→C→A」のように複数の状態を連続させたり、無限ループさせたりできる機能です。
つまり、transitionとtransformはセットで組み合わせて使うのが基本となります。
要素の移動・拡大・回転アニメーションには、transformとtransitionを組み合わせて使用してください。
transformはGPUで処理されるため、スマホでも60fpsの滑らかなアニメーションが実現できます。
① ホバーで移動(transition + transform)
AからBへのシンプルな1回限りの変化(きっかけが必要)
② ずっと回転(animation + transform)
きっかけ不要で自動再生・無限ループが可能
.box-hover {
transition: transform 0.3s ease; /* 動きの時間を指定 */
}
.box-hover:hover {
transform: translateY(-10px); /* 上に10px移動する指定 */
}
/* 💡 ② animation はキーフレームを呼び出して自走する */
.box-loop {
animation: spin 2s linear infinite; /* 2秒で無限ループ */
}
@keyframes spin {
100% { transform: rotate(360deg); }
}
HTMLコード表示
<div class="trs-sec2-wrapper">
<div class="trs-sec2-demo-area">
<div class="trs-sec2-box">
<div class="trs-sec2-label">🔄 transition / transform / animation の役割</div>
<div class="trs-sec2-visual">
<div class="trs-sec2-item">
<p class="trs-sec2-title">① ホバーで移動(transition + transform)</p>
<div class="trs-sec2-card trs-sec2-use-transform">
HOVER ME
</div>
<p class="trs-sec2-desc">AからBへのシンプルな1回限りの変化(きっかけが必要)</p>
</div>
<div class="trs-sec2-item">
<p class="trs-sec2-title">② ずっと回転(animation + transform)</p>
<div class="trs-sec2-card trs-sec2-use-animation">
LOOP
</div>
<p class="trs-sec2-desc">きっかけ不要で自動再生・無限ループが可能</p>
</div>
</div>
<div class="trs-sec1-code">
/* 💡 ① transform(変形) を transition(時間) で滑らかにする */<br>
<span class="trs-hl-blue">.box-hover</span> {<br>
<span class="trs-hl-green">transition: transform 0.3s ease;</span> /* 動きの時間を指定 */<br>
}<br>
<span class="trs-hl-blue">.box-hover:hover</span> {<br>
<span class="trs-hl-red">transform: translateY(-10px);</span> /* 上に10px移動する指定 */<br>
}<br><br>
/* 💡 ② animation はキーフレームを呼び出して自走する */<br>
<span class="trs-hl-blue">.box-loop</span> {<br>
<span class="trs-hl-red">animation: spin 2s linear infinite;</span> /* 2秒で無限ループ */<br>
}<br>
<span class="trs-hl-blue">@keyframes spin</span> {<br>
<span class="trs-hl-green">100%</span> { <span class="trs-hl-green">transform: rotate(360deg);</span> }<br>
}
</div>
</div>
</div>
</div>CSSコード表示
.trs-sec2-wrapper {
background-color: #f8f9fa;
padding: 20px;
border: 1px solid #dee2e6;
border-radius: 4px;
font-family: sans-serif;
}
.trs-sec2-demo-area {
display: flex;
justify-content: center;
}
.trs-sec2-box {
background-color: #ffffff;
border: 2px dashed #adb5bd;
padding: 25px;
width: 100%;
max-width: 600px;
border-radius: 4px;
}
.trs-sec2-label {
font-size: 15px;
font-weight: bold;
margin-bottom: 20px;
color: #333;
}
.trs-sec2-visual {
background-color: #f1f3f5;
padding: 30px 20px;
border-radius: 8px;
margin-bottom: 20px;
border: 1px solid #dee2e6;
display: flex;
justify-content: space-around;
flex-wrap: wrap;
gap: 30px;
}
.trs-sec2-item {
display: flex;
flex-direction: column;
align-items: center;
width: 45%;
min-width: 200px;
}
.trs-sec2-title {
font-size: 13px;
font-weight: bold;
margin: 0 0 15px 0;
text-align: center;
}
.trs-sec2-desc {
font-size: 11px;
color: #666;
text-align: center;
margin-top: 15px;
line-height: 1.4;
}
.trs-sec2-card {
width: 100px;
height: 100px;
background-color: #0d6efd;
color: #fff;
display: flex;
align-items: center;
justify-content: center;
font-weight: bold;
border-radius: 8px;
cursor: pointer;
box-shadow: 0 4px 6px rgba(0,0,0,0.1);
}
/* ① transition と transform の組み合わせ */
.trs-sec2-use-transform {
/* ベースにtransitionを指定 */
transition: transform 0.3s ease, box-shadow 0.3s ease;
}
.trs-sec2-use-transform:hover {
/* transformで上に移動させる */
transform: translateY(-15px);
box-shadow: 0 10px 15px rgba(0,0,0,0.2);
}
/* ② animation と transform の組み合わせ */
.trs-sec2-use-animation {
background-color: #198754;
/* きっかけ不要で自動再生 */
animation: trsSpinAnim 3s linear infinite;
}
@keyframes trsSpinAnim {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}CSSアニメーションの作り方を詳しく知りたい人は「【CSS】アニメーションの作り方:コピペで使えるおしゃれサンプル集」を一読ください。
時間・イージングと遅延の設定
transitionは、単に変化させるだけでなく、「どれくらいの時間をかけるか」「いつ変化を始めるか」「どのような緩急をつけるか」を細かく制御することで心地よいUIになります。
ここでは、アニメーションにおける「時間(duration)」「遅延(delay)」「イージング(timing-function)」の使い方を解説します。
durationとdelayの使い方timing-function(ease・cubic-bezier等)
durationとdelayの使い方
変化にかかる時間を決めるのがtransition-duration、変化がスタートするまでの待ち時間を決めるのがtransition-delayです。
時間の単位は、秒を表す「s」か、ミリ秒を表す「ms」を使用します。
実務では0.3sなどの短い秒数が好まれます。
一括指定で書く時は、transition: [プロパティ] [時間(duration)] [イージング] [遅延(delay)];の順で書く癖をつけましょう。
※下のエリアにマウスを乗せて(スマホはタップして)ください。
HOVER HERE
時間: 1s
遅延: 0s
時間: 0.2s
遅延: 0.8s
.box-duration {
transition: transform 1s ease; /* 時間のみ指定 */
}
/* 💡 0.8秒待ってから、0.2秒で変化する */
.box-delay {
transition: transform 0.2s ease 0.8s;
/* ↑ 1つ目の時間がDuration、2つ目がDelay */
}
HTMLコード表示
<div class="trs-sec3-wrapper">
<div class="trs-sec3-demo-area">
<div class="trs-sec3-box">
<div class="trs-sec3-label">⏱ Duration(時間)と Delay(遅延)</div>
<div class="trs-sec3-visual">
<p style="font-size:12px; color:#555; margin-bottom:15px; text-align:center;">
※下のエリアにマウスを乗せて(スマホはタップして)ください。
</p>
<div class="trs-sec3-hover-area">
<p class="trs-sec3-hover-text">HOVER HERE</p>
<div style="display:flex; justify-content:space-around; width:100%; margin-top:20px;">
<div class="trs-sec3-item">
<div class="trs-sec3-circle trs-sec3-duration"></div>
<p style="font-size:11px; margin-top:10px;">時間: 1s<br>遅延: 0s</p>
</div>
<div class="trs-sec3-item">
<div class="trs-sec3-circle trs-sec3-delay"></div>
<p style="font-size:11px; margin-top:10px;">時間: 0.2s<br>遅延: 0.8s</p>
</div>
</div>
</div>
</div>
<div class="trs-sec1-code">
/* 💡 1秒かけて変化する(Delayなし) */<br>
<span class="trs-hl-blue">.box-duration</span> {<br>
<span class="trs-hl-red">transition: transform 1s ease;</span> /* 時間のみ指定 */<br>
}<br><br>
/* 💡 0.8秒待ってから、0.2秒で変化する */<br>
<span class="trs-hl-blue">.box-delay</span> {<br>
<span class="trs-hl-red">transition: transform 0.2s ease 0.8s;</span><br>
<span class="trs-hl-comment">/* ↑ 1つ目の時間がDuration、2つ目がDelay */</span><br>
}
</div>
</div>
</div>
</div>CSSコード表示
.trs-sec3-wrapper {
background-color: #f8f9fa;
padding: 20px;
border: 1px solid #dee2e6;
border-radius: 4px;
font-family: sans-serif;
}
.trs-sec3-demo-area {
display: flex;
justify-content: center;
}
.trs-sec3-box {
background-color: #ffffff;
border: 2px dashed #adb5bd;
padding: 25px;
width: 100%;
max-width: 600px;
border-radius: 4px;
}
.trs-sec3-label {
font-size: 15px;
font-weight: bold;
margin-bottom: 20px;
color: #333;
}
.trs-sec3-visual {
background-color: #f1f3f5;
padding: 20px;
border-radius: 8px;
margin-bottom: 20px;
border: 1px solid #dee2e6;
}
/* ホバーを検知する大枠 */
.trs-sec3-hover-area {
background-color: #fff;
border: 2px dashed #ced4da;
padding: 30px 10px;
border-radius: 8px;
display: flex;
flex-direction: column;
align-items: center;
cursor: pointer;
}
.trs-sec3-hover-text {
font-weight: bold;
color: #0d6efd;
margin: 0;
letter-spacing: 2px;
}
.trs-sec3-item {
display: flex;
flex-direction: column;
align-items: center;
text-align: center;
}
.trs-sec3-circle {
width: 50px;
height: 50px;
background-color: #6c757d;
border-radius: 50%;
}
/* 1. 時間のみ(1秒) */
.trs-sec3-duration {
transition: background-color 1s ease, transform 1s ease;
}
/* 2. 遅延あり(0.8秒待って0.2秒で動く) */
.trs-sec3-delay {
transition: background-color 0.2s ease 0.8s, transform 0.2s ease 0.8s;
}
/* 親枠がホバーされたら子要素を動かす */
.trs-sec3-hover-area:hover .trs-sec3-circle {
background-color: #dc3545;
transform: translateY(20px);
}timing-function(ease・cubic-bezier等)
アニメーションの「緩急(加速度のカーブ)」を決定するのがtransition-timing-functionです。
代表的な値として、最初と最後がふんわりと遅くなるease(デフォルト)、常に一定の速度で動くlinearがあります。
さらに、パラパラ漫画のようにコマ送りで変化させるstepsという特殊な値もあります。
手書きで複雑な曲線を書くのは不可能なので、実務では「ブラウザのデベロッパーツールやCubic-Bezierジェネレーターサイト」を使って直感的にカーブを作成し、出力された数値(例:cubic-bezier(0.17, 0.67, 0.83, 0.67))をコピペして使用します。
特に、少し行き過ぎて戻ってくる「バウンス(跳ね返り)効果」は、これを使わないと実装できません。
① linear (一定速度・ロボット的)
② ease (初期値・最初と最後が遅い)
③ cubic-bezier (少し跳ね返る)
.linear {
transition: transform 1s linear;
}
/* ② 最初と最後がゆっくり */
.ease {
transition: transform 1s ease;
}
/* ③ 行き過ぎて戻ってくる(バウンス効果) */
.bezier {
/* ジェネレーターで作った数値を貼り付ける */
transition: transform 1s cubic-bezier(0.34, 1.56, 0.64, 1);
}
HTMLコード表示
<div class="trs-sec4-wrapper">
<div class="trs-sec4-demo-area">
<div class="trs-sec4-box">
<div class="trs-sec4-label">🎢 イージング(timing-function)の違い</div>
<div class="trs-sec4-visual">
<div style="text-align:center; margin-bottom:15px;">
<button id="trs-sec4-trigger" class="trs-sec4-btn">🏁 アニメーション開始</button>
</div>
<div class="trs-sec4-track">
<p class="trs-sec4-title">① linear (一定速度・ロボット的)</p>
<div class="trs-sec4-target trs-sec4-linear">🚗</div>
</div>
<div class="trs-sec4-track">
<p class="trs-sec4-title">② ease (初期値・最初と最後が遅い)</p>
<div class="trs-sec4-target trs-sec4-ease">🚙</div>
</div>
<div class="trs-sec4-track" style="border-bottom:none;">
<p class="trs-sec4-title" style="color:#0d6efd;">③ cubic-bezier (少し跳ね返る)</p>
<div class="trs-sec4-target trs-sec4-bezier">🏎💨</div>
</div>
</div>
<div class="trs-sec1-code">
/* ① ずっと同じ速度 */<br>
<span class="trs-hl-blue">.linear</span> {<br>
<span class="trs-hl-red">transition: transform 1s linear;</span><br>
}<br><br>
/* ② 最初と最後がゆっくり */<br>
<span class="trs-hl-blue">.ease</span> {<br>
<span class="trs-hl-red">transition: transform 1s ease;</span><br>
}<br><br>
/* ③ 行き過ぎて戻ってくる(バウンス効果) */<br>
<span class="trs-hl-blue">.bezier</span> {<br>
<span class="trs-hl-comment">/* ジェネレーターで作った数値を貼り付ける */</span><br>
<span class="trs-hl-red">transition: transform 1s cubic-bezier(0.34, 1.56, 0.64, 1);</span><br>
}
</div>
</div>
</div>
</div>CSSコード表示
.trs-sec4-wrapper {
background-color: #f8f9fa;
padding: 20px;
border: 1px solid #dee2e6;
border-radius: 4px;
font-family: sans-serif;
}
.trs-sec4-demo-area {
display: flex;
justify-content: center;
}
.trs-sec4-box {
background-color: #ffffff;
border: 2px dashed #adb5bd;
padding: 25px;
width: 100%;
max-width: 600px;
border-radius: 4px;
}
.trs-sec4-label {
font-size: 15px;
font-weight: bold;
margin-bottom: 20px;
color: #333;
}
.trs-sec4-visual {
background-color: #f1f3f5;
padding: 20px;
border-radius: 8px;
margin-bottom: 20px;
border: 1px solid #dee2e6;
}
.trs-sec4-btn {
background-color: #0d6efd;
color: #fff;
border: none;
padding: 8px 16px;
border-radius: 4px;
font-weight: bold;
cursor: pointer;
}
.trs-sec4-track {
margin-bottom: 15px;
padding-bottom: 10px;
border-bottom: 1px dashed #ced4da;
}
.trs-sec4-title {
font-size: 12px;
font-weight: bold;
color: #555;
margin: 0 0 10px 0;
}
.trs-sec4-target {
font-size: 24px;
display: inline-block;
/* JSで付与されるクラスによって移動する */
}
/* 1. linear */
.trs-sec4-linear {
transition: transform 1s linear;
}
/* 2. ease */
.trs-sec4-ease {
transition: transform 1s ease;
}
/* 3. cubic-bezier (跳ね返り) */
.trs-sec4-bezier {
transition: transform 1s cubic-bezier(0.34, 1.56, 0.64, 1);
}
/* JSによって付与される移動クラス */
.trs-sec4-target.is-moved {
transform: translateX(250px);
}JavaScriptコード表示
setTimeout(() => {
const btn = document.getElementById('trs-sec4-trigger');
const targets = document.querySelectorAll('.trs-sec4-target');
let isMoved = false;
function toggleAnim() {
isMoved = !isMoved;
targets.forEach(target => {
if(isMoved) {
target.classList.add('is-moved');
} else {
target.classList.remove('is-moved');
}
});
}
if(btn) {
btn.addEventListener('click', toggleAnim);
}
}, 100);プロパティの指定方法(個別・複数・all)
滑らかなアニメーションを実現する上で、「どれくらい時間をかけるか」と同じくらい重要なのが、「何に対して時間をかけるか」を明確に指示することです。
CSSでは、すべての変化を無差別にアニメーションさせることも、特定の箇所だけを狙い撃ちして動かすことも可能です。
ここでは、プロパティの指定方法について解説します。
- プロパティで対象(色・幅・高さ等)を指定する
- 複数のプロパティ(複数指定)と「all」の注意点
プロパティで対象(色・幅・高さ等)を指定する
transitionのプロパティは、アニメーションさせる対象(プロパティ)を具体的に指定する記述です。
Webサイトの装飾でよく使われるtransitionにおけるアニメーション可能なプロパティ一覧の代表格としては、以下のようなものがあります。
- background-color(背景色の変化)
- color(文字色の変化)
- border(枠線の色や太さの変化)
- opacity(透明度のフワッとした変化)
- transform(拡大縮小・回転・移動)
初心者の勘違いで悩むのが、「display: none;からdisplay: block;に切り替わる時にフワッと表示させたい」というケースです。
結論から言うと、displayプロパティはtransitionの対象外であるため、いくら時間を指定してもパッと切り替わってしまいます。
フワッと表示させたい場合は、displayではなくopacityとvisibilityを組み合わせて対象に指定するのがよいです。
※ホバー時、背景色は「一瞬」で変わりますが、枠線と位置は「滑らか」に変化します。
background-color: #f8f9fa;
border: 2px solid #dee2e6;
transform: translateY(0);
/* 💡 border と transform だけを対象に指定 */
transition-property: border, transform;
transition-duration: 0.4s;
}
.card:hover {
background-color: #e9ecef; /* 対象外なので一瞬で変わる */
border: 2px solid #0d6efd; /* 0.4秒かけて変わる */
transform: translateY(-10px); /* 0.4秒かけて変わる */
}
HTMLコード表示
<div class="trs-sec5-wrapper">
<div class="trs-sec5-demo-area">
<div class="trs-sec5-box">
<div class="trs-sec5-label">🎯 指定したプロパティだけを変化させる</div>
<div class="trs-sec5-visual">
<p style="font-size:12px; color:#555; margin-bottom:15px; text-align:center;">
※ホバー時、背景色は「一瞬」で変わりますが、枠線と位置は「滑らか」に変化します。
</p>
<div class="trs-sec5-item-wrap">
<div class="trs-sec5-card">
HOVER ME
</div>
</div>
</div>
<div class="trs-sec5-code">
<span class="trs-hl-blue">.card</span> {<br>
<span class="trs-hl-green">background-color: #f8f9fa;</span><br>
<span class="trs-hl-green">border: 2px solid #dee2e6;</span><br>
<span class="trs-hl-green">transform: translateY(0);</span><br>
<span class="trs-hl-comment">/* 💡 border と transform だけを対象に指定 */</span><br>
<span class="trs-hl-red">transition-property: border, transform;</span><br>
<span class="trs-hl-red">transition-duration: 0.4s;</span><br>
}<br><br>
<span class="trs-hl-blue">.card:hover</span> {<br>
<span class="trs-hl-green">background-color: #e9ecef;</span> /* 対象外なので一瞬で変わる */<br>
<span class="trs-hl-green">border: 2px solid #0d6efd;</span> /* 0.4秒かけて変わる */<br>
<span class="trs-hl-green">transform: translateY(-10px);</span> /* 0.4秒かけて変わる */<br>
}
</div>
</div>
</div>
</div>CSSコード表示
.trs-sec5-wrapper {
background-color: #f8f9fa;
padding: 20px;
border: 1px solid #dee2e6;
border-radius: 4px;
font-family: sans-serif;
}
.trs-sec5-demo-area {
display: flex;
justify-content: center;
}
.trs-sec5-box {
background-color: #ffffff;
border: 2px dashed #adb5bd;
padding: 25px;
width: 100%;
max-width: 600px;
border-radius: 4px;
}
.trs-sec5-label {
font-size: 15px;
font-weight: bold;
margin-bottom: 20px;
color: #333;
}
.trs-sec5-visual {
background-color: #f1f3f5;
padding: 40px 20px;
border-radius: 8px;
margin-bottom: 20px;
border: 1px solid #dee2e6;
display: flex;
justify-content: center;
}
.trs-sec5-item-wrap {
perspective: 1000px;
}
.trs-sec5-card {
width: 150px;
height: 100px;
background-color: #fff;
border: 2px solid #ced4da;
color: #333;
display: flex;
align-items: center;
justify-content: center;
font-weight: bold;
border-radius: 8px;
cursor: pointer;
/* 💡 個別指定のショートハンド書き(プロパティ名 時間) */
transition: border 0.4s ease, transform 0.4s ease;
}
.trs-sec5-card:hover {
/* 対象外なので一瞬で変わる */
background-color: #e9ecef;
/* 対象なのでフワッと変わる */
border: 2px solid #0d6efd;
transform: translateY(-15px);
}
.trs-sec5-code {
background-color: #282c34;
color: #abb2bf;
padding: 15px;
font-family: monospace;
font-size: 13px;
border-radius: 4px;
line-height: 1.6;
border-left: 4px solid #0d6efd;
}
.trs-hl-green { color: #98c379; font-weight: bold; }
.trs-hl-blue { color: #61afef; font-weight: bold; }
.trs-hl-red { color: #e06c75; font-weight: bold; }
.trs-hl-comment { color: #6c757d; font-style: italic; }複数のプロパティ(複数指定)と「all」の注意点
色もサイズも透明度も動かしたい場合、複数プロパティの指定が必要になります。
2つのプロパティやそれ以上を個別に指定する場合は、,(カンマ)で区切って記述します。
しかし、カンマで区切るのが面倒な時に使われるのが、すべてを一括でアニメーション対象にする「all」というキーワードです。
よく「Aだけは除外して、それ以外はallにしたい」という検索をする人がいますが、except(除外)という機能はありません。
原則としてallは使用せず、カンマ区切りで動かしたいプロパティだけを明示的に指定してください。
こうすることで、色変化は早く(0.3秒)、移動は少し遅く(0.5秒)といったプロパティごとに異なる時間を設定する演出も可能になります。
※ホバー時、文字と背景色は「0.2秒」、ボタンの浮き上がりは「0.6秒」で変化します。
/* ❌ 悪い例:思考停止の all(全て同じ時間になる) */
/* transition: all 0.3s ease; */
/* ⭕️ 良い例:プロパティごとに時間を変えてカンマで繋ぐ */
transition:
background-color 0.2s ease,
color 0.2s ease,
transform 0.6s cubic-bezier(0.34, 1.56, 0.64, 1);
}
HTMLコード表示
<div class="trs-sec6-wrapper">
<div class="trs-sec6-demo-area">
<div class="trs-sec6-box">
<div class="trs-sec6-label">🔀 複数指定(カンマ区切り)による時間差アニメ</div>
<div class="trs-sec6-visual">
<p style="font-size:12px; color:#555; margin-bottom:15px; text-align:center;">
※ホバー時、文字と背景色は「0.2秒」、ボタンの浮き上がりは「0.6秒」で変化します。
</p>
<div class="trs-sec6-item-wrap">
<button class="trs-sec6-multi-btn">
時間差ボタン
</button>
</div>
</div>
<div class="trs-sec6-code">
<span class="trs-hl-blue">.multi-btn</span> {<br>
<span class="trs-hl-comment">/* ❌ 悪い例:思考停止の all(全て同じ時間になる) */</span><br>
<span class="trs-hl-comment">/* transition: all 0.3s ease; */</span><br><br>
<span class="trs-hl-comment">/* ⭕️ 良い例:プロパティごとに時間を変えてカンマで繋ぐ */</span><br>
<span class="trs-hl-red">transition: </span><br>
<span class="trs-hl-red">background-color 0.2s ease,</span><br>
<span class="trs-hl-red">color 0.2s ease,</span><br>
<span class="trs-hl-red">transform 0.6s cubic-bezier(0.34, 1.56, 0.64, 1);</span><br>
}
</div>
</div>
</div>
</div>CSSコード表示
.trs-sec6-wrapper {
background-color: #f8f9fa;
padding: 20px;
border: 1px solid #dee2e6;
border-radius: 4px;
font-family: sans-serif;
}
.trs-sec6-demo-area {
display: flex;
justify-content: center;
}
.trs-sec6-box {
background-color: #ffffff;
border: 2px dashed #adb5bd;
padding: 25px;
width: 100%;
max-width: 600px;
border-radius: 4px;
}
.trs-sec6-label {
font-size: 15px;
font-weight: bold;
margin-bottom: 20px;
color: #333;
}
.trs-sec6-visual {
background-color: #f1f3f5;
padding: 40px 20px;
border-radius: 8px;
margin-bottom: 20px;
border: 1px solid #dee2e6;
display: flex;
justify-content: center;
}
.trs-sec6-multi-btn {
background-color: transparent;
color: #0d6efd;
border: 2px solid #0d6efd;
padding: 15px 30px;
font-size: 16px;
font-weight: bold;
border-radius: 50px;
cursor: pointer;
/* 💡 複数プロパティに対する個別指定 */
transition:
background-color 0.2s ease,
color 0.2s ease,
transform 0.6s cubic-bezier(0.34, 1.56, 0.64, 1),
box-shadow 0.6s ease;
}
.trs-sec6-multi-btn:hover {
background-color: #0d6efd;
color: #fff;
transform: translateY(-8px);
box-shadow: 0 10px 15px rgba(13, 110, 253, 0.3);
}
.trs-sec6-code {
background-color: #282c34;
color: #abb2bf;
padding: 15px;
font-family: monospace;
font-size: 13px;
border-radius: 4px;
line-height: 1.6;
border-left: 4px solid #0d6efd;
}
.trs-hl-green { color: #98c379; font-weight: bold; }
.trs-hl-blue { color: #61afef; font-weight: bold; }
.trs-hl-red { color: #e06c75; font-weight: bold; }
.trs-hl-comment { color: #6c757d; font-style: italic; }効かない原因(display・height等)の解決
CSSアニメーションを実装していると、指定したはずなのに「transitionが効かない」という壁にぶつかります。
多くの場合、それは記述ミスではなく「CSSの仕様上、アニメーションできないプロパティ」を指定してることが原因です。
ここでは、「見えない状態からの表示」「高さの自動計算」「グラデーション」の3大トラブルと解決策を解説します。
display:noneからのフェードインが効かない問題height: 0からautoへのアニメーション解決策- グラデーション(
gradient)が効かない時の代替案
display:noneからのフェードインが効かない問題
ハンバーガーメニューやモーダルウィンドウを作る際、フワッと表示させようとして挫折する人は多いです。
display:noneでのアニメーションは、CSSの仕様上不可能です。
displayプロパティは「存在する」か「存在しないか」の2択しかないため、0秒から0.3秒の間に「半分だけ存在する」といった中間の状態を作れないからです。
そのため、いくらtransitionを指定しても、パッと表示されてしまいます。
挙動を実現したい場合は、displayプロパティを使うのをやめ、代わりにvisibility: hidden;(見えない状態)とopacity: 0;(透明な状態) をセットで使い、これらをvisibleと1にアニメーションさせるのがスタンダードです。
※ボタンをクリックしてください。display:noneを使わずに滑らかに表示・非表示を切り替えます。
(opacity と visibility で制御しています)
.modal {
/* display: none; は絶対に書かない! */
visibility: hidden; /* 要素を「見えない(クリック不可)」にする */
opacity: 0; /* 完全に透明にする */
transform: translateY(-10px); /* 少し上にずらしておく */
transition: visibility 0.4s ease, opacity 0.4s ease, transform 0.4s ease;
}
/* 💡 表示された状態(チェックが入った時) */
.check:checked ~ .modal {
visibility: visible; /* 見えるようにする */
opacity: 1; /* 不透明にする */
transform: translateY(0); /* 元の位置に戻す */
}
HTMLコード表示
<div class="trs-sec7-wrapper">
<div class="trs-sec7-demo-area">
<div class="trs-sec7-box">
<div class="trs-sec7-label">👻 見えない状態からのフェードイン</div>
<div class="trs-sec7-visual">
<p style="font-size:12px; color:#555; margin-bottom:15px; text-align:center;">
※ボタンをクリックしてください。display:noneを使わずに滑らかに表示・非表示を切り替えます。
</p>
<div class="trs-sec7-ui-container">
<input type="checkbox" id="trs-sec7-toggle" class="trs-sec7-hidden-check">
<label for="trs-sec7-toggle" class="trs-sec7-btn">
メニューを開く / 閉じる
</label>
<div class="trs-sec7-modal">
フワッと表示されました!🎉<br>
<span style="font-size:12px; font-weight:normal;">(opacity と visibility で制御しています)</span>
</div>
</div>
</div>
<div class="trs-sec7-code">
/* 💡 非表示の状態(ベース) */<br>
<span class="trs-hl-blue">.modal</span> {<br>
<span class="trs-hl-comment">/* display: none; は絶対に書かない! */</span><br>
<span class="trs-hl-green">visibility: hidden;</span> /* 要素を「見えない(クリック不可)」にする */<br>
<span class="trs-hl-green">opacity: 0;</span> /* 完全に透明にする */<br>
<span class="trs-hl-green">transform: translateY(-10px);</span> /* 少し上にずらしておく */<br>
<span class="trs-hl-red">transition: visibility 0.4s ease, opacity 0.4s ease, transform 0.4s ease;</span><br>
}<br><br>
/* 💡 表示された状態(チェックが入った時) */<br>
<span class="trs-hl-blue">.check:checked ~ .modal</span> {<br>
<span class="trs-hl-green">visibility: visible;</span> /* 見えるようにする */<br>
<span class="trs-hl-green">opacity: 1;</span> /* 不透明にする */<br>
<span class="trs-hl-green">transform: translateY(0);</span> /* 元の位置に戻す */<br>
}
</div>
</div>
</div>
</div>CSSコード表示
.trs-sec7-wrapper {
background-color: #f8f9fa;
padding: 20px;
border: 1px solid #dee2e6;
border-radius: 4px;
font-family: sans-serif;
}
.trs-sec7-demo-area {
display: flex;
justify-content: center;
}
.trs-sec7-box {
background-color: #ffffff;
border: 2px dashed #adb5bd;
padding: 25px;
width: 100%;
max-width: 600px;
border-radius: 4px;
}
.trs-sec7-label {
font-size: 15px;
font-weight: bold;
margin-bottom: 20px;
color: #333;
}
.trs-sec7-visual {
background-color: #f1f3f5;
padding: 20px;
border-radius: 8px;
margin-bottom: 20px;
border: 1px solid #dee2e6;
}
.trs-sec7-ui-container {
display: flex;
flex-direction: column;
align-items: center;
min-height: 160px; /* モーダルが表示される高さを確保 */
}
/* CSSだけでクリック判定をするためのチェックボックス(画面からは隠す) */
.trs-sec7-hidden-check {
display: none;
}
.trs-sec7-btn {
background-color: #0d6efd;
color: #fff;
padding: 12px 24px;
border-radius: 4px;
cursor: pointer;
font-weight: bold;
font-size: 14px;
margin-bottom: 20px;
box-shadow: 0 4px 6px rgba(0,0,0,0.1);
transition: background-color 0.2s ease;
user-select: none; /* テキスト選択を防ぐ */
}
.trs-sec7-btn:hover {
background-color: #0b5ed7;
}
/* 💡 非表示の状態(フェードアウト用) */
.trs-sec7-modal {
background-color: #198754;
color: #fff;
padding: 20px;
border-radius: 8px;
text-align: center;
font-weight: bold;
line-height: 1.5;
box-shadow: 0 10px 15px rgba(0,0,0,0.1);
/* 💡 ここが重要:displayを使わずに隠す */
visibility: hidden;
opacity: 0;
transform: translateY(-15px); /* 少し上から下へ降りてくる演出 */
transition: visibility 0.4s ease, opacity 0.4s ease, transform 0.4s ease;
}
/* 💡 チェックが入ったら表示する(チェックボックスの兄弟要素であるモーダルを指定) */
.trs-sec7-hidden-check:checked ~ .trs-sec7-modal {
visibility: visible;
opacity: 1;
transform: translateY(0);
}
.trs-sec7-code {
background-color: #282c34;
color: #abb2bf;
padding: 15px;
font-family: monospace;
font-size: 13px;
border-radius: 4px;
line-height: 1.6;
border-left: 4px solid #0d6efd;
}
.trs-hl-green { color: #98c379; font-weight: bold; }
.trs-hl-blue { color: #61afef; font-weight: bold; }
.trs-hl-red { color: #e06c75; font-weight: bold; }
.trs-hl-comment { color: #6c757d; font-style: italic; }height: 0からautoへのアニメーション解決策
アコーディオン(開閉メニュー)を作る際、誰もが一度は「height: autoが効かない」という罠にはまります。
アコーディオンの作り方は、heightを使うのをやめ、Gridのgrid-template-rowsを使う方法です。
親要素をgrid-template-rows: 0fr;から1frに変化させることで、中身がどれだけ可変であっても、滑らかな開閉アニメーションが実現できます。
.accordion-wrapper {
display: grid;
grid-template-rows: 0fr; /* 高さを0にする */
transition: grid-template-rows 0.3s ease;
}
/* 💡 開いた状態:1frで中身の高さまで広げる */
.accordion.is-open .accordion-wrapper {
grid-template-rows: 1fr; /* 高さをautoと同じにする */
}
/* ※中身の要素には overflow: hidden; が必須です */
.accordion-content {
overflow: hidden;
}
HTMLコード表示
<div class="trs-sec8-wrapper">
<div class="trs-sec8-demo-area">
<div class="trs-sec8-box">
<div class="trs-sec8-label">↕️ height: auto への滑らかな開閉(Gridを使用)</div>
<div class="trs-sec8-visual">
<label class="trs-sec8-accordion">
<input type="checkbox" class="trs-sec8-acc-check">
<div class="trs-sec8-acc-header">質問をクリックして開く 🔽</div>
<div class="trs-sec8-acc-wrapper">
<div class="trs-sec8-acc-content">
CSS Gridの「1fr」を使うことで、<br>
中身のテキスト量がどれだけ増減しても、<br>
常にぴったりで滑らかなアニメーションになります。<br>
もうmax-heightハックは必要ありません。
</div>
</div>
</label>
</div>
<div class="trs-sec7-code">
/* 💡 閉じた状態:0frで潰す */<br>
<span class="trs-hl-blue">.accordion-wrapper</span> {<br>
<span class="trs-hl-green">display: grid;</span><br>
<span class="trs-hl-red">grid-template-rows: 0fr;</span> /* 高さを0にする */<br>
<span class="trs-hl-red">transition: grid-template-rows 0.3s ease;</span><br>
}<br><br>
/* 💡 開いた状態:1frで中身の高さまで広げる */<br>
<span class="trs-hl-blue">.accordion.is-open .accordion-wrapper</span> {<br>
<span class="trs-hl-red">grid-template-rows: 1fr;</span> /* 高さをautoと同じにする */<br>
}<br><br>
/* ※中身の要素には overflow: hidden; が必須です */<br>
<span class="trs-hl-blue">.accordion-content</span> {<br>
<span class="trs-hl-green">overflow: hidden;</span><br>
}
</div>
</div>
</div>
</div>CSSコード表示
.trs-sec8-wrapper {
background-color: #f8f9fa;
padding: 20px;
border: 1px solid #dee2e6;
border-radius: 4px;
font-family: sans-serif;
}
.trs-sec8-demo-area {
display: flex;
justify-content: center;
}
.trs-sec8-box {
background-color: #ffffff;
border: 2px dashed #adb5bd;
padding: 25px;
width: 100%;
max-width: 600px;
border-radius: 4px;
}
.trs-sec8-label {
font-size: 15px;
font-weight: bold;
margin-bottom: 20px;
color: #333;
}
.trs-sec8-visual {
background-color: #f1f3f5;
padding: 20px;
border-radius: 8px;
margin-bottom: 20px;
border: 1px solid #dee2e6;
}
.trs-sec8-accordion {
display: block;
background-color: #fff;
border: 1px solid #ced4da;
border-radius: 4px;
cursor: pointer;
}
.trs-sec8-acc-check {
display: none;
}
.trs-sec8-acc-header {
padding: 15px;
font-weight: bold;
color: #333;
background-color: #e9ecef;
}
/* 💡 閉じた状態のアニメーションラッパー */
.trs-sec8-acc-wrapper {
display: grid;
grid-template-rows: 0fr;
transition: grid-template-rows 0.4s ease;
}
/* 中身の要素(はみ出しを隠す) */
.trs-sec8-acc-content {
overflow: hidden;
font-size: 13px;
color: #555;
line-height: 1.6;
}
/* デザインのためのパディング(内側にdivをもう一つ作って入れると綺麗になりますが、今回はデモ用に直書き) */
.trs-sec8-acc-content {
padding: 0 15px; /* 上下パディングは開閉時に崩れる原因になるため左右のみ */
}
.trs-sec8-acc-check:checked ~ .trs-sec8-acc-wrapper .trs-sec8-acc-content {
padding: 15px; /* 開いた時だけ上下パディングをつけるハック */
}
/* 💡 チェックが入ったら1frにして開く */
.trs-sec8-acc-check:checked ~ .trs-sec8-acc-wrapper {
grid-template-rows: 1fr;
}グラデーション(gradient)が効かない時の代替案
ボタンをホバーした時に、グラデーション色を別のグラデーション色にさせたい要望は多いです。
しかし、「background gradient(またはlinear gradient)」は効きません。
グラデーションを滑らかに変化させたい場合は、要素の裏側(擬似要素 ::before)に変化後のグラデーションを作っておき、ホバーした時に擬似要素のopacityを0から1にフワッと表示させるという演出を使います。
position: relative;
/* 変化前(通常時)のグラデーション */
background: linear-gradient(to right, #0d6efd, #0dcaf0);
z-index: 1;
}
/* 💡 擬似要素に変化後(ホバー時)のグラデーションを作る */
.btn-correct::before {
position: absolute;
background: linear-gradient(to right, #dc3545, #fd7e14);
opacity: 0; /* 💡 最初は見えなくしておく */
transition: opacity 0.4s ease; /* 透明度ならアニメできる! */
}
/* 💡 ホバーしたら擬似要素をフワッと表示する */
.btn-correct:hover::before {
opacity: 1;
}
HTMLコード表示
<div class="trs-sec9-wrapper">
<div class="trs-sec9-demo-area">
<div class="trs-sec9-box">
<div class="trs-sec9-label">🌈 グラデーションを滑らかに変化させる</div>
<div class="trs-sec9-visual">
<div style="display:flex; justify-content:center; gap:20px;">
<button class="trs-sec9-btn trs-sec9-grad-wrong">
❌ 失敗
</button>
<button class="trs-sec9-btn trs-sec9-grad-correct">
<span>⭕️ 正解</span>
</button>
</div>
</div>
<div class="trs-sec7-code">
<span class="trs-hl-blue">.btn-correct</span> {<br>
<span class="trs-hl-green">position: relative;</span><br>
<span class="trs-hl-comment">/* 変化前(通常時)のグラデーション */</span><br>
<span class="trs-hl-green">background: linear-gradient(to right, #0d6efd, #0dcaf0);</span><br>
<span class="trs-hl-green">z-index: 1;</span><br>
}<br><br>
/* 💡 擬似要素に変化後(ホバー時)のグラデーションを作る */<br>
<span class="trs-hl-blue">.btn-correct::before</span> {<br>
<span class="trs-hl-green">position: absolute;</span><br>
<span class="trs-hl-green">background: linear-gradient(to right, #dc3545, #fd7e14);</span><br>
<span class="trs-hl-red">opacity: 0;</span> /* 💡 最初は見えなくしておく */<br>
<span class="trs-hl-red">transition: opacity 0.4s ease;</span> /* 透明度ならアニメできる! */<br>
}<br><br>
/* 💡 ホバーしたら擬似要素をフワッと表示する */<br>
<span class="trs-hl-blue">.btn-correct:hover::before</span> {<br>
<span class="trs-hl-red">opacity: 1;</span><br>
}
</div>
</div>
</div>
</div>CSSコード表示
.trs-sec9-wrapper {
background-color: #f8f9fa;
padding: 20px;
border: 1px solid #dee2e6;
border-radius: 4px;
font-family: sans-serif;
}
.trs-sec9-demo-area {
display: flex;
justify-content: center;
}
.trs-sec9-box {
background-color: #ffffff;
border: 2px dashed #adb5bd;
padding: 25px;
width: 100%;
max-width: 600px;
border-radius: 4px;
}
.trs-sec9-label {
font-size: 15px;
font-weight: bold;
margin-bottom: 20px;
color: #333;
}
.trs-sec9-visual {
background-color: #f1f3f5;
padding: 40px 20px;
border-radius: 8px;
margin-bottom: 20px;
border: 1px solid #dee2e6;
}
.trs-sec9-btn {
color: #fff;
border: none;
padding: 15px 30px;
border-radius: 50px;
font-weight: bold;
cursor: pointer;
font-size: 14px;
width: 120px;
}
/* ❌ 失敗:直接書き換え(効かない) */
.trs-sec9-grad-wrong {
background: linear-gradient(to right, #0d6efd, #0dcaf0);
transition: background 0.5s ease; /* これを書いても無視される */
}
.trs-sec9-grad-wrong:hover {
background: linear-gradient(to right, #dc3545, #fd7e14);
}
/* ⭕️ 成功:擬似要素を重ねる手法 */
.trs-sec9-grad-correct {
position: relative;
background: linear-gradient(to right, #0d6efd, #0dcaf0);
z-index: 1;
overflow: hidden; /* 角丸からはみ出ないように */
}
/* ボタンの文字が擬似要素に隠れないようにする */
.trs-sec9-grad-correct span {
position: relative;
z-index: 2;
}
.trs-sec9-grad-correct::before {
content: "";
position: absolute;
top: 0; left: 0; right: 0; bottom: 0;
background: linear-gradient(to right, #dc3545, #fd7e14);
opacity: 0;
transition: opacity 0.5s ease;
z-index: 1;
}
.trs-sec9-grad-correct:hover::before {
opacity: 1;
}コピペで使える!ホバーエフェクト等の実例サンプル
transitionの仕組みを理解したら、実務で使われるパターンをストックしておくだけです。
サンプルとして、Webサイトで頻出するレイアウトを厳選しました。
ご自身のプロジェクトに合わせて、デザインの色や数値を微調整しながらご活用ください。
- ボタン・画像のホバー(色変更・拡大・回転)
- フェードインやメニューのスライド(左右上下)
- アコーディオン展開やモーダル・ポップアップ
ボタン・画像のホバー(色変更・拡大・回転)
Webサイトにおいて多用されるのが、マウスを乗せた時のホバーエフェクトです。
ボタンホバーや画像の拡大は、ユーザーに「ここはクリックできる」と直感的に伝える重要な役割を持ちます。
.btn {
background-color: #0d6efd;
transition: background-color 0.3s ease, transform 0.3s ease, box-shadow 0.3s ease;
}
.btn:hover {
background-color: #0b5ed7;
transform: translateY(-5px); /* 上に浮く */
box-shadow: 0 10px 15px rgba(0,0,0,0.2);
}
/* 💡 2. 画像の拡大・回転(親枠ではみ出しを隠す) */
.img-wrap {
overflow: hidden; /* 💡 拡大してはみ出た部分を隠す */
}
.img-inner {
transition: transform 0.5s cubic-bezier(0.25, 1, 0.5, 1);
}
.img-wrap:hover .img-inner {
transform: scale(1.5) rotate(10deg); /* 1.5倍に拡大し、10度回転 */
}
HTMLコード表示
<div class="ex-sec1-wrapper">
<div class="ex-sec1-demo-area">
<div class="ex-sec1-box">
<div class="ex-sec1-label">👆 ボタン・画像のホバーエフェクト</div>
<div class="ex-sec1-visual">
<div class="ex-sec1-item">
<button class="ex-sec1-btn">HOVER ME</button>
</div>
<div class="ex-sec1-item">
<div class="ex-sec1-img-wrap">
<div class="ex-sec1-img-inner">写真</div>
</div>
</div>
</div>
<div class="ex-sec1-code">
/* 💡 1. ボタンのホバー(ベースにtransitionを指定) */<br>
<span class="ex-hl-blue">.btn</span> {<br>
<span class="ex-hl-green">background-color: #0d6efd;</span><br>
<span class="ex-hl-red">transition: background-color 0.3s ease, transform 0.3s ease, box-shadow 0.3s ease;</span><br>
}<br>
<span class="ex-hl-blue">.btn:hover</span> {<br>
<span class="ex-hl-green">background-color: #0b5ed7;</span><br>
<span class="ex-hl-green">transform: translateY(-5px);</span> /* 上に浮く */<br>
<span class="ex-hl-green">box-shadow: 0 10px 15px rgba(0,0,0,0.2);</span><br>
}<br><br>
/* 💡 2. 画像の拡大・回転(親枠ではみ出しを隠す) */<br>
<span class="ex-hl-blue">.img-wrap</span> {<br>
<span class="ex-hl-green">overflow: hidden;</span> /* 💡 拡大してはみ出た部分を隠す */<br>
}<br>
<span class="ex-hl-blue">.img-inner</span> {<br>
<span class="ex-hl-red">transition: transform 0.5s cubic-bezier(0.25, 1, 0.5, 1);</span><br>
}<br>
<span class="ex-hl-blue">.img-wrap:hover .img-inner</span> {<br>
<span class="ex-hl-green">transform: scale(1.5) rotate(10deg);</span> /* 1.5倍に拡大し、10度回転 */<br>
}
</div>
</div>
</div>
</div>CSSコード表示
.ex-sec1-wrapper {
background-color: #f8f9fa;
padding: 20px;
border: 1px solid #dee2e6;
border-radius: 4px;
font-family: sans-serif;
}
.ex-sec1-demo-area {
display: flex;
justify-content: center;
}
.ex-sec1-box {
background-color: #ffffff;
border: 2px dashed #adb5bd;
padding: 25px;
width: 100%;
max-width: 600px;
border-radius: 4px;
}
.ex-sec1-label {
font-size: 15px;
font-weight: bold;
margin-bottom: 20px;
color: #333;
}
.ex-sec1-visual {
background-color: #f1f3f5;
padding: 40px 20px;
border-radius: 8px;
margin-bottom: 20px;
border: 1px solid #dee2e6;
display: flex;
justify-content: space-around;
align-items: center;
flex-wrap: wrap;
gap: 30px;
}
.ex-sec1-item {
display: flex;
justify-content: center;
}
/* 1. ボタン */
.ex-sec1-btn {
background-color: #0d6efd;
color: #fff;
border: none;
padding: 15px 30px;
border-radius: 50px;
font-weight: bold;
font-size: 16px;
cursor: pointer;
box-shadow: 0 4px 6px rgba(0,0,0,0.1);
/* 💡 ベース指定 */
transition: background-color 0.3s ease, transform 0.3s ease, box-shadow 0.3s ease;
}
.ex-sec1-btn:hover {
background-color: #0b5ed7;
transform: translateY(-5px);
box-shadow: 0 10px 15px rgba(13, 110, 253, 0.3);
}
/* 2. 画像(の代わりのボックス) */
.ex-sec1-img-wrap {
width: 150px;
height: 100px;
border-radius: 8px;
/* 💡 はみ出しを隠すのが鉄則 */
overflow: hidden;
box-shadow: 0 4px 6px rgba(0,0,0,0.1);
cursor: pointer;
}
.ex-sec1-img-inner {
width: 100%;
height: 100%;
background-image: linear-gradient(135deg, #20c997, #198754);
color: #fff;
display: flex;
align-items: center;
justify-content: center;
font-weight: bold;
/* 💡 ベース指定 */
transition: transform 0.5s cubic-bezier(0.25, 1, 0.5, 1);
}
.ex-sec1-img-wrap:hover .ex-sec1-img-inner {
/* 拡大と回転を組み合わせる */
transform: scale(1.5) rotate(10deg);
}
.ex-sec1-code {
background-color: #282c34;
color: #abb2bf;
padding: 15px;
font-family: monospace;
font-size: 13px;
border-radius: 4px;
line-height: 1.6;
border-left: 4px solid #0d6efd;
}
.ex-hl-green { color: #98c379; font-weight: bold; }
.ex-hl-blue { color: #61afef; font-weight: bold; }
.ex-hl-red { color: #e06c75; font-weight: bold; }buttonタグの使い方を詳しく知りたい人は「【HTML】buttonタグの使い方:リンク・CSS装飾・無効化」を一読ください。
また、写真に使うimgタグの使い方を詳しく知りたい人は「【HTML】imgタグの使い方:src・altの使い分けや画像リサイズ・中央寄せ」を一読ください。
フェードインやメニューのスライド(左右上下)
ページ読み込み時の「フェードイン」、ナビゲーションメニューの展開も実務で実装する機能です。
「上から下へ」や「左から右へ」といった方向を持ったアニメーションは、空間の広がりを感じさせます。
スライドさせる移動処理は、transform: translateY()(縦の移動)またはtranslateX()(横の移動)を使用してください。
また、見えない状態からの出現はopacityとvisibilityを組み合わせるのが最適解です。
※「メニュー ▼」にマウスを乗せてください。
上から下へ滑らかにスライド表示されます。
-
メニュー ▼
- サブメニュー 1
- サブメニュー 2
- サブメニュー 3
.dropdown {
visibility: hidden;
opacity: 0;
/* 💡 上に15pxズラしておく(ここから降りてくる) */
transform: translateY(-15px);
transition: all 0.3s ease;
}
/* 💡 親要素(li)をホバーした時の状態 */
.nav-item:hover .dropdown {
visibility: visible;
opacity: 1;
/* 💡 元の位置(0)に戻ることでスライドダウンになる */
transform: translateY(0);
}
HTMLコード表示
<div class="ex-sec2-wrapper">
<div class="ex-sec2-demo-area">
<div class="ex-sec2-box">
<div class="ex-sec2-label">🗂 ドロップダウンメニュー(スライドダウン)</div>
<div class="ex-sec2-visual">
<p style="font-size:12px; color:#555; margin-bottom:20px; text-align:center;">
※「メニュー ▼」にマウスを乗せてください。<br>上から下へ滑らかにスライド表示されます。
</p>
<div class="ex-sec2-nav-wrap">
<ul class="ex-sec2-nav">
<li class="ex-sec2-nav-item">
<span class="ex-sec2-nav-link">メニュー ▼</span>
<ul class="ex-sec2-dropdown">
<li>サブメニュー 1</li>
<li>サブメニュー 2</li>
<li>サブメニュー 3</li>
</ul>
</li>
</ul>
</div>
</div>
<div class="ex-sec1-code">
/* 💡 隠れているドロップダウンの初期状態 */<br>
<span class="ex-hl-blue">.dropdown</span> {<br>
<span class="ex-hl-green">visibility: hidden;</span><br>
<span class="ex-hl-green">opacity: 0;</span><br>
<span class="ex-hl-comment">/* 💡 上に15pxズラしておく(ここから降りてくる) */</span><br>
<span class="ex-hl-green">transform: translateY(-15px);</span><br>
<span class="ex-hl-red">transition: all 0.3s ease;</span><br>
}<br><br>
/* 💡 親要素(li)をホバーした時の状態 */<br>
<span class="ex-hl-blue">.nav-item:hover .dropdown</span> {<br>
<span class="ex-hl-green">visibility: visible;</span><br>
<span class="ex-hl-green">opacity: 1;</span><br>
<span class="ex-hl-comment">/* 💡 元の位置(0)に戻ることでスライドダウンになる */</span><br>
<span class="ex-hl-green">transform: translateY(0);</span><br>
}
</div>
</div>
</div>
</div>CSSコード表示
.ex-sec2-wrapper {
background-color: #f8f9fa;
padding: 20px;
border: 1px solid #dee2e6;
border-radius: 4px;
font-family: sans-serif;
}
.ex-sec2-demo-area {
display: flex;
justify-content: center;
}
.ex-sec2-box {
background-color: #ffffff;
border: 2px dashed #adb5bd;
padding: 25px;
width: 100%;
max-width: 600px;
border-radius: 4px;
}
.ex-sec2-label {
font-size: 15px;
font-weight: bold;
margin-bottom: 20px;
color: #333;
}
.ex-sec2-visual {
background-color: #f1f3f5;
padding: 30px 20px;
border-radius: 8px;
margin-bottom: 20px;
border: 1px solid #dee2e6;
/* 💡 縦並びに変更 */
display: flex;
flex-direction: column;
align-items: center;
min-height: 250px; /* メニューが開くスペースを確保 */
}
.ex-sec2-nav-wrap {
position: relative;
z-index: 10;
}
.ex-sec2-nav {
list-style: none;
padding: 0;
margin: 0;
}
.ex-sec2-nav-item {
position: relative;
}
.ex-sec2-nav-link {
display: inline-block;
background-color: #343a40;
color: #fff;
padding: 15px 30px;
border-radius: 4px;
font-weight: bold;
cursor: pointer;
/* 💡 文字が縦に潰れるのを防ぐ */
white-space: nowrap;
}
/* 💡 ドロップダウン(初期状態) */
.ex-sec2-dropdown {
list-style: none;
padding: 10px 0;
margin: 0;
background-color: #fff;
border: 1px solid #ced4da;
border-radius: 4px;
box-shadow: 0 10px 20px rgba(0,0,0,0.1);
position: absolute;
top: 100%; /* 親要素のすぐ下 */
left: 50%;
transform: translateX(-50%) translateY(-15px); /* 中央寄せしつつ上に15pxズラす */
width: 200px;
/* アニメーションの仕込み */
visibility: hidden;
opacity: 0;
transition: all 0.3s ease;
}
.ex-sec2-dropdown li {
padding: 10px 20px;
color: #333;
font-size: 14px;
border-bottom: 1px solid #f8f9fa;
cursor: pointer;
}
.ex-sec2-dropdown li:hover {
background-color: #f1f3f5;
}
/* 💡 ホバーで表示 */
.ex-sec2-nav-item:hover .ex-sec2-dropdown {
visibility: visible;
opacity: 1;
transform: translateX(-50%) translateY(0); /* スライドダウンさせながら中央を維持 */
}
.ex-sec1-code {
background-color: #282c34;
color: #abb2bf;
padding: 15px;
font-family: monospace;
font-size: 13px;
border-radius: 4px;
line-height: 1.6;
border-left: 4px solid #0d6efd;
}
.ex-hl-green { color: #98c379; font-weight: bold; }
.ex-hl-blue { color: #61afef; font-weight: bold; }
.ex-hl-red { color: #e06c75; font-weight: bold; }
.ex-hl-comment { color: #6c757d; font-style: italic; }ドロップダウンメニューの作り方を詳しく知りたい人は「【HTML】プルダウン・セレクトボックス・ドロップダウンの作り方:コンボボックスとの違い」を一読ください。
アコーディオン展開やモーダル・ポップアップ
ユーザーのアクションに合わせて詳細な情報を表示するの代表格が、アコーディオンや画面中央に出るモーダルです。
ポップアップを表示する際は、非表示のベース状態にtransform: scale(0.95);(少し縮小) を仕込んでおき、表示するタイミングでtransform: scale(1);(元のサイズ) に戻すアニメーションをopacityと同時に実行します。
これにより、画面の手前にフワッと飛び出してくるような、立体的で心地よいポップアップが完成します。
.modal-content {
visibility: hidden;
opacity: 0;
/* 💡 0.95倍に縮小しておく */
transform: scale(0.95);
transition: all 0.3s cubic-bezier(0.25, 1, 0.5, 1);
}
/* 💡 表示フラグ(チェック)が入った時 */
.check:checked ~ .overlay .modal-content {
visibility: visible;
opacity: 1;
/* 💡 等倍に戻すことで手前に飛び出す演出になる */
transform: scale(1);
}
HTMLコード表示
<div class="ex-sec3-wrapper">
<div class="ex-sec3-demo-area">
<div class="ex-sec3-box">
<div class="ex-sec3-label">💬 モーダル・ポップアップ(スケールアップ)</div>
<div class="ex-sec3-visual">
<input type="checkbox" id="ex-sec3-toggle" class="ex-sec3-hidden-check">
<label for="ex-sec3-toggle" class="ex-sec3-open-btn">
ポップアップを開く
</label>
<div class="ex-sec3-modal-overlay">
<div class="ex-sec3-modal-content">
<div style="margin:0 0 10px 0;">お知らせ</div>
<p style="font-size:13px; color:#555; margin-bottom:20px;">
少し縮小した状態(scale: 0.95)から元のサイズ(scale: 1)に戻すことで、手前にポンッと飛び出すような心地よい動きになります。
</p>
<label for="ex-sec3-toggle" class="ex-sec3-close-btn">閉じる</label>
</div>
</div>
</div>
<div class="ex-sec1-code">
/* 💡 モーダル本体(初期状態は少し小さくしておく) */<br>
<span class="ex-hl-blue">.modal-content</span> {<br>
<span class="ex-hl-green">visibility: hidden;</span><br>
<span class="ex-hl-green">opacity: 0;</span><br>
<span class="ex-hl-comment">/* 💡 0.95倍に縮小しておく */</span><br>
<span class="ex-hl-green">transform: scale(0.95);</span><br>
<span class="ex-hl-red">transition: all 0.3s cubic-bezier(0.25, 1, 0.5, 1);</span><br>
}<br><br>
/* 💡 表示フラグ(チェック)が入った時 */<br>
<span class="ex-hl-blue">.check:checked ~ .overlay .modal-content</span> {<br>
<span class="ex-hl-green">visibility: visible;</span><br>
<span class="ex-hl-green">opacity: 1;</span><br>
<span class="ex-hl-comment">/* 💡 等倍に戻すことで手前に飛び出す演出になる */</span><br>
<span class="ex-hl-green">transform: scale(1);</span><br>
}
</div>
</div>
</div>
</div>CSSコード表示
.ex-sec3-wrapper {
background-color: #f8f9fa;
padding: 20px;
border: 1px solid #dee2e6;
border-radius: 4px;
font-family: sans-serif;
}
.ex-sec3-demo-area {
display: flex;
justify-content: center;
}
.ex-sec3-box {
background-color: #ffffff;
border: 2px dashed #adb5bd;
padding: 25px;
width: 100%;
max-width: 600px;
border-radius: 4px;
}
.ex-sec3-label {
font-size: 15px;
font-weight: bold;
margin-bottom: 20px;
color: #333;
}
.ex-sec3-visual {
background-color: #f1f3f5;
padding: 40px 20px;
border-radius: 8px;
margin-bottom: 20px;
border: 1px solid #dee2e6;
position: relative; /* モーダルの絶対配置の基準 */
min-height: 250px;
display: flex;
justify-content: center;
align-items: center;
overflow: hidden; /* デモ枠からはみ出ないように */
}
.ex-sec3-hidden-check {
display: none;
}
.ex-sec3-open-btn {
background-color: #198754;
color: #fff;
padding: 12px 24px;
border-radius: 50px;
cursor: pointer;
font-weight: bold;
}
/* 💡 黒い半透明の背景(オーバーレイ) */
.ex-sec3-modal-overlay {
position: absolute;
top: 0; left: 0; width: 100%; height: 100%;
background-color: rgba(0,0,0,0.5);
display: flex;
align-items: center;
justify-content: center;
z-index: 100;
/* アニメーション */
visibility: hidden;
opacity: 0;
transition: all 0.3s ease;
}
/* 💡 モーダル本体 */
.ex-sec3-modal-content {
background-color: #fff;
width: 80%;
max-width: 300px;
padding: 25px;
border-radius: 12px;
text-align: center;
box-shadow: 0 15px 30px rgba(0,0,0,0.2);
/* 💡 ポップアップの要(スケールアニメ) */
visibility: hidden;
opacity: 0;
transform: scale(0.9); /* 少し小さくしておく */
transition: all 0.4s cubic-bezier(0.25, 1, 0.5, 1);
}
.ex-sec3-close-btn {
display: inline-block;
background-color: #6c757d;
color: #fff;
padding: 8px 16px;
border-radius: 4px;
cursor: pointer;
font-size: 13px;
font-weight: bold;
}
/* 💡 チェックが入った時の状態変化 */
.ex-sec3-hidden-check:checked ~ .ex-sec3-modal-overlay {
visibility: visible;
opacity: 1;
}
.ex-sec3-hidden-check:checked ~ .ex-sec3-modal-overlay .ex-sec3-modal-content {
visibility: visible;
opacity: 1;
transform: scale(1); /* 等倍に戻す */
}モーダルウィンドウやポップアップに利用するdialogタグの使い方を詳しく知りたい人は「【HTML】dialogタグの使い方:モーダルウィンドウや枠外クリック・CSS装飾」を一読ください。
まとめ
分かりやすいようにまとめを記載します。
transitionは、ある状態から別の状態への変化を指定した時間で滑らかに補間するプロパティである。- ホバー時のアニメーションを実装する際は、
:hover側ではなく、変化前のベースとなるクラスに指定する。 - 移動や拡大などの変化は、描画負荷の軽い
transformプロパティと組み合わせて実装する。 - 自走・ループする
animationとは異なり、変化を発火させる「きっかけ(ホバーやクラス付与など)」が必要となる。 - プロパティの一括指定で時間を2つ記述した場合、1つ目が「変化時間」、2つ目が「遅延時間」として解釈される。
- サイトの動作が重くなる原因となるため
transition: allの多用は避け、動かしたいプロパティをカンマ区切りで明示的に指定する。 display: none;に対するアニメーションは無効になるため、visibilityとopacityの切り替えで代用する。height: 0からautoへのアニメーションは、Gridのgrid-template-rows(0fr → 1fr)を使って実装する。- 背景グラデーションを滑らかに変化させたい場合は、擬似要素に変化後のグラデーションを作り、
opacityでフェードインさせる。
よくある質問(FAQ)
transitionとanimation(@keyframes)の違いは何ですか?
大きな違いは「トリガー(きっかけ)の有無」と「複雑さ」です。
transitionは、ホバー(:hover)やクラスの追加など「何かしらのアクション」をきっかけとして、AからBへのシンプルな1回限りの状態変化を作るのに適しています。
一方、animation(@keyframes)は、ページ読み込みと同時に自動再生させたり、A→B→Cと複数の状態を経由したり、無限ループさせたり、複雑で独立した動きを作りたい場合に使用します。
マウスを外した時に動きがカクつくのはなぜですか?
transitionプロパティを:hoverの疑似クラス側に書いてしまっていることが原因です。
ホバー側のみ時間を指定すると、マウスを外した瞬間にアニメーションの指示が消滅するため、元の状態へパッと戻ってしまいます。
行きも帰りも滑らかに動かすには、ホバーされる前の「通常時(ベース)」のクラスに対してtransitionを指定してください。
display: noneからdisplay: blockに切り替わる時にフワッと表示させられますか?
いいえ、CSSの仕様上displayプロパティに対してtransitionをかけることはできません。
パッと表示・非表示が切り替わってしまいます。
フワッとフェードイン・フェードアウトさせたい場合は、displayを使うのをやめ、代わりにvisibility: hidden;とopacity: 0;から、visibility: visible;とopacity: 1; へと変化させる手法を使うのが解決策です。
transitionとtransformの違いは何ですか?
役割が全く異なります。
これらは対立するものではなく、セットで組み合わせて使うものです。
transform(変形)
要素を「どのように変えるか(移動、拡大縮小、回転など)」を指定します。
アニメーション機能はありません。transition(変化)
その変形に対して「どれくらいの時間をかけて滑らかに動かすか」を指定します。
つまり、「transformで指定した移動を、transitionで0.3秒かけて滑らかに実行する」という使い方が基本になります。
複数のプロパティを同時にtransitionさせるにはどうすればいいですか?
カンマ(,)で区切って記述します。
例:transition: background-color 0.3s ease, transform 0.5s ease;
このように書くことで、色と大きさで別々のアニメーション時間を設定することも可能です。
なお、transition: all 0.3s;と書くことで全ての変化を一括指定できますが、意図しないレイアウト変化までアニメーション処理してしまいブラウザの動作が重くなる原因になるため、実務では動かしたいプロパティだけをカンマ区切りで明示的に指定するのが推奨されています。

