Modern CSS (:has, nesting, layers)

Difficulty: Advanced

Question

What are the newest CSS features? Explain :has(), native nesting, and @layer.

Answer

Modern CSS (2023-2025) introduced game-changing features:

1. :has() - parent selector: style parent based on children 2. Native CSS Nesting - nest selectors like Sass (no preprocessor needed) 3. @layer - cascade layers for controlling specificity order 4. @scope - scope styles to a DOM subtree 5. Subgrid - child grids inheriting parent grid tracks

These features reduce the need for preprocessors (Sass) and CSS-in-JS, making vanilla CSS much more powerful.

Code examples

:has() - The Parent Selector

/* Style parent based on child */
.card:has(img) {
  grid-template-rows: auto 1fr;
}
.card:has(img):not(:has(.badge)) {
  /* Card with image but no badge */
}

/* Form validation styling */
.field:has(input:invalid) {
  border-color: red;
}
.field:has(input:valid) {
  border-color: green;
}
.form:has(input:invalid) .submit-btn {
  opacity: 0.5;
  pointer-events: none;
}

/* Conditional layouts */
.grid:has(> :nth-child(4)) {
  grid-template-columns: repeat(2, 1fr);
}
.grid:has(> :nth-child(7)) {
  grid-template-columns: repeat(3, 1fr);
}

/* Previous sibling selector (reverse + ) */
.item:has(+ .item:hover) {
  /* Style item BEFORE the hovered item */
  transform: scale(0.95);
}

:has() is the most requested CSS feature ever. It lets you select parents and previous siblings, which was previously impossible without JavaScript.

Native CSS Nesting

/* Native CSS nesting (no Sass needed!) */
.card {
  background: white;
  border-radius: 0.5rem;

  /* Nested selector */
  & .title {
    font-size: 1.25rem;
    font-weight: 600;
  }

  /* & is optional for pseudo-classes */
  &:hover {
    box-shadow: 0 4px 12px rgb(0 0 0 / 0.1);
  }

  /* Nested media query */
  @media (min-width: 768px) {
    padding: 2rem;

    & .title {
      font-size: 1.5rem;
    }
  }

  /* BEM with nesting */
  &__body {
    padding: 1.5rem;
  }
  &--featured {
    border: 2px solid #3b82f6;
  }
}

/* Compiles mentally to:
   .card { }
   .card .title { }
   .card:hover { }
   .card__body { }
   .card--featured { } */

Native CSS nesting works like Sass but in the browser with no build step. The & symbol references the parent selector. Supported in all modern browsers since 2023.

@layer - Cascade Layers

/* Define layer order (lowest to highest priority) */
@layer reset, base, components, utilities;

/* Reset layer (lowest priority) */
@layer reset {
  * { margin: 0; padding: 0; box-sizing: border-box; }
}

/* Base layer */
@layer base {
  body { font-family: system-ui; line-height: 1.6; }
  a { color: #3b82f6; }
}

/* Components layer */
@layer components {
  .btn {
    padding: 0.75rem 1.5rem;
    border-radius: 0.375rem;
  }
  .card {
    background: white;
    border-radius: 0.5rem;
  }
}

/* Utilities layer (highest priority) */
@layer utilities {
  .hidden { display: none !important; }
  .text-center { text-align: center; }
}

/* Utilities ALWAYS override components,
   regardless of specificity!
   .card has higher specificity than .hidden,
   but utilities layer wins */

/* Un-layered styles beat ALL layers */

@layer controls the cascade independently from specificity. Later layers override earlier ones regardless of selector specificity. This solves specificity wars.

Key points

Concepts covered

:has(), CSS Nesting, @layer, Cascade Layers, Modern CSS Features