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.