pure selectors must contain at least one local class or id

経緯

css modules ファイル内に、html セレクタを直接記述したらエラーに遭遇したので、原因と解説、解決方法を簡単にまとめました。

やったこと

css modules ファイル内で、<h1> タグ内の文字色を 黄色 にするクラス指定を追記。

import styles from '../styles/xxx.module.scss'

export default function Home() {
  return (
    <div className={styles.container}>
      <h1>Welcome to My app!</h1>  // ここの色を黄色に変えたい
    </div>
  )
}
.container {
  padding: 0 2rem;
}

// ↓↓ 以下を追記 ↓↓
h1 {
  color: yellow;
}

エラー内容

./styles/xxx.module.css:131:1
Syntax error: Selector "h1" is not pure (pure selectors must contain at least one local class or id)
シンタックスエラー。
セレクタ "h1" は pure ではありません( pure なセレクタは、少なくとも1つのローカルクラスまたは ID を含む必要があります)。

解説

上記でいう pure とは、自前で用意する .top-page-title#top-page などの classセレクタ や idセレクタ を表しています。

反対に html, body, button, h1 などは impure なセレクタになります。

原因

つまりエラーの原因は xxx.module.scss という css modules ファイル内に、 impure なセレクタを記述していること。

ルールとして、css modules ファイルでは impure なセレクタは使用できません。

解決方法1

css modules ファイルに pure な classセレクタ(id でも可)を用意し、 import したうえでその style を適用してあげる。

これが基本的な使い方になります。

.container {
  padding: 0 2rem;
}

// クラスセレクタを用意
.title {
  color: yellow;
}
import styles from '../styles/xxx.module.scss' // import

export default function Home() {
  return (
    <div className={styles.container}>
      // styles.title で適用
      <h1 className="{styles.title}">Welcome to My app!</h1>
    </div>
  )
}

解決方法2

(ネストができる Sass であれば) pure なセレクタ内に記述する。

実は、pure なセレクタの下であれば、 h1等を記述することができます。

.container {
  padding: 0 2rem;

  // .container の中に h1 を記述
  h1 {
    color: yellow
  }
}

コンパイル後の css

css modules の場合、コンパイルされた css は基本的にセレクタの後に hashのような値が付与されます。(下画像の__ngV3cの部分)

css modules ファイル名の頭部分 + _pureセレクタ名 + __hashのような値

しかし、classセレクタ、idセレクタでない h1 や p などは、 hashのような値が付与されないようになっています。

まとめ

いかがでしたでしょうか。

css modules は css のグローバルスコープ汚染問題を回避するための一つの仕組みです。

つまり、 css modules ファイル内には、基本的に特定の対象にのみクラスを当てるような記述(つまりクラスセレクタ等を用意)をすべきで、グローバルに適用したいスタイルを css modules 内に記述すべきではないんですね。

グローバルに適用したいものはグローバルなファイルを用意して、グローバルな場所で import するようにしましょう。