Interogări de containere CSS: componente cu adevărat receptive
Ani de zile, designul responsive a însemnat: „adaptați aspectul la fereastra de vizualizare”.
Un card component cu @media (max-width: 768px) el știe cât de largă este
ecranul, dar nu știe cât spațiu are de fapt disponibil pe el
context. Pune cardul într-o bară laterală îngustă și se comportă ca și cum ar fi
pe mobil, chiar dacă ecranul este un desktop de 27". Pune-l în conținutul principal
și se comportă ca un desktop chiar dacă acel container este mai îngust decât un smartphone.
Le Interogări de containere CSS rezolvă această problemă la rădăcină: o componentă poate reacționa la dimensiunea container propriu, nu a fereastra de vizualizare. Cu suport superior pentru browser88% în perioada de referință 2025 (Chrome 105+, Firefox 110+, Safari 16+), această tehnică este gata de producție.
Ce vei învăța
- Diferența fundamentală dintre Interogările Media și Interogările Container
- Cum se definește un context de izolare cu
container-type - Sintaxa
@containerpentru interogări - Interogări privind dimensiunea containerului: dimensiune inline, dimensiune bloc
- Interogări în stil container: interogări bazate pe proprietăți personalizate
- Containere denumite pentru interogări ierarhice
- Cum se integrează interogările containerului în Angular, React și Vue
Problema cu interogările media
Interogările media interogează caracteristicile fereastra: lățimea a ecranului, orientarea, schema de culori. Acest lucru funcționează atunci când aspectul și simplu și o componentă ocupă întotdeauna o lățime previzibilă. Dar în desene sisteme moderne, aceeași componentă este reutilizată în contexte radical diferite:
- Un card de produs pe pagina de pornire (3 coloane pe desktop)
- Același card în bara laterală „produse înrudite” (1 coloană îngustă)
- Același card într-un mod de ecran complet (2 coloane)
- Același card pe pagina de căutare (variabilă în funcție de filtrele active)
Cu interogările media, trebuie să cunoașteți contextul fiecărei utilizări în avans și să scrieți selectoare CSS specifice cazului. Cu interogări de containere, e autonom: se adaptează la spațiul său disponibil.
Definiți un container
Pentru a utiliza interogări container, primul pas este să declarați ce element este
„container” care va fi pus la îndoială. Se face cu proprietate 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;
}
Odată ce un articol are container-type, toți urmașii săi
pot folosi @container pentru a-i interoga dimensiunile.
Sintaxa @container
Sintaxa este identică cu interogările media, dar în loc să interogheze fereastra de vizualizare, interogați cel mai apropiat container cu un context de reținere:
.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 */
}
}
Containere numite: Interogări ierarhice
Când aveți containere imbricate, puteți denumi containerele pentru a interoga a strămoș specific în loc de cel mai apropiat:
<!-- 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; }
}
Interogări privind stilul containerului: caracteristica ascunsă
Pe lângă interogările de dimensiune, sunt acceptate și interogările container stil interogări: interogări bazate pe valorile proprietăților personalizate CSS ale containerului. Această funcție, acceptată în Chrome 111+ și Safari 17.4+, deschide posibilități complet nou în ceea ce privește tematica și variantele componente.
/* 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 */
}
}
Acest model vă permite să comunicați contextul semantic de la container la componentă fără clase suplimentare CSS sau JavaScript, menținând încapsularea.
Unități de măsură ale containerului: cqw, cqh, cqi, cqb
Odată cu interogările de containere vin și noi unități de măsură legate de container:
cqw: 1% din lățimea recipientuluicqh: 1% din inaltimea recipientuluicqi: 1% din dimensiunea în linie a containerului (= cqw pentru aspectul LTR)cqb: 1% din dimensiunea blocului container (= cqh)cqmin: cu cât este mai mic între cqi și cqbcqmax: cu cât este mai mare între cqi și 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);
}
Interogări container în Angular, React și Vue
Angular: Componente pentru containere
/* 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;
}
Reacționează: module CSS cu interogări container
/* 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>
);
}
Interogări container vs interogări media: când să folosiți ce
| Scenariu | Alegerea optimă | Motiv |
|---|---|---|
| Aspect global de pagină | Interogări media | Aspectul depinde de fereastra de vizualizare |
| Componente reutilizabile | Interogări de containere | Componenta trebuie să se adapteze contextului său |
| Proiectați jetoane de sistem | ambele | Vizualizări pentru puncte de întrerupere, containere pentru variante |
| Modul întuneric/luminos | Interogări media | prefers-color-scheme și o caracteristică media |
| Bara laterală dinamică | Interogări de containere | Conținutul se încadrează în bara laterală deschisă/închisă |
| Imprimare stil | Interogări media | @media print este o interogare media |
Pattern Anti: greșeli frecvente cu interogările containerului
Greșeala nr. 1: Interogarea containerului în sine
Un element cu container-type el nu se poate întreba cu
@container — trebuie să fie un descendent care este modificat.
Nu definiți niciodată un container și o regulă @container pe aceeasi
selector.
Eroare #2: container-type: dimensiune fără înălțime definită
container-type: size necesită ca containerul să aibă o dimensiune
definite atât în lățime, cât și în înălțime. Dacă utilizați size pe un recipient
fără înălțime explicită, interogări height e cqh
nu vor funcționa conform așteptărilor. STATELE UNITE ALE AMERICII inline-size în majoritate
de cazuri.
Următorii pași
Acum aveți componente cu adevărat receptive datorită interogărilor containerului. Următorul articol din serie explorează API-ul CSS Anchor Positioning, care permite pentru a implementa sfaturi cu instrumente, meniuri derulante și popover fără o singură linie de JavaScript: o altă tehnică care aduce CSS mai aproape de puterea declarativă pe care dezvoltatorii o așteptau de ani de zile.
Concluzii
Interogările Container CSS schimbă fundamental modul în care construim componente receptive. În loc de un sistem global de puncte de întrerupere, fiecare componentă trebuie să cunoască și să respecte, fiecare componentă devine autonomă și se adaptează la ea context. Acest lucru duce la un cod mai ușor de întreținut, sisteme de design cu adevărat componabile și mai puține cazuri de gestionare manuală.
Cu ajutorul browserului de peste 88%, interogările containerului sunt gata pentru implementare producția de astăzi. Cel mai bun mod de a începe și de a identifica componentele sistemul dvs. de proiectare care sunt utilizate în mai multe contexte - de obicei card, articol din listă, obiect media — și să le convertească progresiv la noua paradigmă.







