🙀

cssの頭に付いている「.」や「#」の処理方法について調べてみた。

2025/02/01に公開

色々調べた結果、「.」や「#」があることで
処理高速化の工夫がなされている
というのがよくわかりました。

そもそもcssの頭に付いている「.」は何?

HTMLの要素に付与されたclass属性を指定するため記号で、
クラスセレクタと呼ばれるものです。

使用方法

.クラス名 {
  プロパティ:;
}

/* 青色のテキスト */
.blue-text {
  color: blue;
}

/* 複数のクラスを組み合わせる */
.large.bold {
  font-size: 20px;
  font-weight: bold;
}

HTML側での使用

<p class="blue-text">青い文字</p>
<div class="large bold">大きな太字</div>

特徴

  • ドット(.)で始まる
  • 複数の要素で再利用可能
  • 1つの要素に複数のクラスを適用可能
  • IDセレクタ(#)より詳細度が低い

その他のセレクタ

  1. 要素セレクタ: div { }
  2. IDセレクタ: #header { }
  3. 属性セレクタ: [type="text"] { }
  4. 擬似クラス: a:hover { }
  5. 擬似要素: p::before { }

使用例

<div id="header">ヘッダー</div>
<p class="text">段落</p>
<input type="text" name="username">
<a href="#">リンク</a>
/* 要素セレクタ */
div {
  background: gray;
}

/* IDセレクタ */
#header {
  font-size: 24px;
}

/* クラスセレクタ */
.text {
  color: blue;
}

/* 属性セレクタ */
[type="text"] {
  border: 1px solid black;
}

/* 擬似クラス */
a:hover {
  color: red;
}

/* 擬似要素 */
p::before {
  content: "▶";
}

クラスセレクタ(.)は一般的に使用される方法の一つですが、これらの他の方法と組み合わせることで、より細かいスタイル制御が可能です。

実際のソースを見てみた

実際のWebブラウザにも使われている
CSS処理用のエンジンWebKitのソースを見てみました。

WebKitをGitHubからクローン

  1. Ctrl+Shift+P を押してコマンドパレットを開く
  2. "Git: Clone" と入力し、出てきた「Git:クローン」を選択
  3. リポジトリURLを入力: https://github.com/WebKit/WebKit
  4. クローン先のローカルフォルダ選択画面が出るので、好きな場所を選択する
  1. 「複製したリポジトリを開きますか?または現在のワークスペースに追加しますか?」と表示されるので、「開く」を選択

「.」のパース処理を探す

GitHub Copilotの助けを借りながら探しました。
以下のようなJavaScriptで処理をしているようです。

JavaScript
var matchExpr = {
  "ID": new RegExp( "^#(" + identifier + ")" ),
  "CLASS": new RegExp( "^\\.(" + identifier + ")" ), // ここでクラスセレクタのドットを検索しています
  "TAG": new RegExp( "^(" + identifier + "|[*])" ),
  "ATTR": new RegExp( "^" + attributes ),
  "PSEUDO": new RegExp( "^" + pseudos ),
  "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace +
    "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace +
    "*(\\d+)|))" + whitespace + "*\\)|)", "i" ),
  "bool": new RegExp( "^(?:" + booleans + ")$", "i" ),
  "needsContext": new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" +
    whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" )
};

処理の概要

  1. IDCLASS - 最も一般的で高速なセレクタが先頭に来ています

    • ID: #my-id のような ID セレクタ
    • CLASS: .my-class のようなクラスセレクタ
  2. NAME, TAG - 次によく使われる基本的なセレクタ

    • NAME: [name='value'] のような name 属性セレクタ
    • TAG: divspan のようなタグセレクタ
  3. より複雑なセレクタ

    • ATTR: 一般的な属性セレクタ
    • PSEUDO: :hover などの擬似クラス
    • POS: 位置関連のセレクタ
    • CHILD: :first-child などの子要素セレクタ
  4. 特殊用途

    • needsContext: .is() メソッド実装用の特殊パターン

この順序の2つの主な理由

  1. パフォーマンス最適化:

    • より単純で高速なセレクタ(ID、クラス)を先に配置
    • より複雑で処理の重いセレクタを後ろに配置
  2. 依存関係の管理:

    • より基本的なパターンを先に定義し、それらを基にして複雑なパターンを構築

この構造により、セレクタのマッチング処理を効率的に行うことができます。

おしまいに

ドットのことを調べすぎて
どっと疲れたワニかず@40歳 出戻りエンジニアでした。

Discussion