CSS has evolved radically

The CSS landscape in 2026 is drastically different from just three years ago. Features that were impossible without JavaScript for decades are now solved with pure CSS. In this article we explore the most impactful new features and how you can start using them today in your projects.

Container Queries: component-based design

The problem they solve

Historically, media queries allowed us to adapt the design based on the browser window size. But in the era of reusable components, a single component can live in a narrow sidebar or in a wide main section. Media queries cannot solve this.

Container Queries allow a component to respond to the size of its parent container, not the window.

How they work

The process has two steps:

  1. Declare a container with container-type
  2. Use @container to define conditional rules
/* Paso 1: declarar el contenedor */
.sidebar {
  container-type: inline-size;
  container-name: sidebar;
}

/* Paso 2: reglas basadas en el contenedor */
@container sidebar (min-width: 300px) {
  .widget {
    display: grid;
    grid-template-columns: 1fr 1fr;
  }
}

container-type values

Value Behavior
inline-size Responds to container width (the most common)
size Responds to both width and height
normal Does not establish containment (default value)

Container Query Units

CSS also introduced container-relative units:

  • cqw - 1% of the container width
  • cqh - 1% of the container height
  • cqi - 1% of the container inline size
  • cqb - 1% of the container block size
.card-title {
  font-size: clamp(1rem, 4cqi, 2rem);
}

The :has() selector - CSS's "parent selector"

The :has() selector is possibly the most revolutionary addition to CSS in the last decade. It allows selecting an element based on its descendants or subsequent siblings.

Practical use cases

Interactive form without JavaScript:

/* Resaltar el fieldset que contiene un input con foco */
fieldset:has(input:focus) {
  background: var(--surface-active);
  border-left: 3px solid var(--color-primary);
}

/* Deshabilitar visualmente un boton si hay inputs vacios */
form:has(input:placeholder-shown) .submit-btn {
  opacity: 0.5;
  pointer-events: none;
}

Conditional layout:

/* Si el main tiene un aside, usar grid de dos columnas */
main:has(aside) {
  display: grid;
  grid-template-columns: 1fr 300px;
}

/* Si no tiene aside, una sola columna */
main:not(:has(aside)) {
  max-width: 65ch;
  margin-inline: auto;
}

Combining :has() with other pseudo-classes

/* Estilizar una lista solo si tiene más de 5 items */
ul:has(li:nth-child(6)) {
  columns: 2;
  column-gap: 2rem;
}

Native CSS Nesting

After years of depending on preprocessors like Sass, CSS now supports native nesting. This improves readability and reduces selector repetition.

Basic syntax

.card {
  padding: 1.5rem;
  border-radius: 0.75rem;

  .card-header {
    display: flex;
    align-items: center;
    gap: 0.5rem;
  }

  .card-body {
    margin-top: 1rem;
    line-height: 1.6;
  }

  &:hover {
    transform: translateY(-2px);
    box-shadow: 0 4px 12px rgb(0 0 0 / 10%);
  }

  @media (width < 768px) {
    padding: 1rem;
  }
}

Important nesting rules

  1. For type selectors (like p, h2), you need to use & or be explicit with the context
  2. Media queries can be nested directly
  3. The ampersand & works the same as in Sass
.article {
  /* Correcto - con & */
  & p {
    margin-bottom: 1rem;
  }

  /* Correcto - selector de clase directamente */
  .highlight {
    background: yellow;
  }
}

Subgrid: perfect alignment between parent and child

subgrid allows a child element to inherit grid lines from its parent. This solves one of the most frustrating Grid layout problems: aligning content between sibling cards.

.grid-layout {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 1.5rem;
}

.card {
  display: grid;
  grid-template-rows: subgrid;
  grid-row: span 3; /* header, body, footer */
}

With subgrid, all card headers, bodies, and footers align perfectly with each other, regardless of content length.

@scope: style encapsulation without Shadow DOM

The @scope rule allows limiting the scope of styles to a DOM subtree, with an optional lower boundary.

@scope (.card) to (.card-footer) {
  p {
    color: var(--text-secondary);
    line-height: 1.7;
  }

  a {
    color: var(--color-primary);
    text-decoration: underline;
  }
}

This applies styles only to p and a elements inside .card but outside .card-footer.

Current browser support

Most of these features have excellent support in 2026:

Feature Chrome Firefox Safari
Container Queries 105+ 110+ 16+
:has() 105+ 121+ 15.4+
CSS Nesting 120+ 117+ 17.2+
Subgrid 117+ 71+ 16+
@scope 118+ 128+ 17.4+

Conclusion

CSS in 2026 is a completely different language from the CSS we knew five years ago. With container queries, :has(), native nesting, subgrid, and @scope, we can build more robust, more maintainable interfaces with less JavaScript dependency. The best time to adopt these features is now.