Moderní tvorba webových aplikací
O webu

CSS Container Queries – responsivní komponenty

Jak pomocí @container, container-type a container-name vytvářet komponenty, které se přizpůsobí velikosti svého rodiče místo viewportu.

16 minut

CSS Container Queries umožňují stylovat elementy podle velikosti jejich nadřazeného kontejneru místo celého viewportu. Zatímco media queries reagují na rozměry okna prohlížeče, container queries reagují na rozměry konkrétního prvku. Díky tomu lze vytvářet skutečně znovupoužitelné komponenty, které se přizpůsobí prostoru, ve kterém se nacházejí.

Proč container queries tak dlouho chyběly

Vývojáři po container queries volali přes deset let. Problém byl v tom, jak CSS počítá rozměry elementů. Šířka rodiče může záviset na obsahu potomků (u inline-block, float nebo flex/grid prvků) a zároveň obsah potomků může záviset na šířce rodiče – vzniká kruhová závislost. Pokud by se styly potomků měnily podle velikosti rodiče, jehož velikost závisí na potomcích, prohlížeč by se zacyklil v nekonečné smyčce přepočtů.

Řešením se stala vlastnost container-type, která zavádí CSS containment – kontejner přestane záviset na obsahu svých potomků při výpočtu velikosti. Tím se kruhová závislost přeruší. Prohlížeč nejdřív spočítá velikost kontejneru z jeho rodiče a teprve pak aplikuje container queries na potomky. Právě nutnost najít tento elegantní způsob, jak kruh rozbít, byla důvodem, proč implementace trvala tak dlouho.

Media queries vs. container queries

Klasické media queries fungují dobře pro celkový layout stránky, ale selhávají u komponent, které se mohou objevit v různých kontextech – v hlavním obsahu, v sidebaru nebo v modálním okně. Stejná komponenta může mít na stránce různou šířku, přestože viewport je stále stejný.

Container queries tento problém řeší. Komponenta se přizpůsobí velikosti svého kontejneru, ať je umístěna kamkoliv:

/* Media query – reaguje na viewport */
@media (min-width: 600px) {
  .card { display: flex; }
}

/* Container query – reaguje na kontejner */
@container (min-width: 400px) {
  .card { display: flex; }
}

To ale neznamená, že media queries přestávají mít smysl. Oba přístupy se vzájemně doplňují:

Media queriesContainer queries
Reaguje navelikost viewportuvelikost kontejneru
Vhodné procelkový layout stránky, navigace, globální přepínáníznovupoužitelné komponenty (karty, widgety, panely)
Typický breakpoint768px, 1024px (viewport)300px, 500px (kontejner)

V praxi se nejčastěji kombinují: media queries řídí layout stránky (sidebar ano/ne, počet sloupců), container queries řídí vzhled jednotlivých komponent uvnitř.

Definice kontejneru: container-type

Aby container queries fungovaly, musíme nejdřív označit rodičovský element jako kontejner. To se dělá vlastností container-type:

.wrapper {
  container-type: inline-size;
}

Možné hodnoty:

  • inline-size – kontejner pro dotazy na šířku (nejčastější volba)
  • size – kontejner pro dotazy na šířku i výšku (vyžaduje explicitní výšku)
  • normal – výchozí hodnota, kontejner pouze pro style queries

Nejčastěji se používá inline-size, protože umožňuje dotazovat se na šířku kontejneru a zároveň nechat výšku záviset na obsahu.

Pojmenování kontejneru: container-name

Kontejner lze pojmenovat pomocí container-name. Pojmenování je užitečné, pokud máme více vnořených kontejnerů a chceme cílit na konkrétní z nich:

.sidebar {
  container-type: inline-size;
  container-name: sidebar;
}

.main {
  container-type: inline-size;
  container-name: main-content;
}

@container sidebar (min-width: 300px) {
  .nav-item { display: flex; gap: .5rem; }
}

@container main-content (min-width: 600px) {
  .article { columns: 2; }
}

Název kontejneru rozlišuje velká a malá písmena (case-sensitive). Hodnota none je vyhrazená (zruší pojmenování). Názvy jako not, and nebo or sice technicky lze nastavit, ale v pravidlech @container by kolidovaly s logickými operátory.

Zkrácený zápis: container

Vlastnost container je zkrácený zápis kombinující název a typ, oddělené lomítkem:

/* Ekvivalent container-name: sidebar; container-type: inline-size; */
.sidebar {
  container: sidebar / inline-size;
}

Pravidlo @container

Samotné container queries se zapisují pomocí at-pravidla @container. Syntaxe je podobná media queries:

@container (min-width: 400px) {
  .card {
    display: flex;
    gap: 1rem;
  }
}

@container (max-width: 399px) {
  .card {
    display: block;
  }
}

Pokud není uvedeno jméno kontejneru, dotaz cílí na nejbližší nadřazený kontejner v DOM stromu.

Range syntax

Místo klasického min-width/max-width zápisu lze použít i novější range syntax s porovnávacími operátory:

/* Šířka kontejneru větší než 500px */
@container (width > 500px) {
  .card { flex-direction: row; }
}

/* Šířka kontejneru mezi 300px a 600px */
@container (300px <= width <= 600px) {
  .card { padding: 1rem; }
}

/* Šířka menší nebo rovna 400px */
@container (width <= 400px) {
  .card { flex-direction: column; }
}

Podmínky lze kombinovat pomocí and, ornot:

@container (width > 400px) and (width < 800px) {
  .card { padding: 1.5rem; }
}

Praktický příklad

Karta, která se přizpůsobí šířce kontejneru – v úzkém prostoru zobrazí obsah vertikálně, v širokém horizontálně:

<div class="card-wrapper">
  <div class="card">
    <img src="photo.jpg" alt="">
    <div class="card-body">
      <h3>Nadpis</h3>
      <p>Popis karty...</p>
    </div>
  </div>
</div>
.card-wrapper {
  container: card / inline-size;
}

.card {
  display: grid;
  gap: 1rem;
  border: 1px solid #e2e8f0;
  border-radius: .5rem;
  overflow: hidden;
}

.card img {
  width: 100%;
  aspect-ratio: 16/9;
  object-fit: cover;
}

@container card (min-width: 400px) {
  .card {
    grid-template-columns: 200px 1fr;
  }

  .card img {
    aspect-ratio: 1;
    height: 100%;
  }
}
Úzký kontejner:

Nadpis karty

Popis obsahu karty v úzkém prostoru.

Široký kontejner:

Nadpis karty

Popis obsahu karty v širokém prostoru.

Stejná komponenta se automaticky přizpůsobí podle toho, kolik místa má k disposici – bez ohledu na velikost okna prohlížeče.

Container query jednotky

Uvnitř kontejnerů jsou k disposici speciální jednotky relativní k rozměrům kontejneru:

JednotkaVýznam
cqw1 % šířky kontejneru
cqh1 % výšky kontejneru
cqi1 % inline rozměru kontejneru
cqb1 % block rozměru kontejneru
cqminmenší z cqicqb
cqmaxvětší z cqicqb
.card-wrapper {
  container-type: inline-size;
}

.card-title {
  font-size: clamp(1rem, 3cqi, 1.5rem);
}

.card-body {
  padding: 2cqi;
}

Tyto jednotky umožňují plynulé škálování velikosti textu a mezer v závislosti na kontejneru, podobně jako viewport jednotky (vw, vh), ale vázané na kontejner.

Style queries

Container queries nejsou omezeny jen na rozměry. Pomocí style queries lze dotazovat i CSS custom properties kontejneru:

.card-wrapper {
  --theme: light;
}

@container style(--theme: dark) {
  .card {
    background: #1e293b;
    color: #f1f5f9;
  }
}

Typické využití: rodičovská komponenta nastaví custom property (např. --variant: compact) a potomci na ni reagují bez nutnosti přidávat CSS třídy. Hodí se pro přepínání tmavého/světlého režimu, kompaktního/plného zobrazení nebo stavů jako --loading: true.

Style queries pro custom properties podporují Chrome, Edge a Safari. Podpora ve Firefoxu je v přípravě.

Jaké jednotky v @container?

V podmínkách @container se nejčastěji používají px, stejně jako u media queries. Je to rozumná volba – breakpointy kontejneru jsou konkrétní body, kdy se mění layout komponenty, a ty se nejlépe vyjádří v absolutních hodnotách:

/* px – nejběžnější a nejčitelnější */
@container (min-width: 400px) {
  .card { display: flex; }
}

/* em – počítá se vůči font-size kontejneru */
@container (min-width: 25em) {
  .card { display: flex; }
}

Použití em má výhodu v přístupnosti: jednotka em se v podmínkách @container počítá vůči font-size kontejneru. Pokud se velikost písma změní (např. uživatel si ji zvětší v prohlížeči), breakpoint se posune a komponenta přepne layout podle skutečné velikosti textu, ne podle pevné šířky v pixelech. Pro většinu projektů ale stačí px – jsou přehlednější a předvídatelnější. Jednotka rem v podmínkách @container funguje a dává smysl – poskytuje stabilní breakpoint odvozený od kořenového font-size, nezávisle na písmu kontejneru. Viewport jednotky (vh, vw) fungují také, ale nedávají smysl – ptáme se na velikost kontejneru, ale porovnáváme s viewportem. Procenta (%) specifikace v podmínkách nepodporuje – počítala by se vůči velikosti kontejneru, na kterou se právě ptáme, což je kruhový odkaz. Uvnitř pravidel (pro padding, font-size apod.) ale lze používat cokoliv včetně container query jednotek.

Container queries v Tailwindu

Tailwind CSS podporuje container queries. Ve versi 3 bylo nutné doinstalovat plugin @tailwindcss/container-queries, od Tailwindu 4 je podpora vestavěná. Kontejner se označí třídou @container a potomci používají prefix @ s breakpointem:

<div class="@container">
  <div class="block @md:flex gap-4">
    <img src="photo.jpg" class="w-full @md:w-48">
    <div>
      <h3>Nadpis</h3>
      <p>Popis karty...</p>
    </div>
  </div>
</div>

Tailwind nabízí tyto container breakpointy: @xs (320px), @sm (384px), @md (448px), @lg (512px), @xl (576px) a další. Pojmenovaný kontejner se vytvoří jako @container/sidebar a potomci na něj cílí jako @md/sidebar:flex.

Kdy použít container queries

Container queries jsou dnes doporučený přístup pro responsivní komponenty. Obecné pravidlo:

  • Media queries – pro celkový layout stránky (počet sloupců, zobrazení/skrytí sidebaru, navigace)
  • Container queries – pro cokoliv, co je komponenta určená k znovupoužití na různých místech stránky

Pokud komponenta žije vždy jen na jednom místě a její šířka je přímo svázaná s viewportem, media query stačí. Jakmile ale může skončit v sidebaru, v modálu nebo v jiném gridu, container query je lepší volba.

Výkon

Prohlížeč vykresluje stránku v několika fázích: nejdřív Style (spočítá, které CSS vlastnosti platí pro které elementy), pak Layout (vypočítá rozměry a posice), pak Paint (vykreslí pixely) a nakonec Composite (složí vrstvy dohromady). Media queries se vyhodnocují ve fázi Style, protože rozměry viewportu jsou známé předem. Container queries fungují jinak – prohlížeč zpracovává strom shora dolů: u každého kontejneru nejdřív spočítá jeho rozměry (Layout), pak vyhodnotí @container podmínky, nastyluje potomky a teprve pak je rozloží. Proto je nutný CSS containment – bez něj by velikost kontejneru mohla záviset na potomcích, kteří závisí na velikosti kontejneru.

Výkonnostně jsou container queries srovnatelné s media queries. Containment sice přidává krok navíc (opakované vyhodnocení stylů po layoutu kontejneru), ale zároveň omezuje rozsah přepočtů – prohlížeč ví, že změna uvnitř kontejneru nemůže ovlivnit layout venku, takže přepočítává jen podstrom daného kontejneru.

Potenciální problém nastává pouze při velkém množství vnořených kontejnerů (desítky úrovní zanoření), kde se náklady na přepočet sčítají. V běžných projektech s několika úrovněmi kontejnerů je dopad na výkon zanedbatelný.

Co nefunguje a omezení

Container queries mají několik omezení, která vyplývají z toho, jak CSS containment funguje:

  • Kontejner nemůže stylovat sám sebe – pravidla uvnitř @container se vztahují na potomky kontejneru, ne na kontejner samotný. Je potřeba mít vždy obalový element.
  • Nelze se dotazovat na výšku s inline-size – nejčastější container-type: inline-size umožňuje dotazy pouze na šířku. Pro dotazy na výšku je nutné container-type: size, které ale vyžaduje explicitně nastavenou výšku.
  • Kontejner nemůže záviset na obsahu – element s container-type: inline-size se chová, jako by měl contain: inline-size layout style. To znamená, že jeho šířka nemůže být určena obsahem (width: max-content nebude fungovat).
  • Nelze dotazovat libovolného předka – @container bez jména vždy cílí na nejbližší kontejner v DOM stromu. Pokud chcete přeskočit vnořený kontejner, musíte použít pojmenované kontejnery.
  • Žádné container queries pro display: contents – element s display: contents nemá vlastní box, a proto nemůže být kontejnerem.

Podpora v prohlížečích

Container queries (size) jsou od roku 2025 klasifikovány jako Baseline Widely Available. Baseline je iniciativa W3C a prohlížečových vendorů, která označuje webové funkce podle úrovně podpory. Rozlišují se dvě úrovně:

  • Newly Available – funkce funguje ve všech hlavních prohlížečích, ale teprve krátce
  • Widely Available – funkce funguje ve všech hlavních prohlížečích minimálně 30 měsíců, takže ji lze bezpečně používat i bez fallbacku

Container queries dosáhly Widely Available statusu, což znamená, že je bezpečné je používat v produkci:

  • Chrome – od verse 105 (srpen 2022)
  • Edge – od verse 105 (srpen 2022)
  • Safari – od verse 16 (září 2022)
  • Firefox – od verse 110 (únor 2023)

Container query jednotky (cqw, cqi atd.) mají stejnou úroveň podpory. Style queries pro custom properties mají podporu v Chromiu a Safari, ve Firefoxu zatím ne.

Odkazy

Co si myslíte o tomto článku?

Diskuse

Související články

CSS Anchor Positioning – posicování elementů relativně k jiným

Jak pomocí anchor-name, position-anchor a funkce anchor() posicovat elementy relativně k jiným bez JavaScriptu.

6 minut

CSS Stacking Context – jak funguje vrstvení elementů a z-index

Jak stacking context v CSS ovlivňuje z-index, co vytváří nový kontext vrstvení a jak řešit problémy s překrýváním elementů.

7 minut

Jeden sloupec fixní, druhý proměnlivý

Jak vytvořit dvousloupcové rozvržení, kde je jeden sloupec s pevnou šířkou a druhý se přizpůsobuje šířce okna.

6 minut

Převod sloupců na procenta

Jak převést fixní sloupcové rozložení na procenta, která se budou přizpůsobovat šířce okna.

3 minuty

Novinky e-mailem

Když budu mít něco opravdu zajímavého, můžu vám to poslat e-mailem

Přidej se k 500+ čtenářům
Jen kvalitní obsah
Žádný spam

Web jecas.cz píše Bohumil Jahoda, kontakt
Seznam všech článků · Témata · Zkratky
2013–2026