CSSのカンマ区切りとスペース区切りの違い
公開日:
- #CSS
- #Web標準
- #Tips
CSSプロパティの値(Value)の内容を区切るとき、カンマとスペースどちらが正しいか悩む!という方のためのメモ書き。
覚えるのが大変!という方には残念なお知らせですが、厳密には仕様を確認するしかありません。とはいえ、理屈を知ることで、なんとなく想像で判断できるようになるかもしれないです。
TailWindCSSで任意の値(arbitrary values)を指定する際にも役立ちます。
// NG
<div className="transition-[opacity_visibility]" />
// OK
<div className="transition-[opacity,visibility]" />// NG
<div className="grid-cols-[30%,70%]" />
// OK
<div className="grid-cols-[30%_70%]" />というわけで今回は、CSSの区切り文字がどのように決められているのかを、仕様書の読み方と合わせてご紹介しようと思います。
結論:スペース → カンマ → スラッシュ
CSSの区切り文字にどれを採用するかは、次のような優先順位で決められています。
スペースだけで解決できる → スペース
スペースだけだと境界が分からなくなる → カンマ
さらに区切り文字が必要 → スラッシュ
たとえばtransitionプロパティも、この優先順位で区切り文字が定義されています。通常はスペース区切りですが、複数トークン[1]からなる塊が繰り返される場合にカンマが登場します。
.hoge {
transition: color 1s ease-out 0.3s;
}.hoge {
transition:
color 0.3s,
background-color 0.3s ease-out;
}仕様書を読んでみる
まずはCSS Transitions Module Level1を例に、仕様書ではどのように定義されているかを確認してみましょう。
.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> =
[ none | <single-transition-property> ]
|| <time>
|| <easing-function>
|| <time>上記の||(二重線)は選択肢の中から「任意の順序で必ず1つ以上指定する必要がある」という意味です[4]。
ここでは#記号が使われていませんが、区切り記号が明示されていない場合はスペース区切りを意味します[5]。
つまり、スペース区切りで1つ〜4つのトークンを並べられるのが<single-transition>。それをカンマ区切りで複数記述できるのが、transitionプロパティだということが読み解けます。
区切り文字が分からなくなった際は、このようにして仕様書を読み解いていきましょう。
もう少し深掘り:transition-property
.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]、#が付いているので、カンマ区切りで複数書けることがわかります。
.hoge {
transition-property: all;
transition-property: all, all, all;
transition-property: opacity, visibility, transform;
}なぜカンマ区切りなのか?
冒頭で、スペースだけだと困るときにカンマが登場すると説明しましたが、transition-propertyはスペース区切りだけでも問題なさそうなのにカンマ区切りが採用されています。どうしてカンマ区切りなのでしょうか?
.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.
transition-*の各プロパティは「複数のトランジションを定義するためにカンマ区切りリストを採用し、同じインデックス位置の値が互いに対応する」と定められています。
.hoge {
transition-property: color, background-color;
transition-duration: 2s, 4s;
}この例では color → 2s、background-color → 4s という対応になります。つまり、次のルールセットと等価です。
.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'.
background-image プロパティも同様にカンマ区切りで複数の値を受け取ります。こちらは複数の背景画像を重ねる(レイヤー化する)ために採用された構文[10]で、background-positionやbackground-sizeなどの他のbackground-*プロパティも書かれた順で対応しています。
.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の区切り文字は構文上必要に応じて スペース → カンマ → スラッシュ の順に変化する
ただし、将来性や関連するプロパティの設計上カンマ区切りが採用されるケースもある
迷った時は仕様書のValue行に
#があるかを確認する
最終的には仕様の文法で決まりますが、そのCSSプロパティが何をしようとしているのかを設計の意図を含めて考えることで、覚えなくても自然に判断できるようになるかもしれません。
余談ですが、色を指定するためのrgb() 関数もrgb(0, 0, 0)のような書き方から、rgb(0 0 0)のようにスペース区切りに統一されました。カンマがなくても困らないときはスペースを採用するという、CSSの一般原則に沿った形になっています。
たまにはこうした根本的な仕様を眺めるのも楽しいですよね。
他のCSSプロパティがどうなっているか、スラッシュが登場するCSSプロパティはどのように説明されているか、将来登場する予定のCSSがどうなっているかなど、ぜひ眺めてみてください。
脚注
- [^1]:トークンとは、CSSパーサがパースする文字列の最小単位のこと。4. Tokenization - CSS Syntax Module Level 3
- [^2]:
#の後に{1,4}のように数字が書かれている場合は繰り返し回数が制限されていることを表す。参考:2.3. Component Value Multipliers - CSS Values and Units Module Level 4 - [^3]:
<single-transition>のように、山括弧で囲まれたものを仕様上は「非終端記号(non-terminal)」と呼ぶ。その非終端記号から始まる定義文を「プロダクション(production)」と呼ぶ。知らなかった。参考:CSS Values and Units Module Level 4 - [^4]:参考:CSS Values and Units Module Level 4
- [^5]:この暗黙のスペース区切りを「並置(juxtaposition)」と呼ぶ。知らなかった。参考:2.2. Component Value Combinators - CSS Values and Units Module Level 4
- [^6]:
|は選択肢のうち、1つだけを選ばなければならない。参考:2.2. Component Value Combinators - CSS Values and Units Module Level 4 - [^7]:
<time>は先に登場した方がtransition-durationプロパティの値として扱われる。 - [^8]:
|は選択肢のうち、1つだけを選ばなければならない。参考:2.2. Component Value Combinators - CSS Values and Units Module Level 4 - [^9]:正確には
all | <custom-ident>。<custom-ident>は一部の予約語を除いた任意の値を指す(hogeとかでも良い)。<single-transition-property>においてはnone、inheritおよびinitialも除外したCSSプロパティ名のこと。参考:Single transition property - CSS Transitions Module Level 1 - [^10]:参考:2.1 Layering Multiple Background Images - CSS Backgrounds and Borders Module Level 3