Modern CSS 2026 — Container Queries, CSS Grid, Layers, and New Features

Sanjeev SharmaSanjeev Sharma
5 min read

Advertisement

Introduction

Why This Matters

CSS in 2026 is unrecognizable compared to 2020. Container queries, cascade layers, native nesting, :has(), color-mix(), and subgrid are all baseline-supported across browsers. These features replace entire libraries and JavaScript workarounds that were standard practice just a few years ago.

Container Queries

Respond to the parent container size, not the viewport:

/* Mark an element as a container */
.card-grid {
  container-type: inline-size;
  container-name: card-grid;
}
 
/* Style children based on container width */
@container card-grid (min-width: 600px) {
  .card {
    display: grid;
    grid-template-columns: 200px 1fr;
  }
}
 
@container card-grid (min-width: 900px) {
  .card {
    grid-template-columns: 280px 1fr;
  }
 
  .card-title {
    font-size: 1.5rem;
  }
}

Container query units:

.responsive-text {
  /* cqi = 1% of the container's inline size */
  font-size: clamp(1rem, 4cqi, 2rem);
  padding: 2cqi;
}

CSS Cascade Layers

Layers give explicit control over specificity — no more !important wars:

/* Define layer order (lower = lower priority) */
@layer reset, base, components, utilities;
 
@layer reset {
  *, *::before, *::after { box-sizing: border-box; margin: 0; }
}
 
@layer base {
  body {
    font-family: system-ui, sans-serif;
    line-height: 1.6;
  }
 
  a { color: var(--color-link); }
}
 
@layer components {
  .btn {
    display: inline-flex;
    padding: 0.5rem 1rem;
    border-radius: 0.375rem;
    background: var(--color-primary);
    color: white;
  }
 
  /* Overrides base layer a color inside .btn */
  .btn a { color: inherit; }
}
 
@layer utilities {
  .sr-only {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
  }
}
 
/* Unlayered styles win over all layers regardless of order */
.override { color: red; }

CSS Nesting

Native CSS nesting — no preprocessor needed:

.card {
  background: white;
  border-radius: 0.5rem;
  padding: 1.5rem;
  box-shadow: 0 1px 3px rgb(0 0 0 / 0.1);
 
  /* Nest selectors with & */
  &:hover {
    box-shadow: 0 4px 12px rgb(0 0 0 / 0.15);
    transform: translateY(-2px);
  }
 
  & .card-title {
    font-size: 1.25rem;
    font-weight: 700;
    margin-bottom: 0.5rem;
  }
 
  & .card-body {
    color: var(--color-text-secondary);
    line-height: 1.7;
  }
 
  @media (min-width: 768px) {
    padding: 2rem;
  }
}

The :has() Selector

Target parents based on their children — the "parent selector" CSS never had:

/* Card with an image gets different padding */
.card:has(img) {
  padding: 0;
}
 
.card:has(img) .card-content {
  padding: 1.5rem;
}
 
/* Form label styling based on required input */
.form-group:has(input:required) label::after {
  content: ' *';
  color: var(--color-danger);
}
 
/* Navigation item with active child */
.nav-item:has(> .active) {
  background: var(--color-primary-light);
  border-left: 3px solid var(--color-primary);
}
 
/* Grid changes when it contains fewer than 3 items */
.grid:not(:has(:nth-child(3))) {
  grid-template-columns: repeat(2, 1fr);
}

CSS Subgrid

Align nested elements to the parent grid:

.product-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
  gap: 1.5rem;
}
 
.product-card {
  display: grid;
  /* Inherit the parent's column tracks */
  grid-template-rows: subgrid;
  grid-row: span 4;  /* image | title | description | price+button */
}
 
/* All cards now align their titles, descriptions, and buttons in the same row */
.product-card img    { grid-row: 1; }
.product-card h2     { grid-row: 2; align-self: start; }
.product-card p      { grid-row: 3; }
.product-card footer { grid-row: 4; align-self: end; }

color-mix() and Modern Color Functions

:root {
  --color-brand: oklch(55% 0.22 264);
 
  /* Mix to create tints/shades */
  --color-brand-light: color-mix(in oklch, var(--color-brand) 30%, white);
  --color-brand-dark: color-mix(in oklch, var(--color-brand) 80%, black);
  --color-brand-alpha: color-mix(in oklch, var(--color-brand) 20%, transparent);
}
 
/* oklch gives perceptually uniform colors — equal lightness = same perceived brightness */
.success { background: oklch(65% 0.18 145); }
.warning { background: oklch(65% 0.18 80); }
.danger  { background: oklch(65% 0.18 25); }

Common Mistakes

  • Using @media queries for component-level responsive design instead of @container
  • Not defining a @layer order at the top of the stylesheet — layers defined out of order behave unpredictably
  • Nesting too deeply — CSS nesting is readable up to 3 levels; deeper nesting hurts maintainability
  • Using color: oklch(...) without a fallback for Safari 15 or older — use @supports for progressive enhancement
  • Using !important instead of reorganizing cascade layers

Best Practices

  • Use @layer for all CSS including third-party libraries to make specificity predictable
  • Use container-type: inline-size on layout containers and @container for component breakpoints
  • Write colors in oklch for accessible, perceptually uniform palettes
  • Use :has() to reduce JavaScript-driven class toggling for CSS-expressible logic
  • Use subgrid to align card content across different cards without JavaScript measurement

Key Takeaways

  • Container queries (@container) respond to parent size, enabling truly reusable components
  • Cascade layers (@layer) give explicit precedence control — replacing !important hacks
  • Native CSS nesting is baseline-supported in all major browsers since 2024
  • :has() is the long-awaited "parent selector" — enables selecting elements by their children
  • CSS Subgrid aligns nested items to an ancestor grid without extra wrappers
  • oklch() colors are perceptually uniform — equal L values have equal perceived lightness
  • color-mix() creates tints, shades, and alpha variants without preprocessors
  • cqi container query units (1% of inline size) allow fluid typography inside components

Advertisement

Sanjeev Sharma

Written by

Sanjeev Sharma

Full Stack Engineer · E-mopro