Panda Noir

JavaScript の限界を究めるブログです。

もう分からないとは言わせない! 体系的に学ぶCSS transform 3D入門

(この記事はQiitaで僕が書いたものを移行した記事です。記事中のコメントはQiitaの該当記事を参照ください)

目次

  1. まえがき
  2. transform関数
  3. 軸について
  4. 複数指定の場合の順序についての注意点
  5. transformはブラウザごとに表示が大きく違う
  6. ベンダープレフィクス
  7. rotate
  8. translate
  9. skew
  10. scale
  11. matrix
  12. transform-styleのpreserve-3d
  13. サイコロをCSSで作る

まえがき: 記事中の画像について

記事中の画像は、青が変形前、赤、緑が青を変形した後の要素となっています。参考にしてください。

transform関数とは

transformプロパティの値として使われる関数です。rotate系、translate系、skew系、scale系、matrix、matrix3d、perspectiveがあります。

「系」と記したものはrotateX、translateYのように軸ごとにそれぞれあります。面倒なのでまとめて「系」と記しました。記事中で出てくるrotateなどは、ほぼrotate系を指しています。

座標軸の注意点

座標軸の正の方向

ここでいう座標軸とは、translate・rotateで変形する際に使われる軸のことです。どちらも同じ軸を使って変形するので、ここでまとめて説明しておきます。

軸にはx軸・y軸・z軸の3種類あります。

x軸、y軸はそれぞれ スクリーン横方向、縦方向 です。数学の座標そのままですね。z軸は スクリーンを貫く方向 …といえば伝わるでしょうか?

正の方向は、x軸は右方向、y軸は下方向、z軸はスクリーンから自分に向かってくる向きです。

display.png

(座標軸と正の方向の図)

座標軸の回転方向

回転方向は「正の方向から負の方向へ見た時に時計回り」です。分かりづらいと思うので下の画像をご覧ください。

axis.png

(軸の回転方向の図)

3軸は通常、要素の中央で交わります。これはCSSのtransform-originプロパティを使うことで変更可能です。 transform-originのサンプルです。 transform-origin

座標軸に関する注意点

x軸・y軸・z軸は 要素ごとに設定されています。どういうことかと言うと、要素を回転させると、座標軸も共に回転します。

複雑なtransform関数の複数指定

指定順に適用される

transformでは rotate + translate のようにtransform関数を複数同時に適用できます。ただし、 記述順に変形されます。

さきほど軸は要素を回転させるとともに回転すると書きました。つまり、 translateZ を行った後 rotateX をするのと、 rotateX をしたあとに translateZ をするのでは結果が異なります。複数指定するときはこのことに気をつけましょう。

実際に順序が違うとどうなるか画像を用意しました。

order.png

(transformの記述順による変形の違いの図)

上の図では赤がrotateが先、緑がtranslateが先です。それ以外の条件は同じにしてあります。

上の画像のコードは表記順による違いからどうぞ。

後ろに書いたtransform関数は「上書き」ではなく「追加」

例えば

.translate1 {
  transform: translateX(100px);
}
.translate2 {
  transform: translateX(100px) translateX(100px);
}

別物 です。.translate2では.translate1にさらに translateX(100px) しています。

CSSだと後ろに書いたほうが優先されるので勘違いしがちです。

検証コード

transformはブラウザによって表示結果がかなり違う

まず、transformならではの問題から話します。

3D周りはやはり実装が難しいのか、 モダンブラウザ間でも 表示が全く違うことがよくあります。バグも多いです。

なんと、同じWebKit系列のSafariChromeでさえも異なることが多々あります。transformを使うときは普段以上に複数のブラウザで動作確認することが大切です。「一つのモダンブラウザで動いたから終わり」では大変危険です。

browser.png

(ブラウザ間で表示が異なるの図 上: Chrome、下: Safari)

ちなみに上の画像、たぶんSafariはバグです。僕の予想どおりの挙動だったのはChromeだったので。上の画像の再現コードはこちら

ベンダープレフィクス

ここ半年ほどの情報が全く出回ってなかったので、ベンダープレフィクスの必要性についてはわかりませんでした。おそらくほぼ全てのモダンブラウザでバグこそあれど、transformはサポートしています。しかし、transform-styleなど一部プロパティにはまだベンダープレフィクスをつけた方がいいかもしれません。

rotate()から始める

前振りも終わりいよいよ入門編です。まずは rotate() からはじめます。 rotate() は回転させるだけなのでさして難しいことはありません。

rotateX()rotateY()rotateZ() はそれぞれx軸、y軸、z軸周りに回転させます。そのままですね。

rotate() のサンプルです。重なっているので赤というより紫になってますね。

rotate.png

(rotate()のサンプル画像)

rotate3D()について

rotate3D(x, y, z, deg) では回転軸を自由に設定できます。 (x, y, z)で定められた方向ベクトルを回転軸にします。

まだベクトルを習ってない人は、原点と(x, y, z)を通る直線を軸にする、と考えてください。

回転方向は上の軸の画像と同じ方向です。

原点を変更するにはtransform-originというプロパティを使います。

ちなみに、rotate()は全てrotate3D()の糖衣構文です。書き換え可能です。まあ可読性下げて冗長になるだけなので rotate3d() に書き換えるメリットはありません。

translate()

translate()指定した量だけ要素を移動させます 。3D方向にも移動させることができるのが特徴です。

回転と移動を同時に行う場合は まず移動させてから回転させる 、とすると書きやすいです。先に回転させると軸も一緒に回ってしまうので、どう移動すればいいのかわかりづらくなります。

perspectiveプロパティが必要です

Z軸方向に移動させるときは奥行きを設定する perspective というCSSプロパティを設定する必要があります。指定しない場合は奥行き0なので移動させても意味がありません。perspectivetranslate() する要素の親要素に設定してください。

perspective プロパティ の代わりに transform: perspective() でも可能です。この場合は translate() する要素に直接設定してください。

skew()

まずサンプル skew

これが一番の曲者です。回転でも移動でもない「傾斜変形」です。言葉で説明する前にまず画像を見てもらいます。

skew.png

(skew()のサンプル画像)

これが skewX() で変形した要素です。ちなみに skewX(80deg) をするとこうなります。ちょっと面白い。

skew2.png

(skew(80deg)のサンプル画像)

skewX() がどういう変形を加えているか説明します。まず要素を1pxの幅に切ります。次にその要素を回転させます。最後に、高さが元の要素と同じになるよう引き伸ばします。

skewY() でも高さ1pxに要素を切り回転させ拡大するという同様の変形をしています。

…うまい説明ができなくてすいません。

scale()

scale() は拡大縮小をします。以上です。…しいて言うなら、数値は%ではなく何倍かで指定します。1倍なら拡大縮小をしません。これはほんとに言うことないですね。そのまんまです。

matrix()

matrix() は行列を用いて変形します。 僕もいまいち理解できてません。 コメントで大変わかりやすいスライドを教えていただきました。高校で行列を習ってない僕でも理解できました。一読をお勧めします。

3Dの場合は(x, y, z, 1)という行列に4x4の行列( matrix3d() の引数として定義される行列)を掛けた結果を用いて変形します。数学では回転、正射影、反転、拡大縮小なら(x, y, z)のみで良いのですが、線形変形で平行移動をするにはどうしても4次元目が必要となります。

ちなみに、rotate()scale()skew()translate() らは全て matrix() の糖衣構文です。ただし、 matrix() に書き直すと冗長になり、可読性も落ちます。matrix() なしで4つだけでもほとんどのことはできるので、 matrix() は基本使わない方針でいるのが幸せだと思います。

transform-styleのpreserve-3d

これに関しては、とほほさんの説明が逸品です。参照先でサンプルもあるので御覧ください。

CSS - transform-style

サンプル作りました。preserve-3d

あまりわかりやすくないですが、一応説明します。CSSのtransform-styleプロパティはデフォルトではflatが設定されています。このプロパティをflatで設定すると親要素をスクリーンとして親要素に子要素を映し出すような変形となります。例えば子要素を rotate() で回転させた後親要素も回転させるとします。もしtransform-styleがflatの場合、パソコンの画面を回したような表示になります。

子要素を立体的に回転させたいときは親要素にpreserve-3dを設定する必要があります。

ちなみにIEは12以上で対応してます。つまり11以下では使えません。

サイコロを作る

以上を踏まえて最後にサイコロを作ってみたいと思います。

6面をdivでつくり、それをtransformで回転+移動させることでできそうです。

完成品がこちら

サイコロ

CSSだけで立体が作れる、結構すごいですよね!