Make your components responsive to their container rather than the viewport, and structure your stylesheets with native nesting.
Open this lesson in KodokonMedia queries measure the viewport: a card displayed both in a narrow sidebar and in a main grid cannot adapt correctly with them, because the same screen width corresponds to two different contexts. Container queries resolve this decoupling: the component queries the size of its container. Prerequisite: explicitly designate a container with container-type (inline-size to measure only the horizontal axis, the common case), optionally named via container-name.
.sidebar {
container-type: inline-size;
container-name: sidebar;
}
@container sidebar (min-width: 400px) {
.widget {
display: grid;
grid-template-columns: 80px 1fr;
gap: 12px;
}
}Container units complete the picture: 1cqi equals 1% of the inline size of the queried container (cqw, cqh, cqb, cqmin, cqmax also exist). Combined with clamp(), they produce fluid typography per component: the same card gets a title proportioned to its column, wherever it is placed.
.card-slot {
container-type: inline-size;
}
.card h2 {
font-size: clamp(1rem, 5cqi, 1.75rem);
}
@container (max-width: 300px) {
.card .meta {
display: none;
}
}Native nesting finally brings nesting without a preprocessor. The & selector references the parent context; media queries and @container nest directly inside a rule. A crucial difference from Sass: the nested parent is treated as if wrapped in :is(). Two consequences: the parent's specificity is that of the strongest of its selectors if it is a list, and & .child does not perform string concatenation - the Sass &__element pattern for generating BEM names does not exist natively.
.menu {
display: flex;
gap: 8px;
& > li {
list-style: none;
&:hover {
background: #f3f4f6;
}
}
@media (min-width: 768px) {
gap: 16px;
}
}5cqi correspond to?