ボタンにマウスを乗せたときに少し大きくなったり、アイコンがくるっと回ったりするサイトをよく見かけます。こうした「要素を動かす・変形させる」表現を、JavaScript を使わずに実現できるのが CSS の transform プロパティです。この記事では、translate()(移動)・rotate()(回転)・scale()(拡大縮小)・skew()(傾斜)という代表的な関数の使い方から、複数の関数を組み合わせるときの書き方と適用順序、基準点を変える transform-origin、そして「効かない・意図しない位置になる」原因までを、初心者の方にも分かるように解説します。
目次
transform とは何か
transform は、要素を移動・回転・拡大縮小・傾斜させて、見た目を変形させるためのプロパティです。値には専用の「変形関数」を指定します。たとえば transform: rotate(10deg); と書くと、要素を 10 度だけ回転させて表示できます。
大きな特長は、レイアウトに影響を与えずに見た目だけを動かせる点です。top や margin で位置をずらすと周囲の要素が押し出されてしまいますが、transform で動かしても要素が元々占めていたスペースはそのまま残り、周りのレイアウトは崩れません。また、transform による変形はブラウザが GPU で処理しやすく、滑らかに動きやすいという利点もあります。こうした理由から、アニメーションでは位置やサイズを直接いじるより transform を使うのが定番です。
4 つの基本的な変形関数
transform でよく使う関数は、移動・回転・拡大縮小・傾斜の 4 種類です。それぞれの役割と書き方を整理しておきましょう。
| 関数 | 意味と指定例 |
|---|---|
translate(x, y) | 要素を水平方向 x・垂直方向 y に移動する。translateX() / translateY() で片方だけも指定できる。例: translate(20px, 10px) |
rotate(角度) | 要素を時計回りに回転する。単位は deg(度)。マイナスで反時計回り。例: rotate(45deg) |
scale(x, y) | 要素を拡大・縮小する。1 が等倍、2 で 2 倍、0.5 で半分。1 つだけ書くと縦横同じ倍率になる。例: scale(1.2) |
skew(x, y) | 要素を平行四辺形のように傾斜させる。x は横方向、y は縦方向の角度。例: skew(15deg, 0) |
基本の書き方は次のとおりです。それぞれ単独で指定した例を見てみましょう。
/* 右に 20px、下に 10px 移動する */
.move {
transform: translate(20px, 10px);
}
/* 時計回りに 45 度回転する */
.rotate {
transform: rotate(45deg);
}
/* 1.2 倍に拡大する(縦横とも) */
.scale {
transform: scale(1.2);
}
/* 横方向に 15 度傾ける */
.skew {
transform: skew(15deg);
}
translate() では、%(パーセント)も指定できます。このとき基準になるのは その要素自身のサイズです。たとえば横幅 200px の要素に translateX(50%) を指定すると、要素の幅の 50%、つまり 100px だけ右に移動します。要素を中央に揃える定番のテクニック translate(-50%, -50%) も、この「自分自身のサイズが基準」という性質を利用しています。
複数の関数を組み合わせる
移動と回転を同時に行いたいときなど、複数の変形を組み合わせたい場合は、スペース区切りで関数を並べて書きます。カンマではなくスペースで区切る点に注意してください。
/* 右下に移動しつつ、45 度回転し、1.2 倍に拡大する */
.box {
transform: translate(20px, 10px) rotate(45deg) scale(1.2);
}
適用される順序は右から左
組み合わせるときに知っておきたいのが、関数は右から左の順に適用されるという点です。先ほどの例 translate(20px, 10px) rotate(45deg) scale(1.2) は、まず scale() で拡大し、次に rotate() で回転させ、最後に translate() で移動する、という順で処理されます。
この順序は見た目に大きく影響します。たとえば rotate(45deg) translateX(100px) は「回転させた後の傾いた座標軸」に沿って移動するため、要素は斜め方向に動きます。一方 translateX(100px) rotate(45deg) は、先に 100px 右へ動かしてからその位置で回転するので、最終的な位置が変わります。思った位置にならないときは、関数を書く順番を見直してみてください。
変形の基準点を変える transform-origin
回転や拡大縮小は、どこを中心に変形するかで結果が変わります。その基準点を決めるのが transform-origin プロパティです。初期値は 50% 50%(要素の中央)なので、何も指定しなければ要素の真ん中を軸に回転・拡大します。
値は「横位置 縦位置」の順で、left / center / right や top / bottom といったキーワード、px、% で指定できます。たとえば左上を基準に回転させたいときは次のように書きます。ドアが蝶番を中心に開くような動きを作れます。
.card {
/* 左上の角を基準に変形する */
transform-origin: left top;
transform: rotate(20deg);
}
transition・hover と組み合わせた実用例
transform は、それ単体だと「変形した状態で表示する」だけですが、:hover と transition を組み合わせると、マウスを乗せたときになめらかに変形するインタラクションになります。下のプレビューで 3 枚のカードにマウスを乗せてみてください。左から順に「拡大」「回転」「移動+回転+拡大の組み合わせ」を試せます。CSS タブを開くと、それぞれにどんな transform を指定しているか確認できます。
<div class="demo">
<div class="card card--scale">拡大</div>
<div class="card card--rotate">回転</div>
<div class="card card--combo">組み合わせ</div>
</div>
.demo {
display: flex;
flex-wrap: wrap;
justify-content: center;
align-items: center;
gap: 40px;
padding: 60px 40px;
font-family: sans-serif;
}
/* 共通のカード。transition で変形をなめらかにする */
.card {
display: flex;
justify-content: center;
align-items: center;
width: 120px;
height: 120px;
color: #fff;
font-size: 18px;
border-radius: 12px;
background-color: #3b82f6;
cursor: pointer;
/* transform の変化を 0.4 秒かけてなめらかに */
transition: transform 0.4s ease;
}
/* ホバーで 1.2 倍に拡大 */
.card--scale:hover {
transform: scale(1.2);
}
/* ホバーで 15 度回転 */
.card--rotate:hover {
background-color: #f59e0b;
transform: rotate(15deg);
}
/* 拡大・回転・移動を組み合わせ(右から左の順に適用される) */
.card--combo {
background-color: #ef4444;
}
.card--combo:hover {
transform: translateY(-12px) rotate(-8deg) scale(1.15);
}
ポイントは、transition を通常の状態(.card)に書き、:hover 側で transform の値を指定していることです。こうすることで、マウスを乗せたときも外したときも両方なめらかに動きます。拡大しても周りのカードがずれないのは、前述のとおり transform がレイアウトに影響しないためです。
transform が効かない・意図しない位置になる原因
「指定したのに変形しない」「思った位置にならない」というつまずきは少なくありません。原因はある程度決まっているので、代表的なものを順に確認していきましょう。
インライン要素には効かない
transform は、span や a のようなインライン要素には適用されません。これらの要素に指定しても何も起こらないことがあります。変形させたいときは、対象に display: inline-block や display: block、あるいは display: flex を指定してインラインボックス以外にしてから transform を適用します。div のようなブロック要素や Flex アイテムでは初めから問題なく効きます。
% の基準が要素自身であることを見落としている
translate() に % を使ったとき、思った距離だけ動かないことがあります。これは、translate() の % が 親要素ではなく、その要素自身のサイズを基準にするためです。width や left の % が親基準なのとは異なります。たとえば「親の幅の半分だけ動かしたい」つもりで translateX(50%) と書くと、実際には要素自身の幅の半分しか動きません。要素自身を基準に動かしたいのか、別の値を基準にしたいのかを意識して使い分けてください。
回転や拡大の中心が思った場所と違う
回転させたら予想と違う方向に動いた、というときは transform-origin の影響を疑いましょう。初期値は要素の中央なので、中央を軸に回転・拡大します。左端や下端を軸にしたいのに中央基準のままだと、見た目が大きくずれます。基準点を意図した位置に transform-origin で明示すれば解決します。
関数を書く順番が違う
複数の関数を組み合わせたときに位置がおかしい場合は、適用順序を思い出してください。前述のとおり関数は右から左に適用され、rotate() を先に処理すると以降の translate() は回転後の傾いた軸に沿って動きます。移動してから回転したいのか、回転してから移動したいのかで、関数を書く順番を入れ替える必要があります。
まとめ
transform は、translate()(移動)・rotate()(回転)・scale()(拡大縮小)・skew()(傾斜)といった関数で、レイアウトに影響を与えずに要素の見た目だけを変形できるプロパティです。複数の関数はスペース区切りで並べ、右から左の順に適用されること、変形の基準点は transform-origin で変えられること、そして :hover と transition を組み合わせるとなめらかなインタラクションになることを押さえておけば、よく使う表現はほとんどカバーできます。インライン要素には効かない、translate() の % は要素自身が基準、といったつまずきポイントも頭に入れておくと安心です。まずはホバーで拡大するカードあたりから試してみてください。