ひびのログ

日々ではないけどログを出力していくブログ

CSS ではショートハンドの使用には注意しなければいけないという話

複数のプロパティをまとめて指定できるショートハンド。 自分も気軽に利用していたが、詳しく調べてみると気をつけなければいけない仕様が結構あり、なるべく使わないほうがいいのではないかと感じた。

対象

あらゆるショートハンドプロパティ。

all, animation, background, border, border-block-end, border-block-start, border-bottom, border-color, border-image, border-inline-end, border-inline-start, border-left, border-radius, border-right, border-style, border-top, border-width, column-rule, columns, flex, flex-flow, font, gap, grid, grid-area, grid-column, grid-row, grid-template, list-style, margin, mask, offset, outline, overflow, padding, place-content, place-items, place-self, scroll-margin, scroll-padding, text-decoration, text-emphasis, transition

MDN に一覧が載っている。 https://developer.mozilla.org/ja/docs/Web/CSS/Shorthand_properties

なぜショートハンドを使わないほうがいいのか

  • 意図して指定されたものなのかわからなくなる
  • 気付かず値を上書きしてしまう可能性がある
  • 読みづらい(個人の感想)

意図して指定されたものなのかわからなくなる

margin や padding では基本的に 4 値指定するが、省略した場合は他の場所の値が設定されることになる。 一番わかりづらいものとして、左(四番目)を省略すると右(二番目)の値が設定されるという仕様がある。

そもそも初心者殺しであるし、慣れた人でも「4 値を設定しようとして 1 つ抜けていた」といった間違いが起きないとも限らない。

名前とメールアドレスを並べて表示するとき。 両方とも、左マージンは 0.5rem、右マージンは 2rem を指定することにする。

すると以下のようなコードになる。

<div>
  <span class="name">名前</section>
  <span class="email">メールアドレス</section>
</div>
.name {
  margin: 1rem 2rem 1rem 0.5rem;
}

.email {
  margin: 1rem 2rem 1rem 0.5rem;
}

ただし、一部を書き換えて以下のようにしても見た目は変わらない。 これは、名前とメールアドレスの間のマージンは、名前の右マージンの 2rem が使用されるから。

.email {
  margin: 1rem 2rem;
}
// もしくは
.email {
  margin: 1rem 2rem 1rem;
}

ここで問題となるのは、本来であれば設定されるべき「左マージン 0.5rem」がなくても動いてしまうことだ。 メールアドレスの要素の仕様とは違うコードが書かれているのに、それを動作確認で見つけるのは至難の業。

そして時間が経って、「左右マージン 2rem」という仕様であると誤解されたまま修正が入り、当初の意図とは違うスタイルになっていく。

気付かず値を上書きしてしまう可能性がある

MDN の例を見るのが早い。

指定されなかった値は初期値に設定されます。つまり、以前設定した値を上書きすることになります。例を見てください。

p {
  background-color: red;
  background: url(images/bg.gif) no-repeat left top;
}
この場合、背景の色は red ではなく、 background-color の既定値である transparent に設定されます。

(https://developer.mozilla.org/ja/docs/Web/CSS/Shorthand_properties#プロパティの省略 より)

「現実にこんなコード書くわけないだろ」と思う人もいるかもしれないが、むしろそういうもののほうが起こりうる。 間に複数のプロパティが挟まっていることもあるし、カスケードした値が使われることもあることを考えると、むしろ起こりやすい部類に入る。

読みづらい(個人の感想)

特に 3 値の margin・padding が圧倒的に読みづらい。 2 値目に左右の指定が来るのが理解に苦しむ。

そして font のショートハンドはこの調査のときに初めて見たが読めなかった。 CSS 何もわからない。

font: italic bold .8em/1.2 Arial, sans-serif;

参考文献の意見

ここで、別の記事ではどういったことが書かれているのか調べてみた。

CSSのショートハンドは常に使用すべきか

https://foolish-pine.com/posts/2021/06/css-shorthand

こちらのサイトでは、「可読性や保守性を重視するならばショートハンドはなるべく使用しない」と結論付けている。

簡単にまとめると、理由として以下が挙げられている。

  1. ショートハンドは以前設定した値を上書きする
  2. 可読性の悪さ
  3. 保守性の低下

CSS ショートハンド・プロパティの問題点

https://terkel.jp/archives/2012/06/problem-with-css-shorthand-propaties/

こちらのサイトでは、「その都度必要なプロパティだけを宣言するよう心掛けるのが良いのではないでしょうか」と記述されている。 理由が以下のように書かれている。

ひょっとするとこのコードを書いた人は、明示されているプロパティのみを宣言したかったのであり、プロパティの省略とそれに伴う暗黙の初期化については意図していなかったのかもしれません。しかしコードを読む人にとってはそこに記述されているコードがすべてなので、それはすべて意図的なものと捉えるしかありません。(中略)こうしてコードに対する認識の食い違いが生まれ、本来は必要のないスタイルが定義され、そして最悪の場合にはバグを生むことになります。

本当にすべてのショートハンドを禁止するべきなのか

ここまでショートハンドは NG という論調だったが、では本当にすべてを禁止するべきかと言われるとそうではない。

使っていいショートハンドはありそうか考えてみる。

個別検討

  • grid-row&-start, &-end の一括指定ができるが、一気に指定したほうがむしろわかりやすいのでは
    • border-radius なども同様
  • border などの、順番が重要ではないプロパティはさほど問題が起きないように思える
    • 省略された部分が初期値で上書きされてしまう問題がある
    • 特にネックなのはこれ(MDN の border より) border は border-image のカスタム値を指定することができず、初期値、つまり none に設定します。
  • animation のように、スペルが長い・まとめられている要素数が多い場合、一括指定を使わないことで可読性が下がりそう
    • バグが発生するよりはマシだと思う
    • とはいえ、border は一括指定の一括指定なので、全て展開すると大変すぎる

ここまでの感想

すべて禁止はやりすぎだと感じた。 特にborder は頻出な上に記述量がめちゃめちゃ増えるのでよろしくなさそう。

ではどうすべきか

stylelint を活用する。

使ってはいけないプロパティがあったらエラー。 使っていいプロパティも、事前に定義した使い方をしていないならエラー。

既存のルールには存在しないみたいなので、新しく Lint ルールを作成する必要がある。 また、チームによって使用してもいいプロパティやその設定値が変わってくるので、カスタマイズできる必要がありそう。

自分の結論

  • ショートハンドは基本的には使用しない
  • 一切使用しないのは逆に大変なので、ルールを決めて運用する
    • ルールはチームによって異なる
    • stylelint を使用して強制する
  • スタイルが若干崩れても問題にならないなら、よしなに運用すればいい
    • 今回はかなり厳格な視点で見た

懸念点

  • stylelint のルールを作る必要がある
    • 誰か似たようなことを考えている人はいないものか
    • 言い出しっぺの法則で作るのはあり
  • CSS プロパティが追加されたときのメンテナンスが面倒

余談

Tailwind CSS のように、CSS を隠蔽してこのような複雑性を吸収してしまうやり方もある。 個人で開発するときはもっぱらこちらを採用している。

おまけ:巷の意見と感想

自分の主観が多く入っているので、css ショートハンド で検索して上から見ていった。

結果、「短ければいい」「かっこいい」という意見がほとんどだった。 正直あまり参考にならなかったので省略。 気になったらググってみるといいと思う。