CSS container queries: responsive dizainas

Kodėl media queries nebepakanka šiuolaikiniam web dizainui

Prisimenu, kai prieš kokius dešimt metų pirmą kartą susidūriau su responsive dizainu. Tuomet media queries atrodė kaip magija – galėjai keisti puslapio išvaizdą priklausomai nuo ekrano dydžio. Bet laikas bėgo, projektai darėsi sudėtingesni, o komponentinis požiūris tapo standartu. Ir štai čia prasidėjo problemos.

Įsivaizduokite situaciją: kuriate card komponentą, kuris turėtų atrodyti gerai tiek šoniniame sidebar’e, tiek pagrindiniame content’o plote, tiek modal lange. Su tradiciniais media queries tai virsta košmaru – jūsų komponentas „žino” tik apie viewport’o dydį, bet neturi supratimo apie savo tėvinį konteinerį. Tai tarsi bandymas vairuoti automobilį žiūrint tik į tolimą horizontą, bet nematant kelio prieš save.

Kas tie container queries ir kaip jie veikia

Container queries – tai CSS funkcionalumas, leidžiantis stilizuoti elementus ne pagal viewport’o dydį, o pagal jų tėvinio elemento (konteinerio) matmenis. Skamba paprasta, bet tai keičia visą žaidimą.

Pagrindinis principas toks: pirmiausia nurodote, kuris elementas yra konteineris, tada rašote užklausas, kurios reaguoja į to konteinerio dydį. Štai paprasčiausias pavyzdys:

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

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

Čia sakome, kad `.sidebar` yra konteineris, o kai jis platesnis nei 400px, viduje esantis `.card` turėtų pereiti į grid išdėstymą. Gražu tai, kad tas pats card’as gali atrodyti visiškai kitaip kitame konteineryje – pavyzdžiui, siauresniame modal’e.

Praktinis panaudojimas: nuo teorijos prie realių projektų

Pradėjus dirbti su container queries, pirmiausia reikia suprasti `container-type` savybę. Ji turi tris pagrindines reikšmes:

**size** – konteineris stebi tiek pločio, tiek aukščio pokyčius. Skamba gerai, bet atsargiai – tai gali sukelti layout’o problemų, nes elementas negali turėti intrinsic aukščio.

**inline-size** – stebi tik inline ašies dydį (dažniausiai plotį). Tai saugiausia ir dažniausiai naudojama opcija.

**normal** – įprastas elgesys, jokio stebėjimo.

Realus pavyzdys iš projekto, kurį dariau praėjusiais metais. Turėjome produktų sąrašą, kuris galėjo būti rodomas trijose vietose: pagrindinėje puslapyje (platus), šoniniame meniu (siauras) ir paieškos rezultatuose (vidutinis). Anksčiau tai buvo trys skirtingi komponentai arba košmaras su media queries ir papildomomis klasėmis.

.product-container {
  container-type: inline-size;
  container-name: products;
}

.product-card {
  padding: 1rem;
}

@container products (min-width: 300px) {
  .product-card {
    display: flex;
    gap: 1rem;
  }
  
  .product-image {
    width: 100px;
    height: 100px;
  }
}

@container products (min-width: 500px) {
  .product-card {
    display: grid;
    grid-template-columns: 150px 1fr;
    gap: 2rem;
  }
  
  .product-details {
    display: grid;
    grid-template-columns: 1fr 1fr;
  }
}

Dabar vienas komponentas prisitaiko prie bet kokio konteinerio. Kodas švaresnis, palaikymas paprastesnis, o dizaineriai laimingesni.

Container query units: nauji matavimo vienetai

Kartu su container queries atsirado ir nauji CSS vienetai. Jie veikia panašiai kaip viewport vienetai (vw, vh), tik orientuoti į konteinerį:

– **cqw** – 1% konteinerio pločio
– **cqh** – 1% konteinerio aukščio
– **cqi** – 1% konteinerio inline dydžio
– **cqb** – 1% konteinerio block dydžio
– **cqmin** – mažesnė iš cqi ar cqb
– **cqmax** – didesnė iš cqi ar cqb

Šie vienetai ypač naudingi tipografijai. Užuot naudoję fiksuotus šrifto dydžius ar viewport-based clamp() funkcijas, galite tiesiogiai susieti tekstą su konteinerio dydžiu:

.card-title {
  font-size: clamp(1.2rem, 4cqi, 2.5rem);
  line-height: 1.2;
}

Eksperimentavau su šiais vienetais kuriant dashboard komponentus – rezultatai įspūdingi. Grafikai, lentelės ir statistikos kortelės dabar skalėjasi organiškai, nepriklausomai nuo to, ar vartotojas žiūri pilną ekraną ar mažą widget’ą.

Suderinamumas ir fallback strategijos

Gerai, dabar realybės patikrinimas. Container queries palaiko visi pagrindiniai naršyklės, bet ne visos versijos. Chrome 105+, Safari 16+, Firefox 110+. Jei jūsų auditorija naudoja senesnes naršykles, reikia plano B.

Pirmiausia, naudokite `@supports` užklausą:

@supports not (container-type: inline-size) {
  /* Fallback stiliai senoms naršyklėms */
  .card {
    display: block;
  }
  
  @media (min-width: 768px) {
    .card {
      display: grid;
      grid-template-columns: 1fr 2fr;
    }
  }
}

Kita strategija – progressive enhancement. Pradėkite nuo bazinių stilių, kurie veikia visur, tada pridėkite container queries kaip patobulinimą:

/* Baziniai stiliai – veikia visur */
.product-card {
  display: block;
  padding: 1rem;
}

/* Patobulinimas su container queries */
@container (min-width: 400px) {
  .product-card {
    display: flex;
    gap: 1.5rem;
  }
}

Projektuose, kur būtina plati parama, galite naudoti PostCSS pluginą, kuris transformuoja container queries į media queries su papildomomis klasėmis. Ne idealu, bet veikia.

Įdomesni panaudojimo scenarijai

Kai įvaldote pagrindus, prasideda tikrasis smagumas. Štai keletas nestandartinių būdų, kaip naudoju container queries.

**Dinamiškos formos**. Turiu registracijos formą, kuri gali būti rodoma modal’e, šoniniame panel’e arba pilname puslapyje. Su container queries forma automatiškai prisitaiko – nuo vieno stulpelio iki trijų, keičiasi input’ų dydžiai, label’ų pozicijos:

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

.form-grid {
  display: grid;
  gap: 1rem;
}

@container (min-width: 500px) {
  .form-grid {
    grid-template-columns: repeat(2, 1fr);
  }
}

@container (min-width: 800px) {
  .form-grid {
    grid-template-columns: repeat(3, 1fr);
  }
  
  .form-field--full {
    grid-column: 1 / -1;
  }
}

**Adaptyvūs navigacijos meniu**. Vietoj hamburger meniu, kuris atsiranda tam tikrame viewport’o dydyje, galite turėti navigaciją, kuri prisitaiko pagal turimą vietą. Jei konteineris siauras – kompaktiška versija, jei platus – pilna navigacija su ikonėlėmis ir tekstais.

**Responsive data vizualizacijos**. Dirbau su projektu, kur turėjome daug grafikų dashboard’e. Container queries leido kiekvienam grafikui turėti savo „responsive” logiką – mažame konteineryje rodo supaprastintą versiją, dideliame – visą informaciją su legend’omis ir papildomomis ašimis.

Dažniausios klaidos ir kaip jų išvengti

Per pastaruosius metus, integruojant container queries į įvairius projektus, pastebėjau kelias tipines klaidas, kurias daro daugelis (įskaitant mane patį pradžioje).

**Klaida #1: Konteinerio ir turinio maišymas**. Negalite taikyti container queries tam pačiam elementui, kurį padarėte konteineriu. Tai neveiks:

/* BLOGAI */
.card {
  container-type: inline-size;
}

@container (min-width: 400px) {
  .card { /* Tai neveiks! */
    padding: 2rem;
  }
}

Teisingas būdas – stilizuoti vaikines elementus arba turėti atskirą wrapper’į.

**Klaida #2: Užmiršti apie containment**. Kai nustatote `container-type: size`, elementas negali turėti natūralaus aukščio pagal turinį. Tai gali sukelti netikėtų layout’o problemų. Dažniausiai norite `inline-size`.

**Klaida #3: Per daug įdėtinių konteinerių**. Techniškai galite turėti konteinerius konteineriuose, bet tai greitai tampa sunku valdyti. Laikykitės paprastos hierarchijos – vienas ar du lygiai maksimum.

**Klaida #4: Ignoruoti performance**. Container queries reikalauja, kad naršyklė stebėtų elementų dydžius. Jei turite šimtus konteinerių puslapyje, tai gali paveikti našumą. Būkite selektyvūs – padarykite konteineriais tik tuos elementus, kuriems tai tikrai reikia.

Kaip container queries keičia komponentų kūrimo filosofiją

Didžiausias container queries poveikis nėra techninis – tai konceptualus pokytis. Anksčiau kūrėme komponentus mąstydami apie puslapį kaip visumą. Dabar galime kurti tikrai nepriklausomus, konteksto-agnostiškus komponentus.

Pavyzdžiui, jūsų komponentų bibliotekoje gali būti „Card” komponentas, kuris tiesiog veikia – nesvarbu, kur jį įdedate. Jis pats „žino”, kaip atrodyti siauram konteineryje ir kaip – plačiam. Dizaineriai gali eksperimentuoti su layout’ais nesikreipdami į developerius dėl papildomų media queries.

Tai ypač svarbu komandose, naudojančiose design systems. Komponentai tampa tikrai universalūs. Vienas Card komponentas veikia marketing puslapyje, admin panel’yje, mobile app’e (per WebView), email’uose (na, gal ne email’uose, bet supratote mintį).

Praktinis patarimas: pradėkite dokumentuoti savo komponentus ne tik su API aprašymais, bet ir su container requirements. Pavyzdžiui: „Šis komponentas optimizuotas konteineriams nuo 280px iki 800px pločio. Mažesniuose konteineriuose kai kurios funkcijos gali būti paslėptos.”

Kitas aspektas – testai. Dabar testavimas tampa įdomesnis. Vietoj to, kad testuotumėte komponentus skirtinguose viewport’uose, testuojate juos skirtinguose konteineriuose. Storybook su container queries tampa dar galingesnis įrankis – galite vizualiai pamatyti, kaip komponentas atrodo įvairiuose kontekstuose.

Į priekį: container queries kaip naujas standartas

Žiūrint į ateitį, container queries nėra tiesiog „nice to have” funkcija – tai tampa būtinu įrankiu šiuolaikiniam web developmentui. Jau dabar matau, kaip nauji framework’ai ir bibliotekos integruoja container queries į savo core funkcionalumą.

Tailwind CSS, pavyzdžiui, jau turi container queries palaikymą per `@tailwindcss/container-queries` pluginą. React komponentų bibliotekos pradeda naudoti container queries kaip default’inį responsive mechanizmą. Tai rodo, kad industrija juda teisinga kryptimi.

Mano rekomendacija: jei dar nenaudojate container queries, pradėkite eksperimentuoti dabar. Nebūtina perrašyti viso projekto – pradėkite nuo vieno komponento. Sukurkite card komponentą su container queries, pamatykite, kaip jis veikia, kokias problemas išsprendžia. Paskui pamažu išplėskite į kitus komponentus.

Svarbu suprasti, kad container queries nepakeičia media queries – jie juos papildo. Vis dar naudosite media queries globaliniams layout’o pokyčiams, tipografijos sistemoms, color schemes. Bet komponentų lygmenyje container queries tampa pirmuoju pasirinkimu.

Galutinė mintis: web developmentas nuolat evoliucionuoja, ir container queries yra viena iš tų retų funkcijų, kuri tikrai keičia kaip mes mąstome apie responsive dizainą. Tai ne tik naujas CSS feature’as – tai naujas būdas kurti lankstesnius, moduliškesnius ir lengviau prižiūrimus web projektus. Ir tai, mano nuomone, yra tikrai įdomu.

Daugiau

Kaip naudojant viešą Wi-Fi išlikti saugiam jungiantis prie paskyrų ir atliekant mokėjimus