ボタンにマウスを乗せたとき、色がパッと切り替わるのではなく、ふわっとなめらかに変わるサイトを見たことはないでしょうか。あの動きは CSS の transition プロパティで実現できます。この記事では、transition の基本的な書き方から、各サブプロパティ(変化させる対象・時間・速度の変化・遅延)の役割、よく使う一括指定の構文、そして「設定したのに動かない」というつまずきの原因までを、初心者の方にも分かるように順番に解説します。JavaScript を使わずにアニメーションを付けたい方に役立つ内容です。
目次
transition とは何か
transition は、要素のプロパティ(背景色や大きさなど)が変化するとき、その変化を一定の時間をかけてなめらかにつなぐためのプロパティです。通常、CSS のプロパティは値が変わった瞬間に切り替わりますが、transition を指定しておくと、変わる前の状態から変わったあとの状態へ少しずつ移り変わるようになります。
典型的な使いどころは、:hover でボタンの色を変えるケースです。ホバーしたときと外したときの両方で、なめらかに色が行き来します。transition は「どのプロパティを」「どれくらいの時間で」「どんな速さの変化で」「いつから」動かすかを指定して使います。
基本の使い方
まずは最小の例を見てみましょう。背景色を 0.3 秒かけて変化させる、もっともシンプルな書き方です。transition は 変化前の状態(通常のセレクタ側) に書くのがポイントです。:hover 側ではなく、元の状態に書くことで、ホバー時もホバーを外したときも両方なめらかになります。
.button {
background-color: #3b82f6;
/* background-color の変化を 0.3 秒かけて行う */
transition: background-color 0.3s;
}
.button:hover {
background-color: #1d4ed8;
}
これだけで、ボタンにマウスを乗せると背景色が 0.3 秒かけてゆっくり濃い青に変わり、外すと元に戻ります。transition 自体はアニメーションのきっかけを作るものではなく、あくまで「値が変わったときの変化の付け方」を決めるものだと覚えておくと理解しやすいです。値を変えるきっかけは :hover や :focus、JavaScript によるクラスの付け外しなどが担います。
4 つのサブプロパティ
transition は、4 つの個別プロパティをまとめた一括指定(ショートハンド)です。それぞれを個別に書くこともできます。まずは 4 つの役割を整理しておきましょう。
| プロパティ | 役割 |
|---|---|
transition-property | 変化させる対象のプロパティ名(background-color など)。all ですべて、none で無効。 |
transition-duration | 変化にかける時間。0.3s や 300ms のように秒またはミリ秒で指定する。 |
transition-timing-function | 時間の中での速さの変化(イージング)。ease や linear など。 |
transition-delay | 変化が始まるまでの待ち時間。0.2s なら 0.2 秒待ってから動き出す。 |
個別に書くと次のようになります。一括指定だけでも十分ですが、対応関係を把握しておくと読みやすくなります。
.button {
transition-property: background-color; /* 何を */
transition-duration: 0.3s; /* どれくらいの時間で */
transition-timing-function: ease; /* どんな速さの変化で */
transition-delay: 0s; /* いつから */
}
一括指定(ショートハンド)の書き方
実際の制作では、transition プロパティ 1 行でまとめて書くのが一般的です。値はスペース区切りで並べます。順番は基本的に自由ですが、時間に関する値(duration と delay)は 先に書いた方が duration、後に書いた方が delay と解釈されるため、この 2 つだけは順番が意味を持ちます。
/* property duration timing-function delay の順で書いた例 */
.button {
transition: background-color 0.3s ease 0s;
}
/* 複数のプロパティはカンマで区切って並べる */
.card {
transition: transform 0.3s ease, box-shadow 0.3s ease;
}
/* すべてのプロパティをまとめて変化させたいときは all */
.box {
transition: all 0.4s ease-in-out;
}
複数のプロパティに別々の時間やイージングを設定したいときは、カンマで区切って並べます。all は手軽ですが、意図しないプロパティまで変化対象になり、パフォーマンスや予期せぬ動きの原因になることがあります。動かしたいプロパティが決まっているなら、transform や opacity のように明示するのがおすすめです。
timing-function(イージング)の値
transition-timing-function は、決められた時間の中で「どんな速さの配分で変化するか」を決めます。同じ 0.3 秒でも、最初はゆっくりで終わりが速い、あるいは一定の速さで進む、といった違いを付けられます。代表的なキーワードは次のとおりです。
| 値 | 動きの特徴 |
|---|---|
ease | 初期値。ゆっくり始まり、中盤で速くなり、終わりでまたゆっくりになる自然な動き。 |
linear | 最初から最後まで一定の速さで変化する。 |
ease-in | ゆっくり始まり、終わりに向かって加速する。 |
ease-out | 速く始まり、終わりに向かって減速する。 |
ease-in-out | ゆっくり始まってゆっくり終わる。ease より緩急がはっきりする。 |
cubic-bezier(x1, y1, x2, y2) | ベジェ曲線で速さの変化を自由に定義する。上記キーワードはこれの特定の値にあたる。 |
steps(n) | なめらかに変化させず、n 段階に分けてカクカクと切り替える。 |
細かく動きを調整したいときは cubic-bezier() を使います。たとえば cubic-bezier(0.25, 0.1, 0.25, 1) のように 4 つの数値で曲線を指定でき、独自の緩急を作れます。値を手で決めるのは難しいので、ブラウザの開発者ツールや専用の Web ツールで曲線を見ながら調整すると確実です。
動く例で確認する
言葉だけでは伝わりにくいので、実際に動くデモを用意しました。下のプレビューでボタンとオレンジ色のボックスにマウスを乗せてみてください。ボタンは背景色が変わりながら少し上に浮き上がり、ボックスは all 指定によってサイズ・角丸・色がまとめてなめらかに変化します。CSS タブを開くと、それぞれにどんな transition を書いているか確認できます。
<div class="demo">
<button class="btn">ホバーしてください</button>
<div class="box"></div>
</div>
.demo {
display: flex;
flex-direction: column;
align-items: center;
gap: 32px;
padding: 40px;
font-family: sans-serif;
}
/* ボタン:背景色と少し浮き上がる動きをなめらかに変化させる */
.btn {
padding: 14px 28px;
font-size: 16px;
color: #fff;
background-color: #3b82f6;
border: none;
border-radius: 8px;
cursor: pointer;
/* 一括指定:変化させるプロパティ・時間・イージング */
transition: background-color 0.3s ease, transform 0.3s ease;
}
.btn:hover {
background-color: #1d4ed8;
transform: translateY(-4px); /* 上に少し移動 */
}
/* ボックス:サイズと角丸と色をまとめて変化させる */
.box {
width: 80px;
height: 80px;
background-color: #f59e0b;
border-radius: 8px;
transition: all 0.4s ease-in-out; /* すべてのプロパティを対象に */
}
.box:hover {
width: 160px;
border-radius: 50%;
background-color: #ef4444;
}
transition が効かないときの原因
「設定したはずなのに、なめらかに変化しない」という相談はとても多いです。原因はだいたい決まっているので、代表的なものを順に確認していきましょう。
変化前と変化後で値の単位がそろっていない
transition は、開始値と終了値の両方が具体的な値として決まっていてはじめて、その間を補間できます。たとえば幅を auto から 200px へ変化させようとしても、auto は計算上の中間値を求められないためアニメーションしません。height: auto へのアニメーションが効かないのも同じ理由です。幅や高さを変化させたいときは、200px から 400px のように両端を具体的な値で指定する必要があります。
display: none との切り替えには効かない
要素を display: none から display: block へ切り替えても、transition は働きません。display は段階的に変化させられるプロパティではなく、表示と非表示が一瞬で切り替わるためです。フェードイン・フェードアウトのように見せたいときは、display ではなく opacity や visibility を併用するのが定番です。次の例のように、透明度を 0 から 1 へ変化させると、ふわっと現れる表現になります。
.modal {
opacity: 0;
visibility: hidden;
transition: opacity 0.3s ease, visibility 0.3s ease;
}
/* is-open クラスが付いたときに表示する */
.modal.is-open {
opacity: 1;
visibility: visible;
}
transition を hover 側にだけ書いている
transition を :hover のブロックの中にだけ書くと、マウスを乗せたときはなめらかに変化するのに、外したときは一瞬で元に戻る、という挙動になります。これは、ホバーを外した瞬間には :hover のスタイルが適用されなくなり、transition の指定も同時に消えてしまうためです。前述のとおり、transition は通常の状態(変化前)のセレクタに書くのが基本です。
そもそも変化させられないプロパティを指定している
すべての CSS プロパティがアニメーションできるわけではありません。色・長さ・透明度・transform など連続的な値を持つプロパティは変化させられますが、display のように離散的な値しか取らないものは対象外です。動かしたいプロパティがアニメーション可能かどうかは、MDN の各プロパティのページにある「Animation type」の記載で確認できます。
まとめ
transition は、プロパティの値が変わるときの変化をなめらかにつなぐためのプロパティです。transition-property(対象)・transition-duration(時間)・transition-timing-function(速さの変化)・transition-delay(遅延)の 4 つを、ふだんは transition: background-color 0.3s ease; のように 1 行でまとめて書きます。記述する場所は :hover 側ではなく変化前の状態に書くこと、開始値と終了値を具体的な値でそろえること、display: none からの切り替えには使えないことを押さえておけば、よくあるつまずきは避けられます。まずはボタンのホバーから試して、動きの感覚をつかんでみてください。