0Support

Logical and relational selectors

Combine conditions with OR, AND, and functional pseudo-classes; compare their matches and inspect how specificity changes.

Guide

Ask AI

Logical and relational selectors

Response generated with openai/gpt-5.4-nano. AI can make mistakes. Always review the result.
Current selectorarticle, .notice
Support unknownSpecificity

Preparing the scenario and its results…

Selects elements matching either of the two comma-separated branches.

Selector preview

The collection is updated with new examples.

HTML
<section class="catalog" aria-label="Catalog for logical and relational selectors">
  <article class="card featured">
    <span class="badge">New</span>
    <h3>Main selector guide</h3>
    <p>Featured and available</p>
  </article>
  <aside class="card archived">
    <h3>Archived reference</h3>
    <p>Kept for reference</p>
  </aside>
  <article class="card featured">
    <span class="media">Video</span>
    <span class="locked">Restricted</span>
    <h3>Advanced course</h3>
    <p>Restricted content</p>
  </article>
  <p class="notice">The collection is updated with new examples.</p>
</section>
CSS
article, .notice {
  outline: 3px solid #f97316;
  outline-offset: 3px;
  background-color: color-mix(in oklch, #f97316 16%, transparent);
}

CSS logic and relationships guide

Combine conditions without losing sight of the subject

Distinguish OR, AND, and exclusion, compare the special specificity of functional pseudo-classes, and learn to read relative selectors.

Back to playground

Four ideas before combining selectors

The same conditions can change meaning and weight depending on where commas appear and which pseudo-class contains them.

A, B

A comma expresses OR

A list matches when at least one branch matches. Each complex selector keeps its own specificity tuple.

A.class

A compound expresses AND

Simple selectors written without a combinator must match the same element and add their contributions.

:is() · :where()

Same matches, different weight

:is() takes the most specific argument; :where() and all of its arguments contribute zero.

E:has(relative)

The subject remains outside :has()

E is the selected element. Relative arguments are evaluated with E as their anchor and may start with a combinator.

Composition with OR and AND

Compare the union of independent branches with multiple conditions required on a single element.

Selector list

A, B

Selects an element when it matches at least one branch in the comma-separated list.

Specificity(0, 0, 1) · (0, 1, 0)
Important behavior
  • Branches are independent complex selectors and may select different element types.
  • Specificity is calculated per branch; there is no single tuple representing the whole list in the abstract.
Selector and HTML examples
SelectorSpecificity(0, 0, 1) · (0, 1, 0)
article, .notice
HTML
<section>
Matches:   <article>Matches</article>
  <div>Does not match</div>
Matches:   <p class="notice">Matches</p>
</section>
SelectorSpecificity(0, 0, 1) · (0, 1, 0)
button, [role="status"]
HTML
<div>
Matches:   <button>Matches</button>
  <a href="#docs">Does not match</a>
Matches:   <output role="status">Matches</output>
</div>
Common conceptual mistakes
  • An invalid branch in a normal selector list invalidates the entire list and its CSS rule.
  • A comma does not require an element to satisfy both branches; that would be AND composition.
Read the full definitionOpens in a new tab

Compound selector

A.class[attr]

Selects one element that simultaneously satisfies every simple selector written without a combinator.

Specificity(0, 2, 1)
Important behavior
  • Every class, attribute, type, or pseudo-class adds its own condition to the compound.
  • Specificity adds every contribution, even when several conditions are the same kind.
Selector and HTML examples
SelectorSpecificity(0, 2, 0)
.card.featured
HTML
<section>
Matches:   <article class="card featured">Matches</article>
  <article class="card">Does not match</article>
  <div class="featured">Does not match</div>
</section>
SelectorSpecificity(0, 2, 1)
button.primary[aria-pressed="true"]
HTML
<div>
Matches:   <button class="primary" aria-pressed="true">Matches</button>
  <button class="primary" aria-pressed="false">Does not match</button>
  <a class="primary" aria-pressed="true">Does not match</a>
</div>
Common conceptual mistakes
  • Adding a space stops expressing AND on the same element and creates a descendant relationship.
  • A comma would change the intersection into a union of independent branches.
Read the full definitionOpens in a new tab

Logical combination pseudo-classes

:is(), :where(), and :not() accept lists, but they do not share the same meaning or specificity.

:is()

:is(A, B)

Matches when the element satisfies at least one selector in its argument list.

Specificity(0, 1, 0)
Important behavior
  • It uses a forgiving list: invalid arguments are discarded as long as one valid argument remains.
  • Its specificity is replaced by that of the most specific argument, whether or not that branch matches the particular element.
Selector and HTML examples
SelectorSpecificity(0, 1, 1)
:is(article, aside).featured
HTML
<section>
Matches:   <article class="featured">Matches</article>
Matches:   <aside class="featured">Matches</aside>
  <section class="featured">Does not match</section>
</section>
SelectorSpecificity(0, 1, 1)
.toolbar :is(a, button)
HTML
<nav class="toolbar">
Matches:   <a href="#guide">Matches</a>
  <span>Does not match</span>
Matches:   <button>Matches</button>
</nav>
Common conceptual mistakes
  • It does not simply add one pseudo-class unit; it may inherit even an ID argument’s weight.
  • Pseudo-elements are not valid arguments inside :is().
Relevant support

This Baseline status covers :is(), including its forgiving list. The current browser is checked separately in the playground.

Read the full definitionOpens in a new tab

:where()

:where(A, B)

Matches the same elements as :is() for the same argument list.

Specificity(0, 0, 0)
Important behavior
  • :where() and every argument inside it always contribute a specificity of (0, 0, 0).
  • It is useful for context or defaults that should remain easy to override.
Selector and HTML examples
SelectorSpecificity(0, 1, 0)
:where(article, aside).featured
HTML
<section>
Matches:   <article class="featured">Matches</article>
Matches:   <aside class="featured">Matches</aside>
  <section class="featured">Does not match</section>
</section>
SelectorSpecificity(0, 1, 0)
.content :where(p, blockquote)
HTML
<article class="content">
Matches:   <p>Matches</p>
Matches:   <blockquote>Matches</blockquote>
  <aside>Does not match</aside>
</article>
Common conceptual mistakes
  • Zero specificity does not mean the rule always loses: the cascade also considers origin, layers, importance, and order.
  • Only :where() has its weight removed; selectors written outside it still count.
Relevant support

This Baseline status covers :where() and its zero-specificity behavior.

Read the full definitionOpens in a new tab

:not()

:not(A, B)

Selects the subject when it matches none of the selectors in the argument.

Specificity(0, 1, 0)
Important behavior
  • Selectors Level 4 permits a complex selector list and nested combinations such as :not(:has(...)).
  • Its specificity is that of the most specific argument, like :is(), with no extra unit of its own.
Selector and HTML examples
SelectorSpecificity(0, 2, 0)
.card:not(.archived, :has(.locked))
HTML
<section>
Matches:   <article class="card">Matches</article>
  <article class="card archived">Does not match</article>
  <article class="card"><span class="locked">Restricted</span></article>
</section>
SelectorSpecificity(0, 0, 2)
section:not(:has(h2, h3))
HTML
<main>
Matches:   <section>
    <p>Matches</p>
  </section>
  <section>
    <h2>Does not match</h2>
  </section>
</main>
Common conceptual mistakes
  • :not() does not remove or hide elements; it only decides whether the subject matches the rule.
  • The order of :not(:has(...)) is not interchangeable with :has(:not(...)); they express different conditions.
Relevant support

This Baseline status represents the Selectors Level 4 form that accepts lists inside :not().

Read the full definitionOpens in a new tab

Relationships with :has()

Select a subject by descendants or siblings matching relative selectors anchored to that subject.

:has()

:has(relative selector)

Selects the subject element when at least one relative selector matches with that element as the anchor.

Specificity(0, 1, 0)
Important behavior
  • Arguments may start with >, +, or ~ to check children or siblings relative to the subject.
  • Its specificity is replaced by that of the most specific relative argument.
Selector and HTML examples
SelectorSpecificity(0, 2, 0)
.card:has(> :is(.badge, .media))
HTML
<section>
Matches:   <article class="card">
    <span class="badge">Matches</span>
  </article>
  <article class="card"><p>Does not match</p></article>
Matches:   <aside class="card">
    <span class="media">Matches</span>
  </aside>
</section>
SelectorSpecificity(0, 0, 2)
dt:has(+ dt)
HTML
<dl>
Matches:   <dt>Matches</dt>
  <dt>Does not match</dt>
  <dd>CSS</dd>
  <dt>Does not match</dt>
  <dd>HTML</dd>
</dl>
Common conceptual mistakes
  • :has() cannot be nested inside another :has(), and its arguments do not accept pseudo-elements in Selectors Level 4.
  • Scope the subject to a concrete component instead of querying very broad ancestors without need.
Relevant support

This Baseline status covers :has(). As a later addition, it is shown separately from core selectors.

Read the full definitionOpens in a new tab