uga.dev - A Front-end Engineer's shed

現在のテーマは「ライトモード」です。

CSSのカンマ区切りとスペース区切りの違い

公開日:

  • #CSS
  • #Web標準
  • #Tips

CSSプロパティの値(Value)の内容を区切るとき、カンマとスペースどちらが正しいか悩む!という方のためのメモ書き。

覚えるのが大変!という方には残念なお知らせですが、厳密には仕様を確認するしかありません。とはいえ、理屈を知ることで、なんとなく想像で判断できるようになるかもしれないです。

TailWindCSSで任意の値(arbitrary values)を指定する際にも役立ちます。

transition-property opacity, visibility; の例
// NG
<div className="transition-[opacity_visibility]" />
// OK
<div className="transition-[opacity,visibility]" />
grid-template-columns 30% 70%; の例
// NG
<div className="grid-cols-[30%,70%]" />
// OK
<div className="grid-cols-[30%_70%]" />

というわけで今回は、CSSの区切り文字がどのように決められているのかを、仕様書の読み方と合わせてご紹介しようと思います。

結論:スペース → カンマ → スラッシュ

CSSの区切り文字にどれを採用するかは、次のような優先順位で決められています。

  • スペースだけで解決できる → スペース

  • スペースだけだと境界が分からなくなる → カンマ

  • さらに区切り文字が必要 → スラッシュ

たとえばtransitionプロパティも、この優先順位で区切り文字が定義されています。通常はスペース区切りですが、複数トークン[1]からなる塊が繰り返される場合にカンマが登場します。

値に4つのトークンを持つ例
.hoge {
  transition: color 1s ease-out 0.3s;
}
「2つのトークンの塊」と「3つのトークンの塊」を持つ例
.hoge {
  transition:
    color 0.3s,
    background-color 0.3s ease-out;
}

仕様書を読んでみる

まずはCSS Transitions Module Level1を例に、仕様書ではどのように定義されているかを確認してみましょう。

CSSのサンプルコード
.hoge {
  transition: color 0.3s ease-out;
}

たとえば、transitionプロパティの値の書き方は、一体どこで説明されているのでしょうか。

The transition shorthand property combines the four properties described above into a single property.

Name: 'transition'Value: <single-transition>#

出典: 2.5. The transition Shorthand Property - CSS Transitions Module Level 1

値(Value)の項目を見てみると、<single-transition>#とありますね。末尾の「#」は「カンマ区切りで1つ以上並べる」という意味を表しています[2]。ここをみることでカンマ区切りかどうかを判断できます。

では次に、<single-transition>とは一体なんなのかを見てみましょう。

<single-transition> = [ none | <single-transition-property> ] || <time> || <easing-function> || <time>

Note that order is important within the items in this property: the first value that can be parsed as a time is assigned to the transition-duration, and the second value that can be parsed as a time is assigned to transition-delay.

If there is more than one <single-transition> in the shorthand, and any of the transitions has none as the <single-transition-property>, then the declaration is invalid.

出典: 2.5. The transition Shorthand Property - CSS Transitions Module Level 1

<single-transition>のプロダクション[3]をみると、次のように書かれています。

<single-transition>のプロダクション
<single-transition> =
  [ none | <single-transition-property> ]
  || <time>
  || <easing-function>
  || <time>

上記の||(二重線)は選択肢の中から「任意の順序で必ず1つ以上指定する必要がある」という意味です[4]

ここでは#記号が使われていませんが、区切り記号が明示されていない場合はスペース区切りを意味します[5]

  • noneまたは<single-transition-property>[6]

  • <time>[7]

  • <easing-function>

  • <time>

つまり、スペース区切りで1つ〜4つのトークンを並べられるのが<single-transition>。それをカンマ区切りで複数記述できるのが、transitionプロパティだということが読み解けます。

区切り文字が分からなくなった際は、このようにして仕様書を読み解いていきましょう。

もう少し深掘り:transition-property

CSSのサンプルコード
.hoge {
  transition-property: opacity, visibility;
}

せっかくなのでCSS Transitionsのカンマ区切り代表、transition-propertyプロパティの仕様書も読んでみます。

The transition-property property specifies the name of the CSS property to which the transition is applied.

Name: 'transition-property'Value: none | <single-transition-property>#

出典: 2.1. The transition-property Property - CSS Transitions Module Level 1

値(Value)の項目を見てみると、none<single-transition-property>#のどちらかを選ぶ必要があると書かれています[8]

<single-transition-property>は、「allキーワード」または「1つのCSSプロパティ」を表現していて[9]#が付いているので、カンマ区切りで複数書けることがわかります。

CSSのサンプルコード
.hoge {
  transition-property: all;
  transition-property: all, all, all;
  transition-property: opacity, visibility, transform;
}

なぜカンマ区切りなのか?

冒頭で、スペースだけだと困るときにカンマが登場すると説明しましたが、transition-propertyはスペース区切りだけでも問題なさそうなのにカンマ区切りが採用されています。どうしてカンマ区切りなのでしょうか?

あり得たかもしれないもう1つの仕様
.hoge {
  transition-property: opacity visibility transform;
}

これは構文上の必要性だけでは説明しきれない代表的なケースです。

Each of the transition properties accepts a comma-separated list, allowing multiple transitions to be defined, each acting on a different property. In this case, the individual transitions take their parameters from the same index in all the lists.

出典: 2. Transitions - CSS Transitions Module Level 1

transition-*の各プロパティは「複数のトランジションを定義するためにカンマ区切りリストを採用し、同じインデックス位置の値が互いに対応する」と定められています。

CSSのサンプルコード
.hoge {
  transition-property: color, background-color;
  transition-duration: 2s, 4s;
}

この例では color2sbackground-color4s という対応になります。つまり、次のルールセットと等価です。

CSSのサンプルコード
.hoge {
  transition:
    color 2s,
    background-color 4s;
}

インデックス対応だけならスペースでも良さそうですが、同仕様書にはこの設計の由来についての注釈が書かれています。

Note: This is analogous to the behavior of the 'background-*' properties, with 'background-image' analogous to 'transition-property'.

出典: 2. Transitions - CSS Transitions Module Level 1

background-image プロパティも同様にカンマ区切りで複数の値を受け取ります。こちらは複数の背景画像を重ねる(レイヤー化する)ために採用された構文[10]で、background-positionbackground-sizeなどの他のbackground-*プロパティも書かれた順で対応しています。

.hoge1 と .hoge2 は等価
.hoge1 {
  background-image: url(a.png), url(b.png);
  background-position:
    left top,
    center center;
  background-size:
    100px 200px,
    cover;
}

.hoge2 {
  background:
    url(a.png) left top / 100px 200px,
    url(b.png) center center / cover;
}

CSS Transitionsはこのbackground-*の設計パターンを踏襲したものであることから、同様にカンマ区切りが採用されました。2007年にWebKitがはじめてCSS Transitionsを実装した際のブログ記事にも、その意図が記されています。

Each of these properties supports a comma separated list of values, like CSS3 multiple backgrounds, which allows different transitions for individual properties to be described in a single style rule.

出典: CSS Animation - WebKit Blog (2007)

このように、その仕様が誕生した背景によっても何を区切り文字に使うのかが変わることがあります。

まとめ

  • CSSの区切り文字は構文上必要に応じて スペース → カンマ → スラッシュ の順に変化する

  • ただし、将来性や関連するプロパティの設計上カンマ区切りが採用されるケースもある

  • 迷った時は仕様書のValue行に#があるかを確認する

最終的には仕様の文法で決まりますが、そのCSSプロパティが何をしようとしているのかを設計の意図を含めて考えることで、覚えなくても自然に判断できるようになるかもしれません。

余談ですが、色を指定するためのrgb() 関数もrgb(0, 0, 0)のような書き方から、rgb(0 0 0)のようにスペース区切りに統一されました。カンマがなくても困らないときはスペースを採用するという、CSSの一般原則に沿った形になっています。

たまにはこうした根本的な仕様を眺めるのも楽しいですよね。

他のCSSプロパティがどうなっているか、スラッシュが登場するCSSプロパティはどのように説明されているか、将来登場する予定のCSSがどうなっているかなど、ぜひ眺めてみてください。

脚注