Skip to content

CSS :has() Selector Not Supported Fix

DodaTech Updated 2026-06-24 3 min read

In this tutorial, you'll learn about CSS :has() Selector Not Supported Fix. We cover key concepts, practical examples, and best practices.

The Problem

The CSS :has() relational selector lets you style a parent element based on its children. Older browsers do not support it, and incorrect usage (like nesting :has() inside :has() or using it where it is not allowed) causes the entire rule to fail.

Quick Fix

Step 1: Provide fallback for unsupported browsers

/* Wrong — no fallback for browsers without :has() */
.card:has(img) {
    grid-column: span 2;
}

/* Right — enhance with :has(), keep baseline styles */
.card {
    grid-column: span 1;
}

@supports selector(:has(*)) {
    .card:has(img) {
        grid-column: span 2;
    }
}

Step 2: Use :has() to style parent based on child state

/* Wrong — cannot select parent based on child */
.form input:invalid {
    border-color: red; /* Only styles the input, not the parent */
}

/* Right — style the parent based on child state */
.form:has(input:invalid) {
    border: 2px solid red;
    padding: 1rem;
}

.form:has(input:valid) {
    border: 2px solid green;
    padding: 1rem;
}

Step 3: Avoid forbidden :has() usages

/* Wrong — :has() inside pseudo-elements not allowed */
.element::after:has(.child) {
    content: 'has child';
}

/* Wrong — :has() inside :has() may cause performance issues */
.parent:has(:has(.child)) {
    color: red;
}

/* Right — flatten the selector */
.parent:has(.child) {
    color: red;
}

Step 4: Use :has() for quantity queries

/* Wrong — no way to count items without JS */
.list-item { width: 100%; }

/* Right — use :has() for quantity-based styling */
.list:has(> :nth-child(n+5)) .list-item {
    width: 50%;
}

.list:has(> :nth-child(n+10)) .list-item {
    width: 33.33%;
}

Step 5: Style siblings based on adjacent state

/* Wrong — cannot select next sibling based on previous */
.input:focus + .label { color: blue; }

/* Right — use :has() to target any sibling */
.form-group:has(.input:focus) .label {
    color: blue;
    font-weight: bold;
}

Prevention

  • Always provide baseline styles before :has() enhancements
  • Use @supports selector(:has(*)) to detect support
  • Avoid nesting :has() inside :has()
  • Do not use :has() inside pseudo-elements
  • Test in target browsers to ensure fallback behavior

Common Mistakes with has selector

  1. Forgetting that lazy evaluation defers computation until the value is forced, causing space leaks with unevaluated thunks
  2. Using return to exit a function early instead of wrapping a pure value in the monad
  3. Mixing let bindings with <- bindings in do notation, producing type errors

These mistakes appear frequently in real-world CSS code. DodaTech's contributors have identified these patterns through analysis of open-source projects and production systems.

Practice Exercise

Write a pure function that safely divides two integers using Maybe, then test it with edge cases like division by zero and negative numbers.

This exercise reinforces the concepts covered in this guide. Try implementing it before checking online solutions.

FAQ

### Why is my :has() selector not working?

Check for unsupported patterns: :has() inside pseudo-elements, nested :has(), or :has() with compound selectors that the browser cannot evaluate. Use @supports selector(:has(*)) to verify support first.

Can :has() select ancestors and siblings?

Yes. :has() traverses up the DOM (parent selector) and sideways (sibling selector). Use div:has(> p) for direct child, div:has(+ .sibling) for adjacent sibling.

Does :has() affect performance on large pages?

:has() can be computationally expensive because the browser must re-evaluate when child content changes. For most pages the impact is negligible, but avoid deeply nested :has() selectors on very large DOM trees.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro