正在加载,请稍候…

Modern CSS Layout 2026: Container Queries, Subgrid, Cascade Layers, and :has()

Master modern CSS layout techniques. Container queries for component responsiveness, CSS Grid subgrid for aligned layouts, cascade layers for specificity control, and the :has() selector.

The CSS landscape in 2026 has solved problems that required JavaScript workarounds for years. Container queries, subgrid, cascade layers, and :has() are all baseline-available.

Container Queries: Component-Based Responsiveness

Media queries respond to viewport width. Container queries respond to the parent element's width — enabling truly portable components.

/* Step 1: Define a containment context */
.card-container {
  container-type: inline-size;
  container-name: card;
}

/* Step 2: Style based on container width, not viewport */
.card {
  display: flex;
  flex-direction: column;
}

@container card (min-width: 400px) {
  .card {
    flex-direction: row;
    gap: 1rem;
  }
  .card__image {
    width: 200px;
    flex-shrink: 0;
  }
}

/* Container query units: cqw = 1% of container width */
.card__title {
  font-size: clamp(1rem, 3cqw, 2rem);
}

CSS Grid Subgrid: Cross-Card Alignment

/* The classic problem: card titles can't align across cards */
/* With subgrid: cards share the parent's row tracks */
.product-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
  gap: 1.5rem;
}

.product-card {
  display: grid;
  grid-row: span 3;            /* Each card spans 3 rows */
  grid-template-rows: subgrid;  /* Participate in parent's grid */
}

/* Now image/title/body align perfectly across ALL cards */
.card-image { grid-row: 1; }
.card-title { grid-row: 2; }
.card-body  { grid-row: 3; }

Cascade Layers: End Specificity Wars

/* Define layer order: later layers win specificity ties */
@layer base, components, utilities;

@layer base {
  *, *::before, *::after { box-sizing: border-box; }
  body { margin: 0; font-family: system-ui; }
}

@layer components {
  .button {
    padding: 0.5rem 1rem;
    background: var(--color-primary);
    color: white;
  }
}

@layer utilities {
  /* These win over components regardless of selector specificity */
  .sr-only { position: absolute; width: 1px; height: 1px; overflow: hidden; }
}

/* Import third-party CSS into a layer (it loses to our layers) */
@import url('bootstrap.css') layer(bootstrap);
@layer bootstrap, components;  /* Our components override Bootstrap */

:has() Relational Selector

/* Style a form based on child validity */
.form-group:has(input:invalid) label {
  color: red;
}

/* Card layout depends on whether it has an image */
.card:has(img) {
  grid-template-columns: 200px 1fr;
}
.card:not(:has(img)) {
  grid-template-columns: 1fr;
}

/* Navigation: dim other links when a dropdown is open */
nav:has(.dropdown:hover) .other-links {
  opacity: 0.5;
}

/* Auto-grid based on child count */
.gallery:has(> :nth-child(4)) { grid-template-columns: repeat(2, 1fr); }
.gallery:has(> :nth-child(5)) { grid-template-columns: repeat(3, 1fr); }

Custom Properties with @property

/* @property enables type-checked custom properties */
@property --gradient-angle {
  syntax: '<angle>';
  inherits: false;
  initial-value: 0deg;
}

.animated-border {
  background: conic-gradient(
    from var(--gradient-angle),
    var(--color-primary), var(--color-secondary), var(--color-primary)
  );
  animation: rotate 3s linear infinite;
}

@keyframes rotate {
  to { --gradient-angle: 360deg; }  /* Only works with @property */
}

Container queries, subgrid, and cascade layers together solve the three hardest CSS layout problems. All are available in modern browsers without polyfills.

→ Validate your CSS hex colors with the Color Converter tool.