この内容は古いバージョンです。最新バージョンを表示するには、戻るボタンを押してください。
バージョン:6
ページ更新者:guest
更新日時:2026-06-11 07:12:00

タイトル: 子孫セレクタ
SEOタイトル: CSS 子孫セレクタ完全ガイド (div p / 子セレクタ > / 兄弟 + ~ との違い)

この記事の要点
  • 子孫セレクタはスペース区切り。div p は "div の中にある全ての p" (孫・ひ孫含む)
  • 子セレクタ div > p は直下の p のみ (孫は対象外)
  • 隣接兄弟 h2 + p は h2 直後の p、間接兄弟 h2 ~ p は h2 以降の全 p
  • * ユニバーサル は全要素マッチ。div * は div の中の全要素
  • 深すぎる入れ子 (.a .b .c .d .e) は specificity と保守性が悪化 → BEM 命名で平坦化

CSS 子孫セレクタとは

子孫セレクタ (Descendant Combinator) は、ある要素の中にネストされている要素を選ぶための CSS セレクタです。区切りは半角スペースのみ。直接の子・孫・ひ孫を問わず全ての子孫がマッチします。

/* div の中にある全ての p (孫・ひ孫含む) */
div p {
    color: red;
}

/* article 配下の見出しをまとめてスタイル */
article h1,
article h2,
article h3 {
    font-family: 'Noto Serif JP', serif;
}

/* 複数階層 OK: .wrapper の中の .content の中の a */
.wrapper .content a {
    text-decoration: underline;
}

子孫セレクタと他の結合子の違い

セレクタ意味マッチ例
div p子孫セレクタ (全階層)div 内の p (孫も対象)
div > p子セレクタ (直下のみ)div の直下の p だけ
h2 + p隣接兄弟セレクタh2 の直後の p 1つ
h2 ~ p間接兄弟セレクタh2 以降の同階層 p 全部
div, pグループ化div または p
div.note同一要素への複合class=note を持つ div

子孫セレクタ vs 子セレクタの動作比較

<div class="outer">
    <p>直下の p (A)</p>
    <section>
        <p>孫の p (B)</p>
    </section>
</div>
/* 子孫セレクタ: A も B もマッチ */
.outer p { color: red; }

/* 子セレクタ: A だけマッチ (B は孫なので除外) */
.outer > p { color: blue; }

隣接兄弟 + / 間接兄弟 ~ の使い分け

/* h2 直後の p だけ (リード文の強調などに) */
h2 + p {
    font-size: 1.1em;
    font-weight: bold;
}

/* h2 以降の同階層 p 全部 */
h2 ~ p {
    margin-left: 1em;
}

/* チェックボックスの状態でラベルを変える定番 */
input[type=&quot;checkbox&quot;]:checked + label {
    text-decoration: line-through;
    color: #888;
}

ユニバーサルセレクタ * との組み合わせ

/* div の中の全ての要素 (p, span, a, img ...) */
div * {
    box-sizing: border-box;
}

/* 直下の全要素 */
div > * {
    margin-top: 0;
}

/* リセット CSS の定番 */
*, *::before, *::after {
    box-sizing: border-box;
    margin: 0;
    padding: 0;
}

性能と specificity の話

ブラウザは CSS セレクタを右から左へ評価します。.menu li a は "a 要素を全部探す → 親に li → 祖先に .menu" という順序。深いネストは古いブラウザで遅くなる可能性がありますが、現代のブラウザでは実用上ほぼ問題になりません。

むしろ問題は specificity (詳細度) です:

セレクタ詳細度 (a, b, c)備考
p0, 0, 1要素のみ
.note0, 1, 0クラス 1つ
div p0, 0, 2要素 2つ
.menu li a0, 1, 2クラス + 要素 2つ
#main .item a1, 1, 1ID 含む → 強い
!importantすべてに勝つ (最終手段)

深すぎる入れ子のアンチパターン

/* ❌ NG: 詳細度が高すぎて上書き困難 */
body div#main .container .card .header h2 span.title {
    color: red;
}

/* ❌ NG: ネスト 5 段以上は保守性が悪い */
.sidebar .widget .list .item .link {
    color: blue;
}

/* ✅ OK: BEM 命名で平坦化 */
.card__title { color: red; }
.sidebar-link { color: blue; }

jQuery セレクタとの互換性

jQuery セレクタは基本的に CSS と同じですが、jQuery 独自拡張もあります:

// CSS と同じ
$('div p').css('color', 'red');
$('div > p').css('color', 'blue');
$('h2 + p').css('font-weight', 'bold');

// jQuery 独自拡張 (純 CSS では不可)
$('div:contains("Hello")');     // テキスト含むもの
$('input:checkbox:checked');    // チェック済
$('p:first');                   // 最初の p (CSS なら :first-of-type)
$('tr:eq(2)');                  // 3 番目 (0 始まり)

// 現代の JS では querySelectorAll で OK
document.querySelectorAll('div p').forEach(el => el.style.color = 'red');

BEM 命名規則と子孫セレクタの関係

BEM (Block Element Modifier) は子孫セレクタを使わずにクラス名だけで構造を表現する命名規則です。詳細度が低く保ち、コンポーネント単位の差し替えが容易になります。

<!-- BEM 例 -->
<article class="card card--featured">
    <h2 class="card__title">タイトル</h2>
    <p class="card__body">本文</p>
    <a class="card__link card__link--external">詳細</a>
</article>
/* 全部単一クラスで詳細度 (0,1,0) に揃う */
.card { padding: 1em; border: 1px solid #ddd; }
.card--featured { border-color: gold; }
.card__title { font-size: 1.5em; }
.card__body { color: #333; }
.card__link { color: blue; }
.card__link--external::after { content: &quot; ↗&quot;; }

ベストプラクティス

  • ネストは 3 段まで (それ以上はクラス名で平坦化)
  • ID セレクタは原則使わない (詳細度が暴走する)
  • !important は最終手段 (デバッグ困難になる)
  • 子孫セレクタを使うのは article 等の意味的なまとまりに対してのみ
  • UI コンポーネントは BEM / CSS Modules / Tailwind 等で平坦化

FAQ

Q: div pdiv, p の違いは?
A: スペースは子孫セレクタ (div の中の p)、カンマはグループ化 (div または p のどちらでも)。全くの別物です。

Q: 子孫セレクタは遅いと聞いた
A: 2010 年頃の話で、現代のブラウザではほぼ気にする必要なし。保守性 (詳細度・上書きやすさ) の方が重要です。

Q: Sass / SCSS のネストは子孫セレクタ?
A: Sass で .parent { .child { ... } } と書くと、コンパイル後は .parent .child (子孫セレクタ) になります。> .child なら子セレクタ。