Zapytania kontenera CSS: naprawdę responsywne komponenty
Przez lata projektowanie responsywne oznaczało: „dopasowanie układu do rzutni”.
Karta składowa z @media (max-width: 768px) wie, jaka jest szeroka
ekranie, ale nie wie, ile tak naprawdę ma wolnego miejsca na swoim
kontekst. Umieść tę kartę na wąskim pasku bocznym, a będzie się zachowywać tak, jakby była
na urządzeniu mobilnym, nawet jeśli ekran jest komputerem stacjonarnym o przekątnej 27 cali. Umieść go w głównej treści
i zachowuje się jak komputer stacjonarny, nawet jeśli jest węższy od smartfona.
Le Zapytania dotyczące kontenerów CSS rozwiąż ten problem u podstaw: komponent może reagować na rozmiar własny kontener, nie rzutni. Z doskonałą obsługą przeglądarek88% w scenariuszu bazowym na 2025 r (Chrome 105+, Firefox 110+, Safari 16+), ta technika jest gotowa do produkcji.
Czego się nauczysz
- Podstawowa różnica między zapytaniami o media a zapytaniami o kontenery
- Jak zdefiniować kontekst przechowywania za pomocą
container-type - Składnia
@containerdla zapytań - Zapytania o rozmiar kontenera: rozmiar wbudowany, rozmiar bloku
- Zapytania w stylu kontenera: zapytania oparte na niestandardowych właściwościach
- Nazwane kontenery dla zapytań hierarchicznych
- Jak zintegrować zapytania kontenerowe z Angularem, Reactem i Vue
Problem z zapytaniami o media
Zapytania o media sprawdzają charakterystykę rzutnia: szerokość ekranu, orientacji, schematu kolorów. Działa to, gdy układ i proste, a komponent zawsze zajmuje przewidywalną szerokość. Ale w projektach nowoczesnych systemach ten sam komponent jest ponownie wykorzystywany w radykalnie różnych kontekstach:
- Karta produktu na stronie głównej (3 kolumny na pulpicie)
- Ta sama karta na pasku bocznym „produkty powiązane” (1 wąska kolumna)
- Ta sama karta w trybie pełnoekranowym (2 kolumny)
- Ta sama karta na stronie wyszukiwania (zmienna na podstawie aktywnych filtrów)
W przypadku zapytań o media musisz wcześniej poznać kontekst każdego użycia i napisać Selektory CSS specyficzne dla przypadku. W przypadku zapytań kontenerowych metoda e autonomiczny: dostosowuje się do dostępnej przestrzeni.
Zdefiniuj kontener
Aby użyć zapytań kontenerowych, pierwszym krokiem jest zadeklarowanie, który element jest
„kontener”, który będzie kwestionowany. Robi się to za pomocą własności 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;
}
Gdy przedmiot ma container-type, wszyscy jego potomkowie
mogą korzystać @container zapytać o jego wymiary.
Składnia @kontener
Składnia jest identyczna jak w przypadku zapytań o media, ale zamiast odpytywać rzutnię, zapytaj najbliższy kontener z kontekstem przechowywania:
.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 */
}
}
Nazwane kontenery: zapytania hierarchiczne
Jeśli masz zagnieżdżone kontenery, możesz nazwać kontenery, do których będą kierowane zapytania: a konkretny przodek zamiast najbliższego:
<!-- 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; }
}
Zapytania w stylu kontenera: ukryta funkcja
Oprócz zapytań o rozmiar obsługiwane są również zapytania kontenerowe styl zapytania: zapytania oparte na wartościach niestandardowych właściwości CSS kontenera. Ta funkcja, obsługiwana w Chrome 111+ i Safari 17.4+, otwiera nowe możliwości zupełnie nowy pod względem tematycznym i wariantów komponentów.
/* 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 */
}
}
Ten wzorzec umożliwia przekazywanie kontekstu semantycznego z kontenera do komponent bez dodatkowych klas CSS lub JavaScript, zachowując enkapsulację.
Jednostki miary kontenera: cqw, cqh, cqi, cqb
W przypadku zapytań o kontenery pojawiają się także nowe jednostki miary odnoszące się do kontenera:
cqw: 1% szerokości pojemnikacqh: 1% wysokości pojemnikacqi: 1% rozmiaru wbudowanego kontenera (= cqw dla układu LTR)cqb: 1% wielkości bloku kontenera (= cqh)cqmin: mniejszy pomiędzy cqi i cqbcqmax: większy pomiędzy 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);
}
Zapytania kontenerowe w Angular, React i Vue
Angular: Komponenty obsługujące kontenery
/* 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;
}
Reaguj: moduły CSS z zapytaniami kontenerowymi
/* 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>
);
}
Zapytania dotyczące kontenerów a zapytania o media: kiedy czego używać
| Scenariusz | Optymalny wybór | Powód |
|---|---|---|
| Globalny układ strony | Zapytania o media | Układ zależy od rzutni |
| Komponenty wielokrotnego użytku | Zapytania dotyczące kontenerów | Komponent musi dostosować się do kontekstu |
| Zaprojektuj tokeny systemowe | Obydwa | Rzutnie dla punktów przerwania, kontenery dla wariantów |
| Tryb ciemny/jasny | Zapytania o media | preferuje schemat kolorów i funkcję multimedialną |
| Dynamiczny pasek boczny | Zapytania dotyczące kontenerów | Treść mieści się na otwartym/zamkniętym pasku bocznym |
| Stylizacja z nadrukiem | Zapytania o media | @media print to zapytanie o media |
Wzorzec anty: typowe błędy w zapytaniach dotyczących kontenerów
Błąd nr 1: Samo wysyłanie zapytań do kontenerów
Element z container-type nie może zadawać sobie pytań
@container — musi to być zmodyfikowany element potomny.
Nigdy nie definiuj kontenera i reguły @container na tym samym
selektor.
Błąd nr 2: typ kontenera: rozmiar bez zdefiniowanej wysokości
container-type: size wymaga, aby pojemnik miał rozmiar
zdefiniowane zarówno pod względem szerokości, jak i wysokości. Jeśli używasz size na pojemniku
bez wyraźnej wysokości, zapytania height e cqh
nie będą działać zgodnie z oczekiwaniami. USA inline-size w większości
przypadków.
Następne kroki
Dzięki zapytaniom kontenerowym masz teraz naprawdę responsywne komponenty. Następny artykuł z tej serii omawia interfejs API pozycjonowania kotwic CSS, który umożliwia aby zaimplementować podpowiedzi, menu rozwijane i wyskakujące okienka bez ani jednej linii kodu JavaScript: kolejna technika, która przybliża CSS do deklaratywnej mocy, na którą czekali programiści przez lata.
Wnioski
Zapytania kontenerowe CSS zasadniczo zmieniają sposób, w jaki budujemy responsywne komponenty. Zamiast globalnego systemu punktów przerwania, w którym każdy komponent trzeba znać i szanować, każdy element staje się autonomiczny i dostosowuje się do własnych kontekst. Prowadzi to do łatwiejszego w utrzymaniu kodu i naprawdę komponowalnych systemów projektowych i mniej przypadków brzegowych, którymi można zarządzać ręcznie.
Przy obsłudze przeglądarek powyżej 88% zapytania kontenerowe są gotowe do wdrożenia produkcja dzisiaj. Najlepszym sposobem na rozpoczęcie i identyfikację komponentów Twój system projektowania, które są używane w wielu kontekstach — zazwyczaj karta, element listy, obiekt medialny – i stopniowo konwertuj je do nowego paradygmatu.







