LoginSignup
10
2
お題は不問!Qiita Engineer Festa 2024で記事投稿!
Qiita Engineer Festa20242024年7月17日まで開催中!

CSS の transform は個別に分離するのが常に優れているわけではない

Last updated at Posted at 2024-06-30

この記事の概要

CSS で要素を変形をさせるとき、昔ながらの書き方は次のようなものです。

.element {
  transform: translate(30px, 20px) rotate(20deg);
}

最近はそれぞれの指定を分離して、次のようにも書けます。

.element {
  translate: 30px 20px;
  rotate: 20deg;
}

個別に書いた方がアニメーションの管理などはしやすいですし、diff も見やすいです。

ただ、常に個別に書くのが優れているわけでもないので、その点について記事にしました。

例示するもの

こういった 3D 表現を実施する際、移動や回転を多く使います。

この立方体を例にして説明します。

translate のローカル座標とグローバル座標

例に出した立方体はこのようなコードでできています。

<div class="cube">
  <div class="face front">front</div>
  <div class="face back">back</div>
  <div class="face right">right</div>
  <div class="face left">left</div>
  <div class="face top">top</div>
  <div class="face bottom">bottom</div>
</div>
.cube {
  position: relative;
  transform-style: preserve-3d;
  transform: rotateX(-30deg) rotateY(30deg);
}

.face {
  position: absolute;
}

.front {
  transform: translateZ(25dvmin);
}

.back {
  transform: rotateY(180deg) translateZ(25dvmin);
}

.right {
  transform: rotateY(90deg) translateZ(25dvmin);
}

.left {
  transform: rotateY(-90deg) translateZ(25dvmin);
}

.top {
  transform: rotateX(90deg) translateZ(25dvmin);
}

.bottom {
  transform: rotateX(-90deg) translateZ(25dvmin);
}

こちらを、書いてある数値のまま各プロパティに分離してみます。
translateの場合は 1 つの値だけを指定すると X 軸の移動になってしまうので、3 つの値を指定しています。

  .front {
-   transform: translateZ(25dvmin);
+   translate: 0 0 25dvmin;
  }

  .back {
-   transform: rotateY(180deg) translateZ(25dvmin);
+   rotate: y 180deg;
+   translate: 0 0 25dvmin;
  }

  .right {
-   transform: rotateY(90deg) translateZ(25dvmin);
+   rotate: y 90deg;
+   translate: 0 0 25dvmin;
  }

  .left {
-   transform: rotateY(-90deg) translateZ(25dvmin);
+   rotate: y -90deg;
+   translate: 0 0 25dvmin;
  }

  .top {
-   transform: rotateX(90deg) translateZ(25dvmin);
+   rotate: x 90deg;
+   translate: 0 0 25dvmin;
  }

  .bottom {
-   transform: rotateX(-90deg) translateZ(25dvmin);
+   rotate: x -90deg;
+   translate: 0 0 25dvmin;
  }

このコードの場合、次のような見た目になります。

localhost_3000_ (3).png

回転の向きは正しそうですが、すべての面が同じ向き(画面向かって右下)に移動してしまっています。

実は、translateを使ってもともとの見た目を再現するためには、このように書く必要があります。

  .front {
    translate: 0 0 25dvmin;
  }

  .back {
    rotate: y 180deg;
-   translate: 0 0 25dvmin;
+   translate: 0 0 -25dvmin;
  }

  .right {
    rotate: y 90deg;
-   translate: 0 0 25dvmin;
+   translate: 25dvmin 0 0;
  }

  .left {
    rotate: y -90deg;
-   translate: 0 0 25dvmin;
+   translate: -25dvmin 0 0;
  }

  .top {
    rotate: x 90deg;
-   translate: 0 0 25dvmin;
+   translate: 0 -25dvmin 0;
  }

  .bottom {
    rotate: x -90deg;
-   translate: 0 0 25dvmin;
+   translate: 0 25dvmin 0;
  }

transformを使う場合、記載の順番に気を付ける必要はありますがローカル座標で操作できます。
一方でtranslateの場合はグローバル座標での操作となります。

どちらかが優れているというよりは、操作したい内容にあわせて変えた方が良いものだと言えそうです。
例えば幾何形態を考えるときはローカル座標の方が扱いやすいと思っています。

複数軸での rotate が複雑

例に出した立方体は X 軸に -30 度、Y 軸に 30 度傾いています。

transformを用いた書き方はこちらです。

.element {
  transform: rotateX(-30deg) rotateY(30deg);
}

直感に沿っていますね。

次に、rotateを使います。
rotateの書式はrotate: x y z angle;なので、次のように書けば同じ結果が得られそうに思いませんか?

.cube {
  rotate: -1 1 0 30deg;
}

ところが、実際にはこのような見た目になります。

もともとの見た目に近づけようと思うと、次のようになります。

.cube {
  rotate: -1 1 -0.3 45deg;
}

XYZ のベクトルを合成して、その軸にあわせて回転するという仕組み上、各軸の回転量を個別に扱うのが難しいです。

今回の例でいえば X 軸と Y 軸の回転させたい角度が同じなのでまだ考えられますが、それぞれの値が違う場合はかなり難しいです。

これも、どちらが優れているというわけではなく、場合によって使い分けた方が良さそうです。
例えばアイソメトリック風のビューにしたい場合transformでの指定は簡単ですがrotateを使うと複雑です。1

最後に

CSS において、古いプロパティと新しいプロパティがある場合、大抵は新しいプロパティが上位互換です。

ただtransformにおいては一概には言えず、実施したいものにあわせて使い分けるのが良さそうだと思ったので記事にしてみました。

細かなアニメーション制御をしたい場合は個別に、静的に綺麗な配置を実現したい場合は一括、みたいな区分はあるのかもしれません。

  1. 複雑というか、私はどの値ならアイソメトリックっぽい見た目になるか、計算できませんでした……。

10
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
2