メインコンテンツまでスキップ

えっ!?まだtransformプロパティを使ってるの!?

投稿情報
CSS

みんな独立したプロパティ使ってる。使ってないのお前だけ。

transformは与えられた要素に移動(translate)、拡大縮小(scale)、回転(rotate)、傾斜(skew)などの変形(transform)を適応させるCSSプロパティです。

transform: translate(-50%, -50%);で中央寄せ(現在ではあまり使用されないレガシーな手法です)といった静的な配置に用いることもありますが、主にCSSアニメーションを実装する際に使われることが多いです。

そのtransformプロパティの値のうち傾斜(skew)以外は現在では独立したプロパティで指定することができます。

/* 従来の書き方 */
.sample {
transform: translateY(12px) rotate(90deg) scale(1.1);
}
/* 独立した書き方 */
.sample {
translate: 0 12px;
rotate: 90deg;
scale: 1.1;
}

プロパティを独立させるとアニメーションの管理がしやすくなる

従来のtransformプロパティでは複数の値が指定された際、1つの値だけをアニメーションする場合にも他の値を重複して指定する必要がありました。

See the Pen by tak-dcxi (@tak-dcxi) on CodePen.

簡単なボタンのサンプルです。

ボタンのシェブロンをCSSで表現するとして、従来のtransformプロパティで実装するとしたらだいたい次のようなCSSコーディングになると思います。

.button {
display: inline-grid;
grid-template-columns: 1fr auto 1fr;
gap: 1em;
align-items: center;
inline-size: min(100%, 25rem);
padding-block: 1em;
padding-inline: 1.5em; /* padding:1em 1.5em;は物理プロパティなので分けて記述 */
color: var(--color-text);
background-color: var(--background);
border-radius: 4px;
transition: background-color var(--duration);
&::before {
content: ''; /* テキストを通常時は中央寄せにしながら、テキストが多い場合は左寄せにするために必要 */
}
&::after {
display: inline-block;
justify-self: end;
inline-size: 0.5em;
aspect-ratio: 1;
content: '';
border-block-start: 1px solid;
border-inline-end: 1px solid;
transform: rotate(45deg);
}
&:where(:any-link):focus-visible {
background-color: var(--background-hover);
}
@media (any-hover: hover) {
&:where(:any-link):hover {
background-color: var(--background-hover);
}
}
}

ここにホバー時はシェブロンを右側に4px移動させるという条件を追加したら、transformプロパティだと次のように本来書かなくてもいいようなrotate(45deg)を含む必要があります。

.button {
&::after {
transform: rotate(45deg);
transition: transform var(--duration);
}
&:where(:any-link):focus-visible::after {
transform: translateX(4px) rotate(45deg);
}
@media (any-hover: hover) {
&:where(:any-link):hover::after {
transform: translateX(4px) rotate(45deg);
}
}
}

一方独立したプロパティを使用すればrotate(45deg)を含まずにtranslateの値を変えるだけで実現できます。

.button {
&::after {
rotate: 45deg;
transition: translate var(--duration);
}
&:where(:any-link):focus-visible::after {
translate: 4px;
}
@media (any-hover: hover) {
&:where(:any-link):hover::after {
translate: 4px;
}
}
}

今回は簡単な例ですが、アニメーションが複雑になればなるほど従来のtransformプロパティでは管理がしにくくなるでしょう。

独立したプロパティのほうが簡潔に書ける

独立したプロパティのほうが短く簡潔にスタイリングできます。

/* これが */
.sample {
transform: translateX(12px);
transform: rotate(45deg);
transform: scale(1.2);
}
/* こうなる */
.sample {
translate: 12px;
rotate: 45deg;
scale: 1.2;
}

ただし、難点としてはtranslateにはY軸(あるいはZ軸)のみの記述、scaleにはX軸Y軸(あるいはZ軸)のみの記述は存在しないため、そういった場合はX軸Y軸の指定も追加しないといけません。

.sample {
transform: translateY(100%);
transform: scaleX(1.1);
transform: scaleY(1.2);
}
/* 独立したプロパティ */
.sample {
translate: 0 100%;
scale: 1.1 1;
scale: 1 1.2;
}

それでもtransformプロパティよりは短い記述で済むことが多いです。

傾斜(skew)には独立したプロパティが無い

他の値に比べるとマイナー感が否めないskewですが、残念ながら独立したプロパティはございません。

ただし、独立したプロパティとtransformプロパティは共存できるため、skewを指定する場合はtransformプロパティをそれ専用として扱うのがベターだと思います。

独立したプロパティは全モダンブラウザで対応済み

独立したプロパティは全モダンブラウザで対応されております。懸念のiOS Safariも 14.1 14.5 から導入されているので使用しても差し支えないでしょう。

iOS Safariは14.1からという誤りがありましたが、正しくは14.5からです。ご指摘いただきありがとうございます。

ちなみに記事執筆時点でChatGPTには「そんなプロパティは存在しない」と怒られるため、CSSのレビューをChatGPTで行う際は注意しましょう。