CSS :has() Pseudo-Class

Beginner
5 min read
Updated: Oct 2026
3 examples
Live preview

Definition and Usage

The :has() pseudo-class matches an element when a relative selector inside the parentheses finds at least one match. Use it to style a parent from its children, or a previous sibling from what comes next.

Examples: .card:has(img) styles a card that contains an image; h1:has(+ p) styles an h1 only when the next sibling is a p.

Baseline Widely available.

Widely available across modern browsers since December 2023. Prefer progressive enhancement if you must support older engines.

Warning — limits inside :has().

You cannot nest :has() inside :has(), and pseudo-elements are not valid arguments. Specificity follows the most specific selector in the argument list (like :not()).

CSS Syntax

syntax.css
:has( <relative-selector-list>)

Relative selectors may start with a combinator such as >, +, or ~.

Selector Arguments

:has() takes a relative selector list — not property values. Common patterns:

PatternDescriptionTry it
:has(img)Element that contains an img descendantTry it
:has(> .child)Element with a matching direct childTry it
:has(+ p)Element followed immediately by a pTry it
:has(a, b)OR — matches if a or b is foundTry it
:has(a):has(b)AND — both conditions must matchTry it
:not(:has(...))Style when the condition is missingTry it

How to Use :has()

Anchor on the element you want to style, then describe what it must contain or be next to.

  1. Choose the element that should receive the styles (the anchor).
  2. Write :has(...) with a relative selector for the condition.
  3. Use > or + when you want a tighter match.
  4. Keep the anchor specific — avoid anchoring to body or * for large pages.
PieceRequired?Role
Anchor selectorUsually yesThe element that gets the styles
Relative selector listYesCondition checked from that element
Combinator (>, +, …)NoLimits how far the condition looks
Valid argumentYesNo nested :has(), no pseudo-elements

Live Preview

Switch :has() patterns and watch which card or heading lights up.

Matched anchors get a blue border and tinted background.

:has() preview

Card with image

Card without image

Badge

Box with direct badge

Box without badge

Heading with p

Next sibling paragraph

Heading alone

Rule: .card:has(img) — cards that contain an image match

CSS Examples

Each snippet focuses on :has(). Use Try It Yourself for a live editor.

Example 1 — Style a Parent From Its Child

Highlight a section when it contains a featured article.

CSS
section:has(.featured) {
  border: 2px solid #2563eb;
  background: #eff6ff;
}
Try It Yourself

How It Works

  1. Anchor on the parent. section is the element you want to style.
  2. Add the condition. :has(.featured) checks for that descendant.
  3. Style the parent. Border and background apply to the matching section.
  4. Leave others. A section without .featured stays normal.

Example 2 — Style a Previous Sibling

Tighten spacing after an h1 when an h2 follows immediately.

CSS
h1:has(+ h2) {
  margin-bottom: 0.25rem;
}
Try It Yourself

How It Works

  1. Look ahead with +. + h2 means the next sibling is an h2.
  2. Style the earlier element. The rule applies to the h1, not the h2.
  3. Skip other cases. An h1 followed by a p does not match.
  4. Use for layout polish. Common for heading stacks and form labels.

Example 3 — OR With a Selector List

Match if any listed condition is true.

CSS
.media:has(video, audio) {
  outline: 2px solid #7c3aed;
}
Try It Yourself

How It Works

  1. Pass a list. Commas inside :has() mean any match is enough.
  2. Style the container. .media gets the outline when video or audio exists.
  3. Skip empty cases. A media box with only text does not match.
  4. Need both? Write :has(video):has(audio) instead.

Edge Cases & Pitfalls

Most issues are nesting limits, broad anchors, or confusing OR vs AND.

nest

No :has() inside :has()

Nested :has() is invalid. Rewrite the condition with combinators or chained :has() on the same anchor.

pseudo

No pseudo-elements inside

::before, ::after, and similar are not valid arguments for :has().

perf

Avoid broad anchors

Prefer a specific container over body:has(...), :root:has(...), or *:has(...) on large pages.

logic

Comma is OR; chaining is AND

:has(a, b) matches either. :has(a):has(b) requires both.

support

Unsupported browsers drop the rule

If :has() is not supported, the whole selector fails unless it sits in a forgiving list such as :is() / :where().

Browser Support

:has() is a browser CSS pseudo-class. Node.js, Deno, and Bun do not evaluate it.

✓ Baseline · Widely available

:has()

Chrome 105+, Edge 105+, Safari 15.4+, Firefox 121+, Opera 91+, Samsung Internet 20+ (widely available since Dec 2023).

95% Modern browsers
Google Chrome 105+
Full support
Mozilla Firefox 121+
Full support
Apple Safari 15.4+
Full support
Microsoft Edge 105+
Full support
Opera 91+
Full support
Samsung Internet 20+
Full support
:has() Widely supported

Bottom line: Safe for modern sites. Use progressive enhancement for older browsers. Not a server runtime API.

Key Takeaways

  • Role: style an element based on what it contains or what follows it.
  • Form: anchor:has(relative-selector)
  • Logic: comma = OR; chained :has() = AND.
  • Tip: keep anchors specific and conditions tight with > or +.

One line: A:has(B) styles A when relative selector B matches from A.

Frequently Asked Questions

It matches an element when a relative selector inside the parentheses finds at least one match. Use it to style a parent from its children, or a previous sibling from what follows.
Yes in practice. section:has(.featured) styles the section when it contains .featured. Use > for a direct child: section:has(> .featured).
Yes. h1:has(+ p) styles an h1 only when the next sibling is a p. That looks forward, then styles the earlier element.
:has(a, b) is OR — match if a or b is found. :has(a):has(b) is AND — both must match.
No. :has() cannot contain another :has(), and pseudo-elements are not valid inside :has().
No. It is a browser CSS pseudo-class. Node.js, Deno, and Bun do not apply it.

Next: :hover

Style an element while the pointer is over it.

:hover tutorial →

About the author

Mari Selvan M P
Mari Selvan M P 🔗

Developer, cloud engineer, and technical writer

  • Experience 12 years building web and cloud systems
  • Focus Full Stack Development, AWS, and Developer Education

I write practical tutorials so students and working developers can learn by doing—from databases and APIs to deployment on AWS.

8 people found this page helpful