CSS-containerquery's: echt responsieve componenten
Jarenlang betekende responsive design: ‘de layout aanpassen aan de viewport’.
Een componentenkaart met @media (max-width: 768px) hij weet hoe breed het is
op het scherm, maar hij weet niet hoeveel ruimte hij daadwerkelijk op zijn scherm heeft
context. Plaats die kaart in een smalle zijbalk en hij gedraagt zich alsof hij dat is
op mobiel, zelfs als het scherm een 27-inch desktop is. Zet het in de hoofdinhoud
en het gedraagt zich als een desktop, ook al is die container smaller dan een smartphone.
Le CSS-containerquery's los dit probleem bij de wortel op: een component kan reageren op de grootte van de eigen container, niet van de kijkpoort. Met superieure browserondersteuning88% in basisscenario 2025 (Chrome 105+, Firefox 110+, Safari 16+), deze techniek is productieklaar.
Wat je gaat leren
- Het fundamentele verschil tussen mediaquery's en containerquery's
- Hoe een containmentcontext te definiëren met
container-type - De syntaxis
@containervoor vragen - Query's over de containergrootte: inlinegrootte, blokgrootte
- Query's in containerstijl: query's op basis van aangepaste eigenschappen
- Benoemde containers voor hiërarchische query's
- Hoe containerquery's te integreren in Angular, React en Vue
Het probleem met mediaquery's
Mediaquery's bevragen de kenmerken van de kijkvenster: de breedte van het scherm, de oriëntatie, het kleurenschema. Dit werkt wanneer de lay-out en eenvoudig en een onderdeel heeft altijd een voorspelbare breedte. Maar in de ontwerpen moderne systemen wordt hetzelfde onderdeel hergebruikt in radicaal verschillende contexten:
- Een productkaart op de homepage (3 kolommen op desktop)
- Dezelfde kaart in de zijbalk 'gerelateerde producten' (1 smalle kolom)
- Dezelfde kaart in een modaal op volledig scherm (2 kolommen)
- Dezelfde kaart op de zoekpagina (variabel op basis van actieve filters)
Bij mediaquery's moet u vooraf de context van elk gebruik kennen en schrijven case-specifieke CSS-selectors. Bij containerquery's kan de e autonoom: het past zich aan de beschikbare ruimte aan.
Definieer een container
Als u containerquery's wilt gebruiken, moet u eerst aangeven welk element de
"container" die in twijfel zal worden getrokken. Het is gedaan met eigendom container-type:
/* Crea un container che risponde alla larghezza (inline-size) */
.card-wrapper {
container-type: inline-size;
}
/* Crea un container che risponde sia a larghezza che altezza */
.card-wrapper {
container-type: size;
}
/* Dai un nome al container per query gerarchiche */
.card-wrapper {
container-type: inline-size;
container-name: card;
}
/* Shorthand */
.card-wrapper {
container: card / inline-size;
}
Zodra een item dat heeft container-type, al zijn nakomelingen
ze kunnen gebruiken @container om de afmetingen ervan op te vragen.
De syntaxis @container
De syntaxis is identiek aan die van mediaquery's, maar in plaats van de viewport te bevragen, vraag naar de dichtstbijzijnde container met een insluitingscontext:
.card {
/* Layout default: verticale, compatto */
display: grid;
grid-template-areas:
"image"
"content";
gap: 12px;
}
.card__image {
aspect-ratio: 16 / 9;
object-fit: cover;
border-radius: 8px 8px 0 0;
}
/* Quando il container e largo almeno 400px: layout orizzontale */
@container (min-width: 400px) {
.card {
grid-template-areas: "image content";
grid-template-columns: 200px 1fr;
}
.card__image {
aspect-ratio: 1;
border-radius: 8px 0 0 8px;
}
}
/* Quando il container e largo almeno 600px: layout espanso */
@container (min-width: 600px) {
.card {
grid-template-columns: 280px 1fr;
gap: 24px;
padding: 24px;
}
.card__title {
font-size: 1.5rem;
}
}
/* Range syntax (CSS Level 4) - piu leggibile */
@container (200px <= width <= 400px) {
.card {
/* stile per range specifico */
}
}
Benoemde containers: hiërarchische zoekopdrachten
Wanneer u geneste containers hebt, kunt u de containers een naam geven waarvoor u een query wilt uitvoeren specifieke voorouder in plaats van de dichtstbijzijnde:
<!-- HTML struttura -->
<main class="layout" style="container: layout / inline-size">
<aside class="sidebar" style="container: sidebar / inline-size">
<div class="widget">
<!-- Questo widget puo interrogare sia "sidebar" che "layout" -->
</div>
</aside>
</main>
/* Query sul container "sidebar" (il piu vicino) */
@container sidebar (min-width: 300px) {
.widget { display: flex; }
}
/* Query sul container "layout" (l'antenato nominato) */
@container layout (min-width: 1200px) {
.widget { max-width: 400px; }
}
Containerstijlquery's: de verborgen functie
Naast groottequery's ondersteunen ook containerquery's stijl vragen: zoekopdrachten gebaseerd op de waarden van de aangepaste CSS-eigenschappen van de container. Deze functie, ondersteund in Chrome 111+ en Safari 17.4+, opent mogelijkheden volledig nieuw qua thema's en componentvarianten.
/* Definisci una custom property sul container */
.card-wrapper {
container-type: style;
/* La variante del componente viene comunicata via custom property */
--card-variant: featured;
}
/* Il componente si adatta alla variante del container */
@container style(--card-variant: featured) {
.card {
border: 2px solid var(--color-accent);
background: var(--color-accent-subtle);
}
.card__badge {
display: block; /* mostra il badge "In evidenza" */
}
}
@container style(--card-variant: compact) {
.card {
padding: 8px;
font-size: 0.875rem;
}
.card__image {
display: none; /* nasconde l'immagine in modalita compatta */
}
}
Met dit patroon kunt u semantische context communiceren van de container naar de component zonder extra CSS- of JavaScript-klassen, waarbij de inkapseling behouden blijft.
Maateenheden voor containers: cqw, cqh, cqi, cqb
Bij containervragen komen ook nieuwe meeteenheden met betrekking tot de container:
cqw: 1% van de breedte van de containercqh: 1% van de containerhoogtecqi: 1% van de container inline-grootte (= cqw voor LTR-indeling)cqb: 1% van de containerblokgrootte (= cqh)cqmin: de kleinste tussen cqi en cqbcqmax: hoe groter tussen cqi en cqb
/* Tipografia fluida relativa al container */
.card__title {
/* Scala da 16px a 24px in base alla larghezza del container */
font-size: clamp(1rem, 4cqi, 1.5rem);
}
/* Padding proporzionale al container */
.card {
padding: 5cqi;
}
/* Gap che si adatta */
.card__grid {
display: grid;
gap: clamp(8px, 2cqi, 24px);
}
Containerquery's in Angular, React en Vue
Hoekig: containerbewuste componenten
/* card.component.scss */
:host {
display: block;
container-type: inline-size;
container-name: card-host;
}
.card {
display: grid;
grid-template-areas: "image" "content";
gap: 12px;
}
@container card-host (min-width: 400px) {
.card {
grid-template-areas: "image content";
grid-template-columns: 180px 1fr;
}
}
// card.component.ts
@Component({
selector: 'app-card',
templateUrl: './card.component.html',
styleUrls: ['./card.component.scss'],
// :host come container - nessun JS necessario per il responsive
host: { class: 'card-container' }
})
export class CardComponent {
@Input() product!: Product;
}
Reageren: CSS-modules met containerquery's
/* card.module.css */
.wrapper {
container-type: inline-size;
container-name: card;
}
.card {
display: grid;
gap: 12px;
}
@container card (min-width: 400px) {
.card {
grid-template-columns: 180px 1fr;
}
}
// Card.tsx
import styles from './card.module.css';
export function Card({ product }: { product: Product }) {
return (
<div className={styles.wrapper}>
<article className={styles.card}>
<img src={product.image} alt={product.name} />
<div>
<h3>{product.name}</h3>
<p>{product.description}</p>
</div>
</article>
</div>
);
}
Containerquery's versus mediaquery's: wanneer moet u wat gebruiken?
| Scenario | Optimale keuze | Reden |
|---|---|---|
| Globale pagina-indeling | Mediavragen | De lay-out is afhankelijk van de viewport |
| Herbruikbare componenten | Containerquery's | Het onderdeel moet zich aanpassen aan zijn context |
| Ontwerp systeemtokens | Beide | Viewports voor breekpunten, containers voor varianten |
| Donker/licht-modus | Mediavragen | geeft de voorkeur aan kleurenschema en een mediafunctie |
| Dynamische zijbalk | Containerquery's | Inhoud past in open/gesloten zijbalk |
| Printstijl | Mediavragen | @media print is een mediaquery |
Patroon Anti: veelvoorkomende fouten bij containerquery's
Fout #1: container vraagt zichzelf af
Een element met container-type hij kan zichzelf niet in twijfel trekken
@container — het moet een afstammeling zijn die is gewijzigd.
Definieer nooit een container en een regel @container op hetzelfde
keuzeschakelaar.
Fout #2: containertype: grootte zonder hoogte gedefinieerd
container-type: size vereist dat de container een maat heeft
zowel in de breedte als in de hoogte gedefinieerd. Als je gebruikt size op een container
zonder expliciete hoogte, queries height e cqh
ze zullen niet werken zoals verwacht. VS inline-size in de meerderheid
van gevallen.
Volgende stappen
Dankzij containerquery's beschikt u nu over echt responsieve componenten. Het volgende artikel in de serie onderzoekt de CSS Anchor Positioning API, die dit mogelijk maakt om tooltips, vervolgkeuzelijsten en popovers te implementeren zonder een enkele regel JavaScript: een andere techniek die CSS dichter bij de declaratieve kracht brengt waar ontwikkelaars op hebben gewacht jarenlang.
Conclusies
CSS-containerquery's veranderen fundamenteel de manier waarop we bouwen responsieve componenten. In plaats van een globaal breekpuntsysteem dat elk onderdeel moet kennen en respecteren, wordt elk onderdeel autonoom en past zich aan de zijne aan context. Dit leidt tot beter onderhoudbare code, echt samenstelbare ontwerpsystemen en minder randgevallen die handmatig moeten worden beheerd.
Met browserondersteuning van meer dan 88% zijn containerquery's klaar voor implementatie productie vandaag. De beste manier om aan de slag te gaan en de componenten van de uw ontwerpsysteem die in meerdere contexten worden gebruikt – meestal kaart, lijstitem, media-objecten – en deze geleidelijk omzetten naar het nieuwe paradigma.







