【CSS】easeの使い方:inとoutの違いや滑らかなアニメーション

css-ease
ポートフォリオ向けサーバー
HTML/CSSスキルが活きる!
学んだ知識を活かして、
自分だけのブログを始めませんか?

WordPressブログなら、あなたのコーディング知識でデザインのカスタマイズが自由自在。
ブログデビューに最適な初心者向けサーバー環境を徹底比較しました。

Webアニメーションのクオリティを決定づける「イージング(速度変化)」があります。

本記事では、ease基本からcubic-bezierを用いたバウンド表現まで、単なる動きを「心地よいUI」へと昇華させる実践テクニックを解説します。

HTML/CSS学習者の方へ
「学んだコード、自分のブログで試してみませんか?」
多くのブロガーがデザインでつまずく中、コードが読めるあなたは圧倒的に有利です。
自由自在なサイト構築の第一歩となる、初心者向けサーバーを分かりやすく比較しました。

\ スキルを活かして情報発信 / ブログ向けレンタルサーバー4選を読む▶︎
目次

ease(イージング)とは:アニメーションの基本

Webサイトに動きをつける際、「ただ動く」のと「心地よく動く」のには大きな壁があります。

その壁を越えるための鍵となるのが、ease(イージング)という概念です。

イージングとは、アニメーションの「開始から終了までの速度の変化」を制御する仕組みのことです。

自然界の物理法則(摩擦や重力)を模倣し、滑らかな変化を実現することで、ユーザーに直感的で高品質な体験を提供します。

ここでは、イージングアニメーションやサンプルなどの実践的な例を交えながら、基本から各種関数の違いまでを解説します。

ease(イージング)とは:アニメーションの基本
  • transitionanimationの変化の速度を操る仕組み
  • easelinearease-inease-outease-in-outの違いと比較

transitionやanimationの変化の速度を操る仕組み

CSSで要素を動かす際、transition-duration: 1s;のように「何秒かけて動くか(時間)」を指定しますが、イージング機能は、1秒間の中での「スピードの配分」を決定します。

例えば、「最初はゆっくり、途中で加速して、最後はまたゆっくり止まる」といった速度のカーブを描くことができます。

アニメーション速度を操るには、「時間はdurationに任せ、timing-function(イージング)は『物質の重さや摩擦』を表現するために使うこと。UIの動きに現実世界の物理法則を重ね合わせることで、ユーザーが心地よいと感じる自然なアニメーションになること」です。

⭕️ ホバーしてみよう!同じ「1秒」でも、速度の配分で印象が全く変わる!

機械的(linear)

自然・滑らか(ease)

/* ❌ 罠:一定速度(linear)は機械的で不自然な印象を与えやすい */
.ball-linear {
  transition-property: margin-left;
  transition-duration: 1s;
  transition-timing-function: linear; /* 🚨 ずっと同じ速度で進む */
}

/* ⭕️ UIには自然な速度変化(ease等)を取り入れる! */
.ball-ease {
  transition-property: margin-left;
  transition-duration: 1s;
  transition-timing-function: ease; /* 💡 最初と最後が滑らかになる */
}
/* ※実務では transition: margin-left 1s ease; のように一括指定するのが一般的です */
HTMLコード表示
<div class="ease-basic-wrapper">
  
  <p class="ease-basic-caption">⭕️ ホバーしてみよう!同じ「1秒」でも、速度の配分で印象が全く変わる!</p>

  <div class="ease-demo-area">
    
    <div class="demo-track">
      <div class="demo-ball is-linear"></div>
      <p class="track-label">機械的(linear)</p>
    </div>

    <div class="demo-track">
      <div class="demo-ball is-ease"></div>
      <p class="track-label">自然・滑らか(ease)</p>
    </div>

  </div>

  <div class="ease-code-area">
    <span class="hl-comment">/* ❌ 罠:一定速度(linear)は機械的で不自然な印象を与えやすい */</span><br>
    <span class="hl-blue">.ball-linear</span> {<br>
      <span class="hl-green">transition-property:</span> <span class="hl-red">margin-left;</span><br>
      <span class="hl-green">transition-duration:</span> <span class="hl-red">1s;</span><br>
      <span class="hl-green">transition-timing-function:</span> <span class="hl-red">linear;</span> <span class="hl-comment">/* 🚨 ずっと同じ速度で進む */</span><br>
    }<br><br>

    <span class="hl-comment">/* ⭕️ UIには自然な速度変化(ease等)を取り入れる! */</span><br>
    <span class="hl-blue">.ball-ease</span> {<br>
      <span class="hl-green">transition-property:</span> <span class="hl-red">margin-left;</span><br>
      <span class="hl-green">transition-duration:</span> <span class="hl-red">1s;</span><br>
      <span class="hl-green">transition-timing-function:</span> <span class="hl-red">ease;</span> <span class="hl-comment">/* 💡 最初と最後が滑らかになる */</span><br>
    }<br>
    <span class="hl-comment">/* ※実務では transition: margin-left 1s ease; のように一括指定するのが一般的です */</span>
  </div>

</div>
CSSコード表示
.ease-basic-wrapper {
  background-color: #f8f9fa;
  padding: 30px;
  border-radius: 8px;
  border: 1px solid #dee2e6;
}

.ease-basic-caption {
  font-size: 14px;
  font-weight: bold;
  margin-bottom: 20px;
  color: #198754;
  text-align: center;
}

.ease-demo-area {
  display: flex;
  flex-direction: column;
  gap: 20px;
  background-color: #e9ecef;
  padding: 30px 20px;
  border-radius: 8px;
  border: 1px dashed #adb5bd;
  margin-bottom: 20px;
}

/* === デモ用トラックとボール === */
.demo-track {
  width: 100%;
  background-color: #ffffff;
  border: 1px solid #ced4da;
  border-radius: 30px;
  padding: 5px;
  position: relative;
  /* 💡 Flexboxにすることで、中のmargin-left計算を枠内に閉じ込める */
  display: flex; 
  align-items: center;
}

.demo-ball {
  width: 40px;
  height: 40px;
  border-radius: 50%;
  background-color: #0d6efd;
  box-shadow: 0 4px 6px rgba(0,0,0,0.2);
  margin-left: 0;
}

.track-label {
  position: absolute;
  top: 50%;
  left: 60px;
  transform: translateY(-50%);
  margin: 0;
  font-size: 13px;
  font-weight: bold;
  color: #adb5bd;
  pointer-events: none;
}

/* === 💡 速度の変化(ホバーで発動) === */
.is-linear {
  /* 💡 translateではなくmargin-leftで移動させる */
  transition: margin-left 1s linear;
}
.ease-demo-area:hover .is-linear {
  margin-left: calc(100% - 40px); 
}

.is-ease {
  background-color: #198754;
  transition: margin-left 1s ease;
}
.ease-demo-area:hover .is-ease {
  margin-left: calc(100% - 40px);
}

/* =コード解説エリア(エディタ風)= */
.ease-code-area {
  background-color: #282c34;
  color: #abb2bf;
  padding: 20px;
  border-radius: 6px;
  font-family: monospace;
  font-size: 13px;
  line-height: 1.6;
  border-left: 4px solid #0d6efd;
  overflow-x: auto;
  text-align: left;
}
.hl-blue { color: #61afef; font-weight: bold; }
.hl-red { color: #e06c75; font-weight: bold; }
.hl-green { color: #98c379; font-weight: bold; }
.hl-comment { color: #6c757d; font-style: italic; }

transitionの使い方を詳しく知りたい人は「【CSS】transitionの使い方:animationやtransformとの違い」を一読ください。

ease・linear・ease-in・ease-out・ease-in-outの違いと比較

CSSには、あらかじめ用意された5つの代表的なイージングキーワードがあります。

それぞれが全く異なる特徴を持っています。

  1. ease(デフォルト)
    開始は少し早く、終わりにかけて滑らかに減速する。
  2. linear
    常に一定速度。
    ローディングの回転など、無限ループするアニメーション専用。
  3. ease-in
    ゆっくり始まり、最後に加速する。
    物が落下するような動き。
  4. ease-out早く始まり、最後にゆっくり減速する。
    滑り込んだUIが摩擦で止まるような動き。
  5. ease-in-out
    ゆっくり始まり、中間で加速し、最後もゆっくり終わる。
    車の発進と停止のような動き。

UIアニメーションでは、「要素が『現れる時』は、ユーザーの操作に反応するために『ease-out』を使うこと。逆に、要素が『消える時』は、ユーザーの意識から外すために『ease-in』を使うこと」です。

これを逆にすると、非常にストレスの溜まるWebサイトになります。

⭕️ ホバーして競争させよう!それぞれの「初速」と「ブレーキ」の違いを目に焼き付けろ!

ease

開始早め → 滑らかに減速(万能)

linear

ずっと一定速度(ローディング用)

ease-in

開始遅い → 最後に加速(消える時用)

ease-out

開始最速 → 最後に減速(現れる時用)

in-out

ゆっくり開始 → 加速 → ゆっくり終了

/* ❌ 罠:現れるアニメーションに ease-in を使うともっさりする */
.modal-open {
  transition: opacity 0.4s ease-in; /* 🚨 押した瞬間の反応が遅く感じる! */
}

/* ⭕️ 用途に合わせて使い分ける! */
.car-in {
  transition-timing-function: ease-in; /* 💡 画面から消えていく要素に最適 */
}
.car-out {
  transition-timing-function: ease-out; /* 💡 画面に現れる(ホバーする)要素に最適 */
}
.car-in-out {
  transition-timing-function: ease-in-out; /* 💡 行って戻るようなループアニメーションに最適 */
}
HTMLコード表示
<div class="easing-race-wrapper">
  
  <p class="easing-race-caption">⭕️ ホバーして競争させよう!それぞれの「初速」と「ブレーキ」の違いを目に焼き付けろ!</p>

  <div class="easing-race-demo-area">
    
    <div class="race-track">
      <div class="race-car is-ease-default">ease</div>
      <p class="race-label">開始早め → 滑らかに減速(万能)</p>
    </div>

    <div class="race-track">
      <div class="race-car is-linear-func">linear</div>
      <p class="race-label">ずっと一定速度(ローディング用)</p>
    </div>

    <div class="race-track">
      <div class="race-car is-ease-in-func">ease-in</div>
      <p class="race-label">開始遅い → 最後に加速(消える時用)</p>
    </div>

    <div class="race-track">
      <div class="race-car is-ease-out-func">ease-out</div>
      <p class="race-label">開始最速 → 最後に減速(現れる時用)</p>
    </div>

    <div class="race-track">
      <div class="race-car is-ease-in-out-func">in-out</div>
      <p class="race-label">ゆっくり開始 → 加速 → ゆっくり終了</p>
    </div>

  </div>

  <div class="easing-race-code-area">
    <span class="hl-comment">/* ❌ 罠:現れるアニメーションに ease-in を使うともっさりする */</span><br>
    <span class="hl-blue">.modal-open</span> {<br>
      <span class="hl-green">transition:</span> <span class="hl-red">opacity 0.4s ease-in;</span> <span class="hl-comment">/* 🚨 押した瞬間の反応が遅く感じる! */</span><br>
    }<br><br>

    <span class="hl-comment">/* ⭕️ 用途に合わせて使い分ける! */</span><br>
    <span class="hl-blue">.car-in</span> {<br>
      <span class="hl-green">transition-timing-function:</span> <span class="hl-red">ease-in;</span> <span class="hl-comment">/* 💡 画面から消えていく要素に最適 */</span><br>
    }<br>
    <span class="hl-blue">.car-out</span> {<br>
      <span class="hl-green">transition-timing-function:</span> <span class="hl-red">ease-out;</span> <span class="hl-comment">/* 💡 画面に現れる(ホバーする)要素に最適 */</span><br>
    }<br>
    <span class="hl-blue">.car-in-out</span> {<br>
      <span class="hl-green">transition-timing-function:</span> <span class="hl-red">ease-in-out;</span> <span class="hl-comment">/* 💡 行って戻るようなループアニメーションに最適 */</span><br>
    }
  </div>

</div>
CSSコード表示
.easing-race-wrapper {
  background-color: #f8f9fa;
  padding: 30px;
  border-radius: 8px;
  border: 1px solid #dee2e6;
}

.easing-race-caption {
  font-size: 14px;
  font-weight: bold;
  margin-bottom: 20px;
  color: #198754;
  text-align: center;
}

.easing-race-demo-area {
  display: flex;
  flex-direction: column;
  gap: 15px;
  background-color: #e9ecef;
  padding: 30px 20px;
  border-radius: 8px;
  border: 1px dashed #adb5bd;
  margin-bottom: 20px;
}

/* === レース用トラックと車 === */
.race-track {
  width: 100%;
  background-color: #ffffff;
  border-bottom: 2px dashed #ced4da;
  padding: 5px 0;
  position: relative;
  /* 💡 修正:こちらもFlexboxに変更 */
  display: flex; 
  align-items: center;
}

.race-car {
  width: 70px;
  height: 40px;
  border-radius: 4px;
  color: #fff;
  font-size: 12px;
  font-weight: bold;
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 2px 4px rgba(0,0,0,0.2);
  margin-left: 0;
}

.race-label {
  position: absolute;
  left: 90px;
  margin: 0;
  font-size: 12px;
  color: #495057;
  font-weight: bold;
  pointer-events: none;
}

/* === 💡 5つのイージング設定(すべてmargin-leftに修正) === */
.is-ease-default {
  background-color: #0d6efd;
  transition: margin-left 1.5s ease;
}

.is-linear-func {
  background-color: #6c757d;
  transition: margin-left 1.5s linear;
}

.is-ease-in-func {
  background-color: #dc3545;
  transition: margin-left 1.5s ease-in;
}

.is-ease-out-func {
  background-color: #198754;
  transition: margin-left 1.5s ease-out;
}

.is-ease-in-out-func {
  background-color: #fd7e14;
  transition: margin-left 1.5s ease-in-out;
}

/* 🏁 ホバーで一斉にスタート(枠から絶対にはみ出さない) */
.easing-race-demo-area:hover .race-car {
  margin-left: calc(100% - 70px);
}

/* =コード解説エリア(エディタ風)= */
.easing-race-code-area {
  background-color: #282c34;
  color: #abb2bf;
  padding: 20px;
  border-radius: 6px;
  font-family: monospace;
  font-size: 13px;
  line-height: 1.6;
  border-left: 4px solid #0d6efd;
  overflow-x: auto;
  text-align: left;
}

hoverやtransitionでのease-in-outの使い方

ゆっくりと始まり、途中で加速し、最後はまたゆっくりと止まるこのイージングは、現実世界の物理的な動きに最も近く、ユーザーに安心感や高級感を与えます。

ここでは、日常的なホバーやトランジションでのイージングの実装、CodePenなどで見かける実践的なカラーチェンジ、複数プロパティの同時指定方法まで解説します。

hoverやtransitionでのease-in-outの使い方
  • ボタンのホバー時にease-in-outでフワッと色を変える
  • すべてのプロパティを同時に変化させるallの指定

ボタンのホバー時にease-in-outでフワッと色を変える

ボタンにマウスを乗せた際、背景色や文字色をフワッと変化させるカラー変更は、ユーザーに「これは押せる要素だ」と認知させるための基本中の基本です。

トランジションのイージングとは異なり、終わり際にもブレーキがかかるため、色が変化する過程が優雅に見えます。

ホバーエフェクトにease-in-outを用いるには、「ユーザーの操作に対するリアクションは即座に返す必要があるため、変化にかける時間は『0.2秒〜0.3秒(0.2s / 0.3s)』という極めて短い時間に設定すること。これにより、もっさり感を排除しつつ、無意識レベルでの滑らかさだけを担保する」ことです。

⭕️ ホバーして比較!「ease-in-out」は0.3秒以内でキレ良く使え!

初速が遅いため、
反応が鈍くもっさり感じる

キレがありつつ、
色の変化が優雅で滑らか

/* ❌ 罠:滑らかさを求めて時間を長くしすぎる */
.btn-trap {
  background-color: #0d6efd;
  transition: background-color 0.8s ease-in-out; /* 🚨 マウスを乗せてもすぐに色が変わらない! */
}

/* ⭕️ ホバーの ease-in-out は 0.3s 以下でキレを出す! */
.btn-success {
  background-color: #198754;
  transition-property: background-color;
  transition-duration: 0.3s; /* 💡 即座に反応しつつ滑らか */
  transition-timing-function: ease-in-out;
}
.btn-success:hover {
  background-color: #146c43; /* 💡 フワッと暗い色へ変化 */
}
HTMLコード表示
<div class="ease-color-wrapper">
  
  <p class="ease-color-caption">⭕️ ホバーして比較!「ease-in-out」は0.3秒以内でキレ良く使え!</p>

  <div class="ease-color-demo-area">
    
    <div class="color-box">
      <button class="btn-color is-trap-slow">
        ❌ 罠(0.8秒)
      </button>
      <p class="color-desc">初速が遅いため、<br>反応が鈍くもっさり感じる</p>
    </div>

    <div class="color-box">
      <button class="btn-color is-success-fast">
        ⭕️ 成功(0.3秒)
      </button>
      <p class="color-desc">キレがありつつ、<br>色の変化が優雅で滑らか</p>
    </div>

  </div>

  <div class="ease-color-code-area">
    <span class="hl-comment">/* ❌ 罠:滑らかさを求めて時間を長くしすぎる */</span><br>
    <span class="hl-blue">.btn-trap</span> {<br>
      <span class="hl-green">background-color:</span> <span class="hl-red">#0d6efd;</span><br>
      <span class="hl-green">transition:</span> <span class="hl-red">background-color 0.8s ease-in-out;</span> <span class="hl-comment">/* 🚨 マウスを乗せてもすぐに色が変わらない! */</span><br>
    }<br><br>

    <span class="hl-comment">/* ⭕️ ホバーの ease-in-out は 0.3s 以下でキレを出す! */</span><br>
    <span class="hl-blue">.btn-success</span> {<br>
      <span class="hl-green">background-color:</span> <span class="hl-red">#198754;</span><br>
      <span class="hl-green">transition-property:</span> <span class="hl-red">background-color;</span><br>
      <span class="hl-green">transition-duration:</span> <span class="hl-red">0.3s;</span> <span class="hl-comment">/* 💡 即座に反応しつつ滑らか */</span><br>
      <span class="hl-green">transition-timing-function:</span> <span class="hl-red">ease-in-out;</span><br>
    }<br>
    <span class="hl-blue">.btn-success:hover</span> {<br>
      <span class="hl-green">background-color:</span> <span class="hl-red">#146c43;</span> <span class="hl-comment">/* 💡 フワッと暗い色へ変化 */</span><br>
    }
  </div>

</div>
CSSコード表示
.ease-color-wrapper {
  background-color: #f8f9fa;
  padding: 30px;
  border-radius: 8px;
  border: 1px solid #dee2e6;
}

.ease-color-caption {
  font-size: 14px;
  font-weight: bold;
  margin-bottom: 20px;
  color: #198754;
  text-align: center;
}

.ease-color-demo-area {
  display: flex;
  flex-wrap: wrap;
  gap: 30px;
  background-color: #e9ecef;
  padding: 40px 20px;
  border-radius: 8px;
  border: 1px dashed #adb5bd;
  margin-bottom: 20px;
  justify-content: center;
}

.color-box {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 15px;
  width: 100%;
  max-width: 200px;
}

.color-desc {
  margin: 0;
  font-size: 12px;
  color: #555;
  font-weight: bold;
  text-align: center;
  line-height: 1.5;
}

/* === 💡 ボタンのベーススタイル === */
.btn-color {
  width: 100%;
  padding: 15px 0;
  border: none;
  border-radius: 8px;
  font-size: 15px;
  font-weight: bold;
  color: #ffffff;
  cursor: pointer;
}

/* === ❌ 罠:遅すぎる ease-in-out === */
.is-trap-slow {
  background-color: #0d6efd;
  /* 🚨 反応が鈍くなる原因 */
  transition: background-color 0.8s ease-in-out;
}
.is-trap-slow:hover {
  background-color: #0a58ca;
}

/* === ⭕️ 成功:キレのある ease-in-out === */
.is-success-fast {
  background-color: #198754;
  /* 💡 UIに適した0.3秒で設定 */
  transition-property: background-color;
  transition-duration: 0.3s;
  transition-timing-function: ease-in-out;
}
.is-success-fast:hover {
  background-color: #146c43;
}

/* =コード解説エリア(エディタ風)= */
.ease-color-code-area {
  background-color: #282c34;
  color: #abb2bf;
  padding: 20px;
  border-radius: 6px;
  font-family: monospace;
  font-size: 13px;
  line-height: 1.6;
  border-left: 4px solid #0d6efd;
  overflow-x: auto;
  text-align: left;
}
.hl-blue { color: #61afef; font-weight: bold; }
.hl-red { color: #e06c75; font-weight: bold; }
.hl-green { color: #98c379; font-weight: bold; }
.hl-comment { color: #6c757d; font-style: italic; }

すべてのプロパティを同時に変化させるallの指定

ホバー時に色だけでなく、影や位置、枠線など複数のスタイルを同時に変更したい場合があります。

このような時、対象となるプロパティにallを指定することで、指定した要素の「変化したすべてのプロパティ」に対して一括でイージングをかけるという記述が可能です。

複数プロパティを動かすには、実務においてallは極力封印し、面倒でもtransition: background-color 0.3s ease-in-out, transform 0.3s ease-in-out;のようにカンマ区切りで変化させたいプロパティを『明示的に指定』することです。

これにより、ブラウザの無駄な計算負荷を減らし、ヌルヌル動くパフォーマンスを維持するできます。

⭕️ ホバーして確認!無闇な「all」指定は捨て、必要なプロパティだけを狙い撃て!

不要なプロパティまで
アニメーション計算されてしまう

色と変形(transform)だけを
軽量に計算して滑らかに動く

/* ❌ 罠:思考停止で「all」を指定してしまう */
.btn-trap {
  background-color: #6f42c1;
  transform: translateY(0);
  transition: all 0.3s ease-in-out; /* 🚨 万能に見えるが、不要な計算負荷を生む原因になる */
}

/* ⭕️ 動かしたいプロパティだけをカンマ(,)で繋いで指定する! */
.btn-success {
  background-color: #fd7e14;
  transform: translateY(0);
  transition-property: background-color, transform, box-shadow; /* 💡 狙い撃ち! */
  transition-duration: 0.3s;
  transition-timing-function: ease-in-out;
}
.btn-success:hover {
  background-color: #e8590c;
  transform: translateY(-5px);
  box-shadow: 0 5px 15px rgba(0,0,0,0.3);
}
HTMLコード表示
<div class="ease-all-wrapper">
  
  <p class="ease-color-caption">⭕️ ホバーして確認!無闇な「all」指定は捨て、必要なプロパティだけを狙い撃て!</p>

  <div class="ease-all-demo-area">
    
    <div class="all-box">
      <button class="btn-all is-trap-all">
        ❌ 罠(all指定)
      </button>
      <p class="all-desc">不要なプロパティまで<br>アニメーション計算されてしまう</p>
    </div>

    <div class="all-box">
      <button class="btn-all is-success-explicit">
        ⭕️ 成功(明示指定)
      </button>
      <p class="all-desc">色と変形(transform)だけを<br>軽量に計算して滑らかに動く</p>
    </div>

  </div>

  <div class="ease-color-code-area">
    <span class="hl-comment">/* ❌ 罠:思考停止で「all」を指定してしまう */</span><br>
    <span class="hl-blue">.btn-trap</span> {<br>
      <span class="hl-green">background-color:</span> <span class="hl-red">#6f42c1;</span><br>
      <span class="hl-green">transform:</span> <span class="hl-red">translateY(0);</span><br>
      <span class="hl-green">transition:</span> <span class="hl-red">all 0.3s ease-in-out;</span> <span class="hl-comment">/* 🚨 万能に見えるが、不要な計算負荷を生む原因になる */</span><br>
    }<br><br>

    <span class="hl-comment">/* ⭕️ 動かしたいプロパティだけをカンマ(,)で繋いで指定する! */</span><br>
    <span class="hl-blue">.btn-success</span> {<br>
      <span class="hl-green">background-color:</span> <span class="hl-red">#fd7e14;</span><br>
      <span class="hl-green">transform:</span> <span class="hl-red">translateY(0);</span><br>
      <span class="hl-green">transition-property:</span> <span class="hl-red">background-color, transform, box-shadow;</span> <span class="hl-comment">/* 💡 狙い撃ち! */</span><br>
      <span class="hl-green">transition-duration:</span> <span class="hl-red">0.3s;</span><br>
      <span class="hl-green">transition-timing-function:</span> <span class="hl-red">ease-in-out;</span><br>
    }<br>
    <span class="hl-blue">.btn-success:hover</span> {<br>
      <span class="hl-green">background-color:</span> <span class="hl-red">#e8590c;</span><br>
      <span class="hl-green">transform:</span> <span class="hl-red">translateY(-5px);</span><br>
      <span class="hl-green">box-shadow:</span> <span class="hl-red">0 5px 15px rgba(0,0,0,0.3);</span><br>
    }
  </div>

</div>
CSSコード表示
.ease-all-wrapper {
  background-color: #f8f9fa;
  padding: 30px;
  border-radius: 8px;
  border: 1px solid #dee2e6;
}

.ease-all-demo-area {
  display: flex;
  flex-wrap: wrap;
  gap: 30px;
  background-color: #e9ecef;
  padding: 40px 20px;
  border-radius: 8px;
  border: 1px dashed #adb5bd;
  margin-bottom: 20px;
  justify-content: center;
}

.all-box {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 15px;
  width: 100%;
  max-width: 250px;
}

.all-desc {
  margin: 0;
  font-size: 12px;
  color: #555;
  font-weight: bold;
  text-align: center;
  line-height: 1.5;
}

/* === 💡 ボタンのベーススタイル === */
.btn-all {
  width: 100%;
  padding: 15px 0;
  border: none;
  border-radius: 8px;
  font-size: 15px;
  font-weight: bold;
  color: #ffffff;
  cursor: pointer;
}

/* === ❌ 罠:allの乱用 === */
.is-trap-all {
  background-color: #6f42c1;
  transform: translateY(0);
  box-shadow: 0 0 0 transparent;
  /* 🚨 実装は楽だが、パフォーマンス面では推奨されない */
  transition: all 0.3s ease-in-out;
}
.is-trap-all:hover {
  background-color: #5936a2;
  transform: translateY(-5px);
  box-shadow: 0 5px 15px rgba(0,0,0,0.3);
}

/* === ⭕️ 成功:カンマ区切りの明示的指定 === */
.is-success-explicit {
  background-color: #fd7e14;
  transform: translateY(0);
  box-shadow: 0 0 0 transparent;
  /* 💡 動かしたいプロパティだけを狙い撃ちしてパフォーマンスを担保 */
  transition-property: background-color, transform, box-shadow;
  transition-duration: 0.3s;
  transition-timing-function: ease-in-out;
}
.is-success-explicit:hover {
  background-color: #e8590c;
  transform: translateY(-5px);
  box-shadow: 0 5px 15px rgba(0,0,0,0.3);
}

/* =コード解説エリア(エディタ風)= */
.ease-color-code-area {
  background-color: #282c34;
  color: #abb2bf;
  padding: 20px;
  border-radius: 6px;
  font-family: monospace;
  font-size: 13px;
  line-height: 1.6;
  border-left: 4px solid #0d6efd;
  overflow-x: auto;
  text-align: left;
}

@keyframesとanimationプロパティでのイージング応用

ホバー時のような単発の動きにはtransitionが便利ですが、複雑な動きや自動で動き続ける要素を作る場合は@keyframesanimationプロパティの出番です。

ここでもイージングは重要な役割を果たします。

基本の動きから、現れる動きや消える動き、あるいは両方を兼ね備えた複合的な動きまで、キーフレームアニメーションにおけるイージングの操り方と応用テクニックを解説します。

@keyframesとanimationプロパティでのイージング応用
  • キーフレームごとの滑らかな進行コントロール
  • アニメーションを無限ループ・反転させる

キーフレームごとの滑らかな進行コントロール

animationプロパティを使う際、イージングは要素全体に1回だけかかるわけではありません。

実は、0%から50%50%から100% といった 「キーフレームの区間ごと」にイージングが適用されるという特殊な仕様を持っています。

キーフレームアニメーションのイージングを操るには、途中のキーフレームを経由する複雑なアニメーションでは、要素全体にイージングをかけるのではなく、linearをベースにしつつ、必要に応じて@keyframesの『内部』で区間ごとにanimation-timing-functionを個別指定して速度を微調整することです。

⭕️ 動作を確認!中継点(50%)がある場合、全体にeaseをかけると途中で止まりかける!

❌ 罠

角(50%)で一度ブレーキがかかる

⭕️ 成功

一定速度でカクつかずに曲がる

/* ❌ 罠:全体にeaseを指定すると、50%の地点でイージングがリセットされる */
.ball-trap {
  animation-name: moveCorner;
  animation-duration: 2s;
  animation-timing-function: ease-in-out; /* 🚨 0~50%と50~100%で2回ブレーキがかかる */
  animation-iteration-count: infinite;
}

/* ⭕️ 中継点がある場合は全体を linear にし、カクつきを防ぐ! */
.ball-success {
  animation-name: moveCorner;
  animation-duration: 2s;
  animation-timing-function: linear; /* 💡 ずっと同じ速度で進ませる */
  animation-iteration-count: infinite;
}

@keyframes moveCorner {
  0% { translate: 0 0; }
  50% { translate: 200px 0; } /* 💡 ここが中継点(角) */
  100% { translate: 200px 50px; }
}
HTMLコード表示
<div class="kf-ease-wrapper">
  
  <p class="kf-ease-caption">⭕️ 動作を確認!中継点(50%)がある場合、全体にeaseをかけると途中で止まりかける!</p>

  <div class="kf-ease-demo-area">
    
    <div class="kf-track">
      <div class="kf-ball is-trap-overall">❌ 罠</div>
      <p class="kf-desc">角(50%)で一度ブレーキがかかる</p>
    </div>

    <div class="kf-track">
      <div class="kf-ball is-success-linear">⭕️ 成功</div>
      <p class="kf-desc">一定速度でカクつかずに曲がる</p>
    </div>

  </div>

  <div class="kf-ease-code-area">
    <span class="hl-comment">/* ❌ 罠:全体にeaseを指定すると、50%の地点でイージングがリセットされる */</span><br>
    <span class="hl-blue">.ball-trap</span> {<br>
      <span class="hl-green">animation-name:</span> <span class="hl-red">moveCorner;</span><br>
      <span class="hl-green">animation-duration:</span> <span class="hl-red">2s;</span><br>
      <span class="hl-green">animation-timing-function:</span> <span class="hl-red">ease-in-out;</span> <span class="hl-comment">/* 🚨 0~50%と50~100%で2回ブレーキがかかる */</span><br>
      <span class="hl-green">animation-iteration-count:</span> <span class="hl-red">infinite;</span><br>
    }<br><br>

    <span class="hl-comment">/* ⭕️ 中継点がある場合は全体を linear にし、カクつきを防ぐ! */</span><br>
    <span class="hl-blue">.ball-success</span> {<br>
      <span class="hl-green">animation-name:</span> <span class="hl-red">moveCorner;</span><br>
      <span class="hl-green">animation-duration:</span> <span class="hl-red">2s;</span><br>
      <span class="hl-green">animation-timing-function:</span> <span class="hl-red">linear;</span> <span class="hl-comment">/* 💡 ずっと同じ速度で進ませる */</span><br>
      <span class="hl-green">animation-iteration-count:</span> <span class="hl-red">infinite;</span><br>
    }<br><br>

    <span class="hl-blue">@keyframes moveCorner</span> {<br>
      <span class="hl-blue">0%</span> { <span class="hl-green">translate:</span> <span class="hl-red">0 0;</span> }<br>
      <span class="hl-blue">50%</span> { <span class="hl-green">translate:</span> <span class="hl-red">200px 0;</span> } <span class="hl-comment">/* 💡 ここが中継点(角) */</span><br>
      <span class="hl-blue">100%</span> { <span class="hl-green">translate:</span> <span class="hl-red">200px 50px;</span> }<br>
    }
  </div>

</div>
CSSコード表示
.kf-ease-wrapper {
  background-color: #f8f9fa;
  padding: 30px;
  border-radius: 8px;
  border: 1px solid #dee2e6;
}

.kf-ease-caption {
  font-size: 14px;
  font-weight: bold;
  margin-bottom: 20px;
  color: #198754;
  text-align: center;
}

.kf-ease-demo-area {
  display: flex;
  flex-direction: column;
  gap: 30px;
  background-color: #e9ecef;
  padding: 30px 20px 100px 20px; /* ボールが下に動く分の余白を確保 */
  border-radius: 8px;
  border: 1px dashed #adb5bd;
  margin-bottom: 20px;
}

/* === アニメーション用のトラックとボール === */
.kf-track {
  position: relative;
  width: 100%;
}

.kf-desc {
  position: absolute;
  top: -25px;
  left: 0;
  margin: 0;
  font-size: 12px;
  font-weight: bold;
  color: #555;
}

.kf-ball {
  width: 60px;
  height: 40px;
  border-radius: 8px;
  color: #fff;
  font-size: 12px;
  font-weight: bold;
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 4px 6px rgba(0,0,0,0.2);
}

/* 共通のキーフレーム(右に行ってから下へ) */
@keyframes moveCornerDemo {
  0% {
    translate: 0 0;
  }
  50% {
    translate: 200px 0;
  }
  100% {
    translate: 200px 60px;
  }
}

/* === ❌ 罠:全体にease-in-outをかける === */
.is-trap-overall {
  background-color: #dc3545;
  animation-name: moveCornerDemo;
  animation-duration: 2.5s;
  /* 🚨 50%の地点でブレーキがかかってしまう */
  animation-timing-function: ease-in-out;
  animation-iteration-count: infinite;
}

/* === ⭕️ 成功:全体をlinearで一定速度にする === */
.is-success-linear {
  background-color: #0d6efd;
  animation-name: moveCornerDemo;
  animation-duration: 2.5s;
  /* 💡 速度を一定にすることで角でも止まらずスムーズに進む */
  animation-timing-function: linear;
  animation-iteration-count: infinite;
}

/* =コード解説エリア(エディタ風)= */
.kf-ease-code-area {
  background-color: #282c34;
  color: #abb2bf;
  padding: 20px;
  border-radius: 6px;
  font-family: monospace;
  font-size: 13px;
  line-height: 1.6;
  border-left: 4px solid #0d6efd;
  overflow-x: auto;
  text-align: left;
}

様々な要素に対するCSSアニメーションの作り方を詳しく知りたい人は「【CSS】アニメーションの作り方:コピペで使えるおしゃれサンプル集」を一読ください。

アニメーションを無限ループ・反転させる

Webサイトのヒーローヘッダーなどで、「フワフワと浮き沈みするオブジェクト」や「ゆっくり点滅するボタン」を見たことがあるでしょう。

このような「行って戻る」動きを実装する際、無限ループと反転の組み合わせは重要です。

infiniteで動きを継続させ、alternateを指定することで、「0% → 100%」まで進んだ後、次は「100% → 0%」へと逆再生で戻ってきます。

これにease-in-outを掛け合わせることで、自然で美しいループアニメーションが完成します。

ループアニメーションは、オブジェクトをフワフワと往復させたい場合は、infinitealternateease-in-outの3つをセットで記述することです。

これにより、重力と浮力を感じるような滑らかな往復運動が実現できます。

⭕️ 動作を確認!「行って戻る」動きには、必ず「alternate」を追加しろ!

👻

❌ alternateなし
浮いた後、下に瞬間移動する

👻

⭕️ alternateあり
息をするように自然に往復する

/* ❌ 罠:往復の指示(alternate)が抜けている */
.icon-trap {
  animation-name: floating;
  animation-duration: 2s;
  animation-timing-function: ease-in-out;
  animation-iteration-count: infinite; /* 🚨 終わったら0%へワープしてしまう */
}

/* ⭕️ 往復運動には infinite alternate を必ずセットで使う! */
.icon-success {
  animation-name: floating;
  animation-duration: 2s;
  animation-timing-function: ease-in-out; /* 💡 両端で滑らかに減速する */
  animation-iteration-count: infinite;
  animation-direction: alternate; /* 💡 100%まで行ったら逆再生で戻る! */
}

@keyframes floating {
  0% { translate: 0 0; }
  100% { translate: 0 -20px; } /* 💡 上に20px浮く */
}
HTMLコード表示
<div class="alt-loop-wrapper">
  
  <p class="alt-loop-caption">⭕️ 動作を確認!「行って戻る」動きには、必ず「alternate」を追加しろ!</p>

  <div class="alt-loop-demo-area">
    
    <div class="loop-box">
      <div class="ghost-icon is-trap-nowarp">👻</div>
      <p class="loop-desc">❌ alternateなし<br>浮いた後、下に瞬間移動する</p>
    </div>

    <div class="loop-box">
      <div class="ghost-icon is-success-alternate">👻</div>
      <p class="loop-desc">⭕️ alternateあり<br>息をするように自然に往復する</p>
    </div>

  </div>

  <div class="alt-loop-code-area">
    <span class="hl-comment">/* ❌ 罠:往復の指示(alternate)が抜けている */</span><br>
    <span class="hl-blue">.icon-trap</span> {<br>
      <span class="hl-green">animation-name:</span> <span class="hl-red">floating;</span><br>
      <span class="hl-green">animation-duration:</span> <span class="hl-red">2s;</span><br>
      <span class="hl-green">animation-timing-function:</span> <span class="hl-red">ease-in-out;</span><br>
      <span class="hl-green">animation-iteration-count:</span> <span class="hl-red">infinite;</span> <span class="hl-comment">/* 🚨 終わったら0%へワープしてしまう */</span><br>
    }<br><br>

    <span class="hl-comment">/* ⭕️ 往復運動には infinite alternate を必ずセットで使う! */</span><br>
    <span class="hl-blue">.icon-success</span> {<br>
      <span class="hl-green">animation-name:</span> <span class="hl-red">floating;</span><br>
      <span class="hl-green">animation-duration:</span> <span class="hl-red">2s;</span><br>
      <span class="hl-green">animation-timing-function:</span> <span class="hl-red">ease-in-out;</span> <span class="hl-comment">/* 💡 両端で滑らかに減速する */</span><br>
      <span class="hl-green">animation-iteration-count:</span> <span class="hl-red">infinite;</span><br>
      <span class="hl-green">animation-direction:</span> <span class="hl-red">alternate;</span> <span class="hl-comment">/* 💡 100%まで行ったら逆再生で戻る! */</span><br>
    }<br><br>

    <span class="hl-blue">@keyframes floating</span> {<br>
      <span class="hl-blue">0%</span> { <span class="hl-green">translate:</span> <span class="hl-red">0 0;</span> }<br>
      <span class="hl-blue">100%</span> { <span class="hl-green">translate:</span> <span class="hl-red">0 -20px;</span> } <span class="hl-comment">/* 💡 上に20px浮く */</span><br>
    }
  </div>

</div>
CSSコード表示
.alt-loop-wrapper {
  background-color: #f8f9fa;
  padding: 30px;
  border-radius: 8px;
  border: 1px solid #dee2e6;
}

.alt-loop-caption {
  font-size: 14px;
  font-weight: bold;
  margin-bottom: 20px;
  color: #198754;
  text-align: center;
}

.alt-loop-demo-area {
  display: flex;
  flex-wrap: wrap;
  gap: 50px;
  background-color: #e9ecef;
  padding: 50px 20px 20px 20px;
  border-radius: 8px;
  border: 1px dashed #adb5bd;
  margin-bottom: 20px;
  justify-content: center;
}

.loop-box {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 20px;
  width: 100%;
  max-width: 200px;
}

.ghost-icon {
  font-size: 50px;
  display: inline-block; /* 💡 変形させるために必須 */
}

.loop-desc {
  margin: 0;
  font-size: 12px;
  color: #555;
  font-weight: bold;
  text-align: center;
  line-height: 1.5;
}

/* 共通の浮遊キーフレーム */
@keyframes floatingDemo {
  0% {
    translate: 0 0;
  }
  100% {
    translate: 0 -25px;
  }
}

/* === ❌ 罠:alternateなし === */
.is-trap-nowarp {
  animation-name: floatingDemo;
  animation-duration: 2s;
  animation-timing-function: ease-in-out;
  animation-iteration-count: infinite;
  /* 🚨 alternateがないため、上に行った瞬間に下にワープする */
}

/* === ⭕️ 成功:alternateあり === */
.is-success-alternate {
  animation-name: floatingDemo;
  animation-duration: 2s;
  animation-timing-function: ease-in-out; /* 💡 上下でフワッと減速する */
  animation-iteration-count: infinite;
  /* 💡 必須:行って戻る反転再生を指定する */
  animation-direction: alternate;
}

/* =コード解説エリア(エディタ風)= */
.alt-loop-code-area {
  background-color: #282c34;
  color: #abb2bf;
  padding: 20px;
  border-radius: 6px;
  font-family: monospace;
  font-size: 13px;
  line-height: 1.6;
  border-left: 4px solid #0d6efd;
  overflow-x: auto;
  text-align: left;
}

バウンドや独自の動きを作るcubic-bezier

easelinearといったあらかじめ用意されたイージングだけでは、どうしても「よくある普通の動き」になりがちです。

Webサイトに個性を出し、よりリッチなユーザー体験を提供するために不可欠なのが、cubic-bezier(3次ベジェ曲線)という機能です。

スマホアプリのような心地よいスワイプ感や要素が跳ねるような物理的なバウンド表現まで、あらゆる「動きのカーブ」を自由デザインできるようになります。

バウンドや独自の動きを作るcubic-bezier
  • cubic-bezier()を使った複雑なカスタムイージング
  • CSSだけで跳ねるような動きを再現する方法

cubic-bezier()を使った複雑なカスタムイージング

標準のイージングキーワード(ease-in-outなど)は、実は裏側ではすべてcubic-bezier()という関数で定義されています。

cubic-bezier()を使うと、cubic-bezier(x1, y1, x2, y2)という4つの数値を指定することで、自分だけのオリジナル速度カーブを作成できます。

カスタムイージングを扱うには、「cubic-bezier の数値を手書きせず、Chromeのデベロッパーツールに内蔵されている『カーブエディタ(紫色の波線アイコン)』やオンラインのジェネレーターを使って視覚的にグラフを調整し、出力された数値をコピペすること」です。

⭕️ ホバーしてみよう!独自に作ったカーブで、動きの「キレ」を極限まで高めろ!

標準 (ease)
カスタム(cubic-bezier)
/* ❌ 罠:当てずっぽうで数値を手打ちすると動きが壊れる */
.box-fail {
  transition-timing-function: cubic-bezier(0.9, 0.1, 0.1, 0.9); /* 🚨 意図しない不自然な加減速になる */
}

/* ⭕️ デベロッパーツールのグラフで作った数値をコピペする! */
.box-custom {
  /* 💡 動きの対象と時間を指定 */
  transition-property: translate;
  transition-duration: 0.8s;
  /* 💡 初速が爆発的に速く、後からブレーキが強くかかるスタイリッシュなカーブ */
  transition-timing-function: cubic-bezier(0.16, 1, 0.3, 1);
}
HTMLコード表示
<div class="bezier-basic-wrapper">
  
  <p class="bezier-basic-caption">⭕️ ホバーしてみよう!独自に作ったカーブで、動きの「キレ」を極限まで高めろ!</p>

  <div class="bezier-demo-area">
    
    <div class="bezier-track">
      <div class="bezier-box is-standard-ease">標準 (ease)</div>
    </div>

    <div class="bezier-track">
      <div class="bezier-box is-custom-bezier">カスタム(cubic-bezier)</div>
    </div>

  </div>

  <div class="bezier-code-area">
    <span class="hl-comment">/* ❌ 罠:当てずっぽうで数値を手打ちすると動きが壊れる */</span><br>
    <span class="hl-blue">.box-fail</span> {<br>
      <span class="hl-green">transition-timing-function:</span> <span class="hl-red">cubic-bezier(0.9, 0.1, 0.1, 0.9);</span> <span class="hl-comment">/* 🚨 意図しない不自然な加減速になる */</span><br>
    }<br><br>

    <span class="hl-comment">/* ⭕️ デベロッパーツールのグラフで作った数値をコピペする! */</span><br>
    <span class="hl-blue">.box-custom</span> {<br>
      <span class="hl-comment">/* 💡 動きの対象と時間を指定 */</span><br>
      <span class="hl-green">transition-property:</span> <span class="hl-red">translate;</span><br>
      <span class="hl-green">transition-duration:</span> <span class="hl-red">0.8s;</span><br>
      <span class="hl-comment">/* 💡 初速が爆発的に速く、後からブレーキが強くかかるスタイリッシュなカーブ */</span><br>
      <span class="hl-green">transition-timing-function:</span> <span class="hl-red">cubic-bezier(0.16, 1, 0.3, 1);</span><br>
    }
  </div>

</div>
CSSコード表示
.bezier-basic-wrapper {
  background-color: #f8f9fa;
  padding: 30px;
  border-radius: 8px;
  border: 1px solid #dee2e6;
}

.bezier-basic-caption {
  font-size: 14px;
  font-weight: bold;
  margin-bottom: 20px;
  color: #198754;
  text-align: center;
}

.bezier-demo-area {
  display: flex;
  flex-direction: column;
  gap: 20px;
  background-color: #e9ecef;
  padding: 30px 20px;
  border-radius: 8px;
  border: 1px dashed #adb5bd;
  margin-bottom: 20px;
}

/* === デモ用トラックとボックス === */
.bezier-track {
  width: 100%;
  background-color: #ffffff;
  border: 1px solid #ced4da;
  border-radius: 8px;
  padding: 5px;
  display: flex;
  align-items: center;
}

.bezier-box {
  padding: 15px 20px;
  border-radius: 4px;
  color: #fff;
  font-weight: bold;
  font-size: 13px;
  margin-left: 0;
  box-shadow: 0 4px 6px rgba(0,0,0,0.2);
}

/* === 💡 1. 標準のease === */
.is-standard-ease {
  background-color: #6c757d;
  /* 💡 プロパティを1行ずつ丁寧に記述 */
  transition-property: margin-left;
  transition-duration: 0.8s;
  transition-timing-function: ease;
}

/* === 💡 2. カスタムのcubic-bezier === */
.is-custom-bezier {
  background-color: #0d6efd;
  /* 💡 スマホアプリのような、初速が速くピタッと止まる高級感のあるカーブ */
  transition-property: margin-left;
  transition-duration: 0.8s;
  transition-timing-function: cubic-bezier(0.16, 1, 0.3, 1);
}

/* 🏁 ホバーで一斉にスタート */
.bezier-demo-area:hover .bezier-box {
  margin-left: calc(100% - 180px); /* 枠内で止める */
}

/* =コード解説エリア(エディタ風)= */
.bezier-code-area {
  background-color: #282c34;
  color: #abb2bf;
  padding: 20px;
  border-radius: 6px;
  font-family: monospace;
  font-size: 13px;
  line-height: 1.6;
  border-left: 4px solid #0d6efd;
  overflow-x: auto;
  text-align: left;
}

.hl-blue { color: #61afef; font-weight: bold; }
.hl-red { color: #e06c75; font-weight: bold; }
.hl-green { color: #98c379; font-weight: bold; }
.hl-comment { color: #6c757d; font-style: italic; }

CSSだけで跳ねるような動きを再現する方法

ポップアップが飛び出す際やお気に入りボタン(ハートマーク)をクリックした際など、要素をプルンとバウンドさせる表現はユーザーの目を引くのに効果的です。

しかし、CSSにはbounceというイージングキーワードが存在しないため、バウンスを実装するには工夫が必要です。

ホバー時の1回だけのバウンドであればcubic-bezierの数値を限界突破させる手法を使い、何度も弾むような重力バウンドであれば@keyframesを使って表現します。

跳ねる動きを実装するには、「ホバー拡大のような1回のバウンドにはcubic-bezier(0.68, -0.55, 0.265, 1.55)のようにY軸を1以上にして『はみ出させる』ことでバネのような弾力を作ること。ボールが落下して何度も弾むような複雑な動きには@keyframestranslateYを刻むこと」です。

⭕️ ホバーして確認!数値を「1以上」に限界突破させると、バネのように跳ね返る!

css transition bounce ease
目標より大きく膨らんで戻る

css animation ease bounce
地面に落ちて何度も弾む

/* ⭕️ トランジションで弾ませるなら、数値を1以上(1.55など)にする! */
.btn-spring {
  transition-property: transform;
  transition-duration: 0.4s;
  /* 💡 最後の数値が 1.55。目標の大きさを一度通り越して戻ってくるバネの動き */
  transition-timing-function: cubic-bezier(0.68, -0.55, 0.265, 1.55);
}
.btn-spring:hover {
  transform: scale(1.2); /* 1.2倍を目指すが、途中で1.3倍くらいまで膨らむ */
}

/* ⭕️ 重力を伴う複雑なバウンドは @keyframes で刻む! */
.ball-gravity:hover {
  animation-name: bouncingBall;
  animation-duration: 1s;
  animation-timing-function: ease;
  animation-fill-mode: both;
}
@keyframes bouncingBall {
  0% { transform: translateY(-80px); animation-timing-function: ease-in; } /* 加速して落ちる */
  40% { transform: translateY(0); animation-timing-function: ease-out; } /* 地面で弾んで減速 */
  65% { transform: translateY(-30px); animation-timing-function: ease-in; }
  85% { transform: translateY(0); animation-timing-function: ease-out; }
  100% { transform: translateY(0); }
}
HTMLコード表示
<div class="bounce-wrapper">
  
  <p class="bounce-caption">⭕️ ホバーして確認!数値を「1以上」に限界突破させると、バネのように跳ね返る!</p>

  <div class="bounce-demo-area">
    
    <div class="bounce-item">
      <button class="bounce-btn is-spring">
        Spring Hover!
      </button>
      <p class="bounce-desc">css transition bounce ease<br>目標より大きく膨らんで戻る</p>
    </div>

    <div class="bounce-item">
      <div class="bounce-ball is-gravity"></div>
      <p class="bounce-desc">css animation ease bounce<br>地面に落ちて何度も弾む</p>
    </div>

  </div>

  <div class="bounce-code-area">
    <span class="hl-comment">/* ⭕️ トランジションで弾ませるなら、数値を1以上(1.55など)にする! */</span><br>
    <span class="hl-blue">.btn-spring</span> {<br>
      <span class="hl-green">transition-property:</span> <span class="hl-red">transform;</span><br>
      <span class="hl-green">transition-duration:</span> <span class="hl-red">0.4s;</span><br>
      <span class="hl-comment">/* 💡 最後の数値が 1.55。目標の大きさを一度通り越して戻ってくるバネの動き */</span><br>
      <span class="hl-green">transition-timing-function:</span> <span class="hl-red">cubic-bezier(0.68, -0.55, 0.265, 1.55);</span><br>
    }<br>
    <span class="hl-blue">.btn-spring:hover</span> {<br>
      <span class="hl-green">transform:</span> <span class="hl-red">scale(1.2);</span> <span class="hl-comment">/* 1.2倍を目指すが、途中で1.3倍くらいまで膨らむ */</span><br>
    }<br><br>

    <span class="hl-comment">/* ⭕️ 重力を伴う複雑なバウンドは @keyframes で刻む! */</span><br>
    <span class="hl-blue">.ball-gravity:hover</span> {<br>
      <span class="hl-green">animation-name:</span> <span class="hl-red">bouncingBall;</span><br>
      <span class="hl-green">animation-duration:</span> <span class="hl-red">1s;</span><br>
      <span class="hl-green">animation-timing-function:</span> <span class="hl-red">ease;</span><br>
      <span class="hl-green">animation-fill-mode:</span> <span class="hl-red">both;</span><br>
    }<br>
    <span class="hl-blue">@keyframes bouncingBall</span> {<br>
      <span class="hl-blue">0%</span> { <span class="hl-green">transform:</span> <span class="hl-red">translateY(-80px);</span> <span class="hl-green">animation-timing-function:</span> <span class="hl-red">ease-in;</span> } <span class="hl-comment">/* 加速して落ちる */</span><br>
      <span class="hl-blue">40%</span> { <span class="hl-green">transform:</span> <span class="hl-red">translateY(0);</span> <span class="hl-green">animation-timing-function:</span> <span class="hl-red">ease-out;</span> } <span class="hl-comment">/* 地面で弾んで減速 */</span><br>
      <span class="hl-blue">65%</span> { <span class="hl-green">transform:</span> <span class="hl-red">translateY(-30px);</span> <span class="hl-green">animation-timing-function:</span> <span class="hl-red">ease-in;</span> }<br>
      <span class="hl-blue">85%</span> { <span class="hl-green">transform:</span> <span class="hl-red">translateY(0);</span> <span class="hl-green">animation-timing-function:</span> <span class="hl-red">ease-out;</span> }<br>
      <span class="hl-blue">100%</span> { <span class="hl-green">transform:</span> <span class="hl-red">translateY(0);</span> }<br>
    }
  </div>

</div>
CSSコード表示
.bounce-wrapper {
  background-color: #f8f9fa;
  padding: 30px;
  border-radius: 8px;
  border: 1px solid #dee2e6;
}

.bounce-caption {
  font-size: 14px;
  font-weight: bold;
  margin-bottom: 20px;
  color: #198754;
  text-align: center;
}

.bounce-demo-area {
  display: flex;
  flex-wrap: wrap;
  gap: 50px;
  background-color: #e9ecef;
  padding: 80px 20px 40px 20px; /* 上に十分な余白を確保 */
  border-radius: 8px;
  border: 1px dashed #adb5bd;
  margin-bottom: 20px;
  justify-content: space-around;
}

.bounce-item {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 20px;
  width: 100%;
  max-width: 200px;
}

.bounce-desc {
  margin: 0;
  font-size: 12px;
  color: #555;
  font-weight: bold;
  text-align: center;
  line-height: 1.5;
}

/* === 💡 1. transition + cubic-bezier のスプリング === */
.bounce-btn {
  background-color: #fd7e14;
  color: #fff;
  border: none;
  padding: 15px 25px;
  font-size: 15px;
  font-weight: bold;
  border-radius: 8px;
  cursor: pointer;
  
  /* 💡 丁寧に1行ずつ記述 */
  transition-property: transform;
  transition-duration: 0.5s;
  /* 💡 最後の値が1以上。目標を一度オーバーシュートするバネの動き */
  transition-timing-function: cubic-bezier(0.68, -0.55, 0.265, 1.55);
}

.bounce-item:hover .is-spring {
  /* 1.2倍を指定しているが、イージングの反動で一度1.3倍くらいまで膨らむ */
  transform: scale(1.2); 
}

/* === 💡 2. animation + keyframes の重力落下 === */
.bounce-ball {
  width: 50px;
  height: 50px;
  background-color: #6f42c1;
  border-radius: 50%;
  box-shadow: 0 10px 10px rgba(0,0,0,0.2);
}

/* 💡 ホバーでアニメーション発動 */
.bounce-item:hover .is-gravity {
  animation-name: bouncingGravity;
  animation-duration: 1s;
  animation-timing-function: ease; /* 基本はeaseにしつつ中で上書き */
  animation-fill-mode: both;
}

/* 💡 内部で ease-in(落下加速) と ease-out(弾み減速) を切り替える */
@keyframes bouncingGravity {
  0% {
    transform: translateY(-80px);
    animation-timing-function: ease-in;
  }
  40% {
    transform: translateY(0);
    animation-timing-function: ease-out;
  }
  65% {
    transform: translateY(-30px);
    animation-timing-function: ease-in;
  }
  85% {
    transform: translateY(0);
    animation-timing-function: ease-out;
  }
  100% {
    transform: translateY(0);
  }
}

/* =コード解説エリア(エディタ風)= */
.bounce-code-area {
  background-color: #282c34;
  color: #abb2bf;
  padding: 20px;
  border-radius: 6px;
  font-family: monospace;
  font-size: 13px;
  line-height: 1.6;
  border-left: 4px solid #0d6efd;
  overflow-x: auto;
  text-align: left;
}

まとめ

分かりやすいようにまとめを記載します。

本記事のまとめ
  • 役割
    アニメーションの総時間は変えず、開始から終了までの「速度の配分」を制御する。
  • 基本の5種類
    ease: 滑らかに減速(万能)
    linear: 常に一定速度(ローディング・無限ループ用)
    ease-in: 後から加速(消える時用)
    ease-out: 初速が最速で減速(現れる時用)
    ease-in-out: ゆっくり始まり、ゆっくり終わる(ホバー・往復用)
  • ホバーの鉄則
    もっさり感を防ぐため、ホバー時のease-in-outは0.3秒以内に設定する。
  • all指定の回避
    描画パフォーマンスの低下を防ぐため、allは避け、変化させるプロパティを明示的に指定する。
  • キーフレームの制御
    @keyframesで中間点がある場合、全体をlinearにして区間ごとの意図しない減速を防ぐ。
  • 往復ループ
    フワフワとした往復運動には、infinite(無限)とalternate(反転再生)をセットで指定する。
  • カスタムイージング
    cubic-bezier()の数値は手打ちせず、ブラウザの検証ツール等で生成する。
  • バウンド表現
    cubic-bezier()のY軸を1以上に設定することで、跳ね返るような動きを実装できる。

よくある質問(FAQ)

easeとease-in-outの違いは何ですか?

どちらも滑らかな動きですが、「初速」が異なります。

ease(デフォルト)は最初が少し速く、終点に向けて滑らかに減速する万能なカーブです。

一方、ease-in-outは「ゆっくり始まり、途中で加速し、ゆっくり終わる」という対称的なカーブを描きます。

ボタンのホバーエフェクトや行ったり来たりするループアニメーションにはease-in-outが適しています。

linearはどういう時に使うべきですか?

linearは「常に一定の速度」で変化するイージングです。

自然な加減速がないため、UIのホバーや移動などに使うと機械的で不自然な印象を与えてしまいます。

しかし、ローディングアイコンの回転(360度回り続ける)や背景画像を無限に横スクロールさせるような「ずっと同じ速度で動き続けるループアニメーション」には必須の設定となります。

アニメーションの反応が遅く、もっさり感じます。どうすればいいですか?

イージングにease-in(最初が遅い)を指定しているか、変化にかける時間(duration)が長すぎる可能性があります。

ユーザーの操作に対するリアクションは即座に返す必要があるため、ホバーアニメーションの時間は0.2sまたは0.3s程度に短く設定し、イージングは初速が速いeaseease-out、またはキレのあるease-in-outを使用してください。

@keyframesでアニメーションを作ると、途中で一瞬カクッと止まるのはなぜですか?

animation-timing-function(イージング)は、アニメーション全体に1回ではなく「キーフレーム(0%から50%など)の区間ごと」に適用されるためです。

途中に中継点(50%等)がある複雑なアニメーション全体にeaseをかけると、中継点を通過するたびにブレーキがかかってしまいます。

これを防ぐには、アニメーション全体をlinear(一定速度)にし、必要に応じて@keyframesの内部で区間ごとにイージングを個別指定してください。

要素がゴムのように「跳ね返る」動きをCSSだけで作れますか?

はい、cubic-bezier()関数を使うことで作成可能です。

通常、ベジェ曲線の数値は0〜1の間で指定しますが、Y軸の数値(2番目と4番目の数値)を「1以上」または「マイナス」に設定することで、目標地点を一度オーバーして戻ってくる「オーバーシュート(跳ね返り)」を作ることができます。

例:cubic-bezier(0.68, -0.55, 0.265, 1.55)

CONTACT

サイト制作でお困りの人はお気軽にご連絡ください。
どんなお悩み事も丁寧に返信させて頂きます。

WordPress移行
Webサイトを公開しよう!

「どのサーバーを選べばいいか分からない…」そんな悩みを解決!
WordPressデビューに最適なサーバーを徹底比較しました。

この記事を書いた人

sugiのアバター sugi Site operator

【経歴】玉川大学工学部卒業→新卒SIer企業入社→2年半後に独立→プログラミングスクール運営/受託案件→フリーランスエンジニア&SEOコンサル→Python特化のコンテンツサイトJob Code&UIコピペサイトCode Stock運営中

目次