Day 2: セレクタとカスケード
今日学ぶこと
- 結合セレクタと擬似クラス
- 詳細度(Specificity)の仕組み
- カスケードと優先順位
- 継承(Inheritance)
結合セレクタ
子孫セレクタ(スペース)
/* article内のすべてのp */
article p {
line-height: 1.8;
}
子セレクタ(>)
/* ulの直接の子のliだけ */
ul > li {
list-style: disc;
}
隣接兄弟セレクタ(+)
/* h2の直後のp */
h2 + p {
font-size: 1.2rem;
color: #64748b;
}
一般兄弟セレクタ(~)
/* h2の後のすべてのp */
h2 ~ p {
margin-left: 16px;
}
flowchart TB
subgraph Combinators["結合セレクタ"]
Desc["子孫<br>A B"]
Child["子<br>A > B"]
Adj["隣接兄弟<br>A + B"]
Gen["一般兄弟<br>A ~ B"]
end
style Desc fill:#3b82f6,color:#fff
style Child fill:#22c55e,color:#fff
style Adj fill:#f59e0b,color:#fff
style Gen fill:#8b5cf6,color:#fff
グループセレクタ(,)
h1, h2, h3 {
color: #1e293b;
}
属性セレクタ
/* href属性を持つa */
a[href] {
color: #3b82f6;
}
/* 外部リンク */
a[target="_blank"] {
text-decoration: underline;
}
/* httpsで始まるリンク */
a[href^="https"] {
color: #22c55e;
}
/* .pdfで終わるリンク */
a[href$=".pdf"] {
color: #ef4444;
}
/* "example"を含むリンク */
a[href*="example"] {
font-weight: bold;
}
| セレクタ | 意味 |
|---|---|
[attr] |
属性が存在する |
[attr="val"] |
値が一致 |
[attr^="val"] |
値が~で始まる |
[attr$="val"] |
値が~で終わる |
[attr*="val"] |
値が~を含む |
擬似クラス
リンク・インタラクション系
a:link { color: #3b82f6; } /* 未訪問 */
a:visited { color: #8b5cf6; } /* 訪問済み */
a:hover { color: #2563eb; } /* マウスオーバー */
a:active { color: #1d4ed8; } /* クリック中 */
a:focus { outline: 2px solid #3b82f6; } /* フォーカス */
順序: リンクの擬似クラスは LVHA(Link, Visited, Hover, Active)の順で書きましょう。
構造系
li:first-child { font-weight: bold; }
li:last-child { border-bottom: none; }
li:nth-child(2) { color: #3b82f6; }
li:nth-child(odd) { background: #f8fafc; }
li:nth-child(even) { background: #f1f5f9; }
li:nth-child(3n) { color: #ef4444; } /* 3の倍数 */
| 擬似クラス | 説明 |
|---|---|
:first-child |
最初の子要素 |
:last-child |
最後の子要素 |
:nth-child(n) |
n番目の子要素 |
:nth-child(odd/even) |
奇数/偶数番目 |
:not(selector) |
指定外の要素 |
:empty |
中身が空の要素 |
:focus-visible |
キーボードフォーカス |
:not() 擬似クラス
/* 最後の要素以外にborder-bottom */
li:not(:last-child) {
border-bottom: 1px solid #e2e8f0;
}
擬似要素
/* 最初の文字を大きく */
p::first-letter {
font-size: 2rem;
font-weight: bold;
}
/* 最初の行を太字に */
p::first-line {
font-weight: bold;
}
/* 要素の前に追加 */
.required::before {
content: "* ";
color: #ef4444;
}
/* 要素の後に追加 */
a[target="_blank"]::after {
content: " ↗";
}
| 擬似要素 | 説明 |
|---|---|
::before |
要素の前にコンテンツを挿入 |
::after |
要素の後にコンテンツを挿入 |
::first-letter |
最初の文字 |
::first-line |
最初の行 |
::placeholder |
プレースホルダーテキスト |
::selection |
選択したテキスト |
詳細度(Specificity)
CSSの核心的な概念です。複数のルールが同じ要素に適用される場合、詳細度が高いルールが優先されます。
詳細度の計算
flowchart LR
subgraph Specificity["詳細度の重み"]
Inline["インラインスタイル<br>1,0,0,0"]
ID["IDセレクタ<br>0,1,0,0"]
Class["クラス/擬似クラス<br>0,0,1,0"]
Elem["要素/擬似要素<br>0,0,0,1"]
end
Inline --> ID --> Class --> Elem
style Inline fill:#ef4444,color:#fff
style ID fill:#f59e0b,color:#fff
style Class fill:#22c55e,color:#fff
style Elem fill:#3b82f6,color:#fff
| セレクタ | 詳細度 | 計算 |
|---|---|---|
p |
0,0,0,1 | 要素 × 1 |
.highlight |
0,0,1,0 | クラス × 1 |
p.highlight |
0,0,1,1 | クラス × 1 + 要素 × 1 |
#main |
0,1,0,0 | ID × 1 |
#main .highlight p |
0,1,1,1 | ID + クラス + 要素 |
例
p { color: black; } /* 0,0,0,1 */
.text { color: blue; } /* 0,0,1,0 → 勝つ */
#intro { color: red; } /* 0,1,0,0 → さらに勝つ */
<p id="intro" class="text">このテキストは赤色です。</p>
!important:color: green !important;はすべての詳細度を上書きしますが、使用は最小限にしましょう。デバッグが困難になります。
カスケード
「カスケード(Cascade)」とは、複数のスタイルルールの優先順位を決定する仕組みです。
優先順位の決定順序
flowchart TB
A["1. 重要度<br>!important > 通常"] --> B["2. 詳細度<br>ID > クラス > 要素"]
B --> C["3. ソース順<br>後に書いたものが優先"]
style A fill:#ef4444,color:#fff
style B fill:#f59e0b,color:#fff
style C fill:#22c55e,color:#fff
/* ソース順: 後に書いたものが優先される(詳細度が同じ場合) */
p { color: blue; }
p { color: red; } /* ← こちらが適用される */
継承(Inheritance)
一部のCSSプロパティは、親要素から子要素に自動的に継承されます。
継承されるプロパティ
body {
font-family: sans-serif; /* ✅ 継承される */
color: #333; /* ✅ 継承される */
line-height: 1.6; /* ✅ 継承される */
}
継承されないプロパティ
.box {
border: 1px solid #ccc; /* ❌ 継承されない */
padding: 16px; /* ❌ 継承されない */
margin: 16px; /* ❌ 継承されない */
background: #f0f0f0; /* ❌ 継承されない */
}
| 継承される | 継承されない |
|---|---|
color |
margin |
font-family |
padding |
font-size |
border |
line-height |
background |
text-align |
width / height |
cursor |
display |
強制的に継承させる
.box {
border: inherit; /* 親のborderを継承 */
}
実践: カード型レイアウト
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>セレクタの実践</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<h1>ニュース一覧</h1>
<article class="card">
<h2>記事タイトル1</h2>
<p class="meta">2026年1月29日 | <span class="tag">CSS</span></p>
<p>記事の本文テキストが入ります...</p>
<a href="#" class="read-more">続きを読む</a>
</article>
<article class="card">
<h2>記事タイトル2</h2>
<p class="meta">2026年1月28日 | <span class="tag">HTML</span></p>
<p>記事の本文テキストが入ります...</p>
<a href="#" class="read-more">続きを読む</a>
</article>
</body>
</html>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: sans-serif;
line-height: 1.6;
color: #333;
max-width: 600px;
margin: 0 auto;
padding: 32px 16px;
}
h1 {
margin-bottom: 24px;
}
.card {
border: 1px solid #e2e8f0;
border-radius: 8px;
padding: 24px;
margin-bottom: 16px;
}
.card:hover {
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
}
.card h2 {
color: #1e293b;
margin-bottom: 8px;
}
.card .meta {
color: #94a3b8;
font-size: 0.875rem;
margin-bottom: 12px;
}
.tag {
background-color: #eff6ff;
color: #3b82f6;
padding: 2px 8px;
border-radius: 4px;
font-size: 0.75rem;
}
.read-more {
color: #3b82f6;
text-decoration: none;
font-weight: bold;
}
.read-more:hover {
text-decoration: underline;
}
.card:first-child {
border-left: 4px solid #3b82f6;
}
まとめ
| 概念 | 説明 |
|---|---|
| 結合セレクタ | 子孫、子、兄弟を指定 |
| 擬似クラス | :hover, :nth-child() など状態を指定 |
| 擬似要素 | ::before, ::after で要素を追加 |
| 詳細度 | セレクタの優先順位(ID > クラス > 要素) |
| カスケード | 重要度 → 詳細度 → ソース順 |
| 継承 | 親から子へプロパティが伝わる仕組み |
重要ポイント
- クラスセレクタを中心に使い、IDセレクタは避ける
- 詳細度は低く保つのがベストプラクティス
!importantは最後の手段- 継承されるプロパティとされないプロパティを把握する
練習問題
問題1: 基本
テーブルの偶数行と奇数行に異なる背景色をnth-childで設定してください。
問題2: 応用
ナビゲーションリンクに:hoverと:focus-visibleのスタイルを設定してください。現在のページのリンクには特別なクラスをつけましょう。
チャレンジ問題
5つのCSSルールの詳細度を計算し、適用される順番を予測してください。その後ブラウザで確認しましょう。
参考リンク
次回予告: Day 3では「ボックスモデル」について学びます。CSSレイアウトの基盤となる概念をマスターしましょう。