CSS でクラス指定の無い要素にのみスタイルを適用する方法

CSS の小ネタです。 CSS で class 属性での指定が無い要素にのみスタイルを付ける方法についてです。

この方法はハックでも何でも無いのですが、個人的には目からウロコでした。 これを使うと、規模が大きめのサイトの CSS で起こりがちな「スタイルリセット地獄」を回避でき、 CSS のメンテナンス性を高めることができます。

クラス指定の無い要素にのみスタイルを適用する方法

やり方

CSS でクラス指定の無い要素にのみスタイルを適用したい場合は、セレクタに :not([class]) を使えば OK です。

ul:not([class]) {
  /* スタイル */
}

メリット

この方法のメリットを、サンプルを使いながら説明してみます( CSS だと冗長なので、コードには SCSS を使用します)。

例として、リスト要素に次のようなスタイルを適用したい場合を考えましょう。

  • デフォルトのスタイル: 先頭のマークが赤色のドット。左マージンは小さめ。
  • item-list というクラスの付いたスタイル: 先頭のマークが四角。

イメージは次のとおりです。

リストスタイル完成形のイメージ

スタイル確認用の HTML には次のものを使いましょう。

<p>クラス無しのリスト:</p>
<ul>
  <li>葛</li>
  <li>根</li>
  <li>湯</li>
</ul>

<p>クラス付きのリスト:</p>
<ul class="item-list">
  <li>小</li>
  <li>青</li>
  <li>竜</li>
  <li>湯</li>
</ul>

これを not([class]) を使わずに書こうとすると、例えば次のようになります。

ul {
  padding-left: 24px;

  li {
    position: relative;
    list-style-type: none;

    &:before {
      position: absolute;
      left: -1em;
      display: inline-block;
      content: "\00B7";
      color: red;
    }
  }
}

.item-list {
  // padding-left をリセット( Chrome のデフォルトの値を再現)
  -webkit-padding-start: 40px;

  li {
    // position をリセット
    position: initial;
    list-style-type: square;

    &:before {
      // before をリセット
      content: initial;
    }
  }
}

.item-list のスタイルに必要なのは本来 list-style-type の指定だけなのですが、ベーススタイルが影響してしまう関係で、それをリセットするためのスタイル指定を何行も書く必要があります。

not([class]) を使えば、この問題は回避することができます。 上のコードと同じことを実現する not([class]) を使ったパターンを見てみましょう。

ul:not([class]) {
  padding-left: 24px;

  li {
    position: relative;
    list-style-type: none;

    &:before {
      position: absolute;
      left: -1em;
      display: inline-block;
      content: "\00B7";
      color: red;
    }
  }
}

.item-list {
  li {
    list-style-type: square;
  }
}

item-list の中で余計なリセットを行う必要がなくなり、ぐっとシンプルになりました。

このサンプルは比較的シンプルなのでこの違いは一見ささいなものに思えますが、例えば、 item-list と同様の menu-list link-list といったさまざまな異なるタイプのリストが出てきた場合等に大きな効果を発揮します。

以上です。

余談です。 ちなみに、この :not([class]) セレクタは jQuery でも利用することができます。

// class でスタイル指定されていないリストのみを取得
const bareLists = jQuery('ul:not([class]) li');

// もちろん not() メソッドを使って次のようにも書くこともできます
const bareLists = jQuery('ul').not('[class]').find('li');