CSS Container Queries: Skutečně citlivé komponenty
Responzivní design po léta znamenal: „přizpůsobit rozvržení výřezu“.
Komponentní karta s @media (max-width: 768px) ví, jak je široký
obrazovce, ale neví, kolik místa má ve skutečnosti k dispozici
kontextu. Vložte tuto kartu do úzkého postranního panelu a chová se, jako by byla
na mobilu, i když je obrazovka 27" desktopu. Vložte ji do hlavního obsahu
a chová se jako desktop, i když je tento kontejner užší než smartphone.
Le Kontejnerové dotazy CSS vyřešit tento problém v kořenu: součástka může reagovat na velikost vlastní nádobu, ne výřezu. S vynikající podporou prohlížeče88 % ve výchozím stavu 2025 (Chrome 105+, Firefox 110+, Safari 16+), tato technika je připravena k výrobě.
Co se naučíte
- Zásadní rozdíl mezi dotazy na média a dotazy na kontejner
- Jak definovat kontext kontejnmentu s
container-type - Syntaxe
@containerpro dotazy - Dotazy na velikost kontejneru: inline-size, block-size
- Dotazy stylu kontejneru: dotazy založené na uživatelských vlastnostech
- Pojmenované kontejnery pro hierarchické dotazy
- Jak integrovat kontejnerové dotazy do Angular, React a Vue
Problém s dotazy na média
Mediální dotazy se dotazují na vlastnosti výřez: šířka obrazovky, orientace, barevné schéma. To funguje, když rozložení a jednoduché a komponenta vždy zabírá předvídatelnou šířku. Ale v návrzích V moderních systémech se stejná součást znovu používá v radikálně odlišných kontextech:
- Produktová karta na domovské stránce (3 sloupce na počítači)
- Stejná karta na postranním panelu „související produkty“ (1 úzký sloupec)
- Stejná karta v režimu celé obrazovky (2 sloupce)
- Stejná karta na stránce vyhledávání (proměnná na základě aktivních filtrů)
U dotazů na média musíte předem znát kontext každého použití a psát selektory CSS pro konkrétní případy. S kontejnerovými dotazy se e autonomní: přizpůsobí se svému dostupnému prostoru.
Definujte kontejner
Chcete-li použít kontejnerové dotazy, prvním krokem je deklarovat, který prvek je
„kontejner“, který bude zpochybněn. Dělá se to s majetkem 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;
}
Jakmile položka má container-type, všichni jeho potomci
mohou používat @container dotaz na jeho rozměry.
Syntaxe @container
Syntaxe je totožná s dotazy na média, ale namísto dotazování na výřez dotaz na nejbližší kontejner s kontextem kontejnmentu:
.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 */
}
}
Pojmenované kontejnery: Hierarchické dotazy
Když máte vnořené kontejnery, můžete kontejnery pojmenovat pro dotaz a specific ancestor instead of closest:
<!-- 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; }
}
Dotazy ve stylu kontejneru: Skrytá funkce
Kromě dotazů na velikost podporují také dotazy kontejnerů styl dotazy: dotazy založené na hodnotách vlastních vlastností CSS kontejneru. Tato funkce, podporovaná v Chrome 111+ a Safari 17.4+, otevírá možnosti zcela nové, pokud jde o tématiku a varianty komponent.
/* 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 */
}
}
Tento vzor vám umožňuje komunikovat sémantický kontext z kontejneru do komponenta bez dalších CSS nebo JavaScript tříd, zachování zapouzdření.
Jednotky měření kontejneru: cqw, cqh, cqi, cqb
S dotazy na kontejner přicházejí také nové měrné jednotky týkající se kontejneru:
cqw: 1 % šířky nádobycqh: 1 % výšky nádobycqi: 1 % vložené velikosti kontejneru (= cqw pro rozložení LTR)cqb: 1 % velikosti bloku kontejneru (= cqh)cqmin: menší mezi cqi a cqbcqmax: větší mezi cqi a 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);
}
Kontejnerové dotazy v Angular, React a Vue
Angular: Container-Aware Components
/* 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;
}
Reagovat: Moduly CSS s dotazy na kontejner
/* 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>
);
}
Kontejnerové dotazy vs mediální dotazy: Kdy použít co
| Scénář | Optimální volba | Důvod |
|---|---|---|
| Globální rozložení stránky | Mediální dotazy | Rozložení závisí na výřezu |
| Opakovaně použitelné komponenty | Kontejnerové dotazy | Komponenta se musí přizpůsobit svému kontextu |
| Navrhněte systémové tokeny | Obě | Výřezy pro body přerušení, kontejnery pro varianty |
| Tmavý/světlý režim | Mediální dotazy | prefers-color-scheme a mediální funkce |
| Dynamický postranní panel | Kontejnerové dotazy | Obsah se vejde do otevřené/zavřené boční lišty |
| Styl tisku | Mediální dotazy | @media print je mediální dotaz |
Pattern Anti: Časté chyby při dotazech na kontejnery
Chyba č. 1: Samotné dotazování na kontejner
Prvek s container-type nemůže se sám sebe ptát
@container — musí jít o potomka, který je upraven.
Nikdy nedefinujte kontejner a pravidlo @container na stejné
volič.
Chyba č. 2: typ kontejneru: velikost bez definované výšky
container-type: size vyžaduje, aby kontejner měl velikost
definované jak na šířku, tak na výšku. Pokud použijete size na kontejneru
bez explicitní výšky, dotazy height e cqh
nebudou fungovat podle očekávání. USA inline-size ve většině
případů.
Další kroky
Nyní máte skutečně citlivé komponenty díky kontejnerovým dotazům. Další článek v sérii zkoumá rozhraní CSS Anchor Positioning API, které umožňuje implementovat popisky, rozevírací seznamy a vyskakovací okna bez jediného řádku JavaScriptu: další technika, která přibližuje CSS deklarativní síle, na kterou vývojáři čekali léta.
Závěry
CSS Container Queries zásadně mění způsob, jakým vytváříme responzivní komponenty. Namísto globálního systému bodů přerušení, který každý komponent musí znát a respektovat, každá složka se stává autonomní a přizpůsobuje se svému vlastnímu kontextu. To vede k lépe udržovatelnému kódu, skutečně složitelným návrhovým systémům a méně okrajových případů, které lze spravovat ručně.
S podporou prohlížeče vyšší než 88 % jsou kontejnerové dotazy připraveny k nasazení výroba dnes. Nejlepší způsob, jak začít a identifikovat komponenty váš návrhový systém, který se používá ve více kontextech – obvykle karta, položka seznamu, mediální objekt – a postupně je převádět do nového paradigmatu.







