React の String Style CSS におけるセミコロン戦略


この記事は何か?

最近個人開発に力を入れており、CSS は String Style で記述しています。
3ヶ月ほど開発してきて知見が溜まってきたので、現時点での自分のベストプラクティスとして記事を書くことにしました。

といっても内容はしょうもないです。
「CSS の末尾のセミコロンは付けたほうが良いの?付けなくてもいいの?」という内容です。
タイトルに壮大そうな「戦略」という言葉を使っていますが、ようするに付けのるか付けないのかということです。

個人開発で実際に使用している CSS ライブラリは linaria です。
フロントエンドには React を採用しており、爆速動作を謳う linaria が面白そうなので導入しました。

セミコロンは付けよう

結論として、セミコロンは付けましょう。

以上です。
本記事は役目を終えました。

結論だけ言われても困ると思うので、ここから先で補足を説明していきます。

そもそも String Style CSS とは?

文字列で CSS を記述する形式のことです。
実際は正式名称を知らないので、もしご存知の方がいれば教えていただきたいです 🙏

String Style という言葉は Emotion のドキュメントから拾ってきました。
The css Prop - String Styles

CSS スタイルの記述の仕方

String Style では、以下のような形で CSS を記述することができます。

const positioin = css`
  position: absolute;
  top: 200px;
  left: 300px;
`

CSS-in-JS で有名な Emotion や 今回導入した linaria では、 css プロップスに値を渡すことにより CSS を適用できます。

const MyComponent: VFC<Props> = (props) => {
  return <div css={position}>hello</div>
}

Emotion では直接書くほうが一般的かも知れませんね。

const MyComponent: VFC<Props> = (props) => {
  return (
    <div 
      css={css`
        position: absolute;
        top: 200px;
        left: 200px;
      `}
    >
      hello
    </div>
  )
}

linaria の stlye タグ

余談ですが、linaria では css タグも利用できるのですが、 styled タグを使用する方がより一般的です。
styled を利用すると、 CSS 適用済みのタグを生成するような感覚でスタイルを適用できます。

linaria - The styled tag

const MyComponent: VFC<Props> = (props) => {
  return (
    <Position>
      <p>hello</p>
    </Position>
  )
}

const Position = styled.div`
  position: absolute;
  top: 200px;
  left: 300px;
`

なぜセミコロンを付けたほうが良いのか?

自分は省略できるものは省略したい派です。
もちろん可読性などの場合によりますが、それでもフォーマットとしては省略したほうが見やすいと感じます。

以下のように、個人開発でもしばらくはセミコロンを省略して書いていました。

const position = css`
  position: absolute
  top: 200px
  left: 300px
`

ではなぜ省略しないほうが良いのか?
それは 2つ のケースにおいて、セミコロンを付与しないとコードフォーマット時に期待しない挙動となるためです。

①コメントが書けない

セミコロンを付けないと、 CSS の中にコメントを記述する事ができません

具体的には、以下のコードではエラーが発生します。

const position = css`
  position: absolute
  /* コメント */
  top: 200px
  left: 300px
`
Compiled with problems:

...

Module build failed (from ./node_modules/postcss-loader/dist/cjs.js):
SyntaxError

(194:6) /path/to/MyComponent.tsx Missed semicolon

セミコロンがないよと言われていますね。
おそらく改行周りの解釈が上手く行かないのだと思います。

セミコロンがなくてもコメントを書けるパターン

この章は余談です。
実はセミコロンがなくてもコメントを書けるパターンが 2つ あります。

  1. css タグの 1行目 に記述
  2. 属性の末尾に記述

1 は以下のようなパターンです。

const position = css`
  /* コメント */
  position: absolute
  top: 200px
  left: 300px
`

2 は以下のようなパターンです。

const position = css`
  position: absolute
  top: 200px /* コメント */
  left: 300px

なぜ改行後のコメントが解釈されないのか?

ではなぜ改行後のコメントが解釈されないのでしょうか?
何らかの理由により仕様で禁止しているのでしょうが、正直理由がわかりません。

CSS の値を改行しても記述可能であるという点はヒントな気がします。
以下の文字列は有効です。

const position = css`
  position:
   absolute
  top: 200px
  left: 300px

ですがコメントのリテラル /* */ が出現した時点でスルーすれば良いので、改行が決定打となる理由が思いつきません。

### ② CSS のアットマークルールをフォーマットしてしまう

2個目は、セミコロンなしで記述すると CSS の アットマークルール をフォーマットしてしまう点です。

例えば次の animation を書いたとします。

const open = css`
  animation: 0.3s ease-in open

  @keyframes open {
    from {
      height: 0px
    }

    to {
      height: 100px
    }
  }
`

この CSS をフォーマットすると以下のようになります。

const open = css`
  animation: 0.3s ease-in open @keyframes open {
    from {
      height: 0px
    }

    to {
      height: 100px
    }
  }
`

なぜ、、、
ここでも上手く改行を解釈してくれません。

animation 行の末尾にセミコロンを付与すれば意図せぬフォーマットは防げます。

以上がセミコロン付けない戦略を採用した場合のデメリットです。
これらを回避するには都度セミコロンを付与する必要があるのですが、それだったら全部に付けて統一感をもたせたほうがメリットが大きいと感じました。

終わりに

割とどうでも良い内容を長々と書いてしまいましたが、そういうのもたまには好きです。
どなたかのお役に立てたら幸いです。