/* Container Queries */
.card-container {
container-type: inline-size; /* Creates query container */
container-name: card;
}
.card {
padding: 1rem;
border: 1px solid #ddd;
}
/* Query container width */
@container (min-width: 400px) {
.card {
display: grid;
grid-template-columns: 150px 1fr;
gap: 1rem;
}
}
@container (min-width: 600px) {
.card {
grid-template-columns: 200px 1fr;
padding: 2rem;
}
.card-title {
font-size: 1.5rem;
}
}
/* Named container queries */
.sidebar {
container-name: sidebar;
container-type: inline-size;
}
@container sidebar (min-width: 300px) {
.widget {
flex-direction: row;
}
}
/* Container query units */
.responsive-text {
font-size: clamp(1rem, 5cqw, 2rem); /* 5% of container width */
}
.container-relative {
padding: 2cqi; /* Container inline size */
margin: 1cqb; /* Container block size */
}
/* Multiple container conditions */
@container (min-width: 400px) and (max-width: 700px) {
.card {
background: lightblue;
}
}
/* :has() selector - parent selection */
.card:has(img) {
display: grid;
grid-template-columns: 200px 1fr;
}
.card:has(> .card-image) {
/* Direct child only */
border-color: blue;
}
/* Form validation styling */
form:has(input:invalid) {
border: 2px solid red;
}
form:has(input:valid) {
border: 2px solid green;
}
.form-group:has(input:focus) {
background-color: #f0f8ff;
}
/* Sibling selection with :has() */
h2:has(+ p) {
/* h2 followed by p */
margin-bottom: 0.5rem;
}
h2:not(:has(+ p)) {
/* h2 NOT followed by p */
margin-bottom: 2rem;
}
/* Multiple descendants */
article:has(h2, h3) {
padding: 2rem;
}
article:has(img):has(video) {
/* Contains both img and video */
display: grid;
}
/* Interactive state propagation */
.button-group:has(button:hover) {
background-color: #f5f5f5;
}
.menu:has(.menu-item:focus) {
box-shadow: 0 4px 8px rgba(0,0,0,0.1);
}
/* Checkbox hack replacement */
label:has(input[type="checkbox"]:checked) {
font-weight: bold;
color: blue;
}
.accordion:has(input:checked) .content {
max-height: 500px;
}
/* Empty state detection */
.list:has(li) .empty-state {
display: none;
}
.list:not(:has(li)) .empty-state {
display: block;
}
/* Cascade Layers */
@layer reset, base, components, utilities;
@layer reset {
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
}
@layer base {
body {
font-family: system-ui, sans-serif;
line-height: 1.5;
}
h1, h2, h3 {
line-height: 1.2;
}
}
@layer components {
.button {
padding: 0.5rem 1rem;
border: none;
border-radius: 4px;
cursor: pointer;
}
.card {
padding: 1rem;
border: 1px solid #ddd;
border-radius: 8px;
}
}
@layer utilities {
.text-center { text-align: center; }
.flex { display: flex; }
.hidden { display: none; }
}
/* Unlayered styles have highest priority */
.important-override {
color: red !important;
}
/* @supports feature queries */
@supports (container-type: inline-size) {
.card-container {
container-type: inline-size;
}
}
@supports not (container-type: inline-size) {
/* Fallback for browsers without container queries */
@media (min-width: 640px) {
.card {
display: grid;
grid-template-columns: 200px 1fr;
}
}
}
@supports (selector(:has(*))) {
.card:has(img) {
grid-template-columns: 200px 1fr;
}
}
@supports not (selector(:has(*))) {
.card.has-image {
grid-template-columns: 200px 1fr;
}
}
/* Combining modern features */
@container (min-width: 500px) {
.product-card:has(.badge) {
position: relative;
padding-top: 2rem;
}
.product-card:has(.badge) .badge {
position: absolute;
top: 1rem;
right: 1rem;
}
}
/* Color functions */
:root {
--primary: oklch(60% 0.2 250); /* Modern color space */
}
.color-mix {
background: color-mix(in srgb, blue 50%, red);
}
.relative-color {
--base: #3b82f6;
--lighter: oklch(from var(--base) calc(l + 0.2) c h);
--darker: oklch(from var(--base) calc(l - 0.2) c h);
}
/* :is() and :where() with :has() */
:is(article, section):has(h2) {
margin-bottom: 2rem;
}
:where(.card, .panel):has(img) {
/* Zero specificity */
display: grid;
}
/* Nesting (experimental) */
.card {
padding: 1rem;
&:hover {
box-shadow: 0 4px 8px rgba(0,0,0,0.1);
}
& h2 {
margin: 0;
}
@container (min-width: 400px) {
& {
display: grid;
grid-template-columns: 200px 1fr;
}
}
}
/* Subgrid */
.grid-parent {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 1rem;
}
.grid-child {
display: grid;
grid-template-columns: subgrid; /* Inherit parent columns */
grid-column: span 3;
}
/* Scroll-driven animations */
@supports (animation-timeline: scroll()) {
.fade-in-on-scroll {
animation: fade-in linear;
animation-timeline: view();
animation-range: entry 0% cover 30%;
}
@keyframes fade-in {
from { opacity: 0; transform: translateY(20px); }
to { opacity: 1; transform: translateY(0); }
}
}
Container queries enable responsive components based on container size using @container at-rule. I set container-type: inline-size to create query containers. The @container (min-width: 400px) queries container width instead of viewport. Named containers with container-name allow targeting specific parents. The :has() relational pseudo-class selects parents based on descendants. Using .card:has(img) selects cards containing images. The :has() enables sibling selectors like h2:has(+ p). Container query units (cqw, cqh, cqi, cqb) size relative to containers. The @layer rule manages cascade layers for better specificity control. Modern CSS reduces JavaScript dependency for responsive design. Feature detection with @supports ensures graceful degradation.