Interogările de containere CSS încă câștigă acțiune și mulți dintre noi ne udă mâinile cu ele, chiar dacă este pentru mici experimente sau altceva. Au fost grozave, dar nu chiar pline, suport pentru browser — suficient pentru a justifica folosirea lor în unele proiecte, dar poate nu în măsura în care am putea fi tentați să începem să înlocuim interogări media din proiectele anterioare cu noi interogări strălucitoare privind dimensiunea containerului.
Cu siguranță sunt totuși la îndemână! De fapt, m-am confruntat deja cu câteva situații în care îmi doream foarte mult să ajung la ele, dar pur și simplu nu puteam depăși cerințele de asistență. Dacă aș fi putut să le folosesc, așa ar fi arătat în acele situații.
Toate demonstrațiile următoare vor fi vizualizate cel mai bine în Chrome sau Safari în momentul scrierii acestui articol. Firefox intenționează să sprijinul navei în versiunea 109.
Cazul 1: Grila cardului
Trebuia să te aștepți la asta, nu? Este un tipar atât de comun încât toți parcă ne întâlnim cu el la un moment dat. Dar adevărul este că interogările de dimensiunea containerului ar fi fost o economie imensă de timp pentru mine, cu un rezultat mai bun dacă aș fi putut să le folosesc peste interogări media standard.
Să presupunem că ați fost însărcinat să construiți această grilă de carduri cu cerința pe care fiecare card are nevoie pentru a-și păstra raportul de aspect 1:1:
E mai dur decât pare! Problema este că dimensionarea conținutului unei componente pe lățimea ferestrei de vizualizare vă lasă la mila modului în care componenta răspunde la fereastra - precum și a modului în care orice alte containere strămoși răspund la acesta. Dacă, de exemplu, doriți ca dimensiunea fontului unui titlu de card să se reducă atunci când cardul atinge o anumită dimensiune în linie, nu există nicio modalitate fiabilă de a face acest lucru.
Puteți seta dimensiunea fontului în vw
unități, presupun, dar componenta este încă legată de lățimea ferestrei de vizualizare a browserului. Și asta poate cauza probleme atunci când grila cardului este utilizată în alte contexte în care este posibil să nu aibă aceleași puncte de întrerupere.
În proiectul meu din lumea reală, am ajuns la o abordare JavaScript care ar:
- Ascultați un eveniment de redimensionare.
- Calculați lățimea fiecărei cărți.
- Adăugați o dimensiune de font în linie la fiecare card în funcție de lățimea acestuia.
- Modelați totul în interior folosind
em
de unități.
Pare multă muncă, nu? Dar este o soluție stabilă pentru a obține scalarea necesară pe diferite dimensiuni de ecran în diferite contexte.
Interogările de containere ar fi fost mult mai bune pentru că ne oferă unități de interogare container, la fel ca cqw
unitate. Probabil că îl înțelegi deja, dar 1cqw
este egal cu 1%
de lăţimea unui container. Avem și cqi
unitate care este o măsură a lățimii în linie a unui container și cqb
pentru lățimea blocului unui container. Deci, dacă avem un container pentru carduri, acesta este 500px
lat, a 50cqw
valoarea se calculează la 250px
.
Dacă aș fi putut folosi interogări de container în grila cardului, aș fi putut configura .card
componentă ca container:
.card {
container: card / size;
}
Atunci aș fi putut pune un înveliș interior cu padding
care scala la 10%
a .card
lățimea lui folosind cqw
unitate:
.card__inner {
padding: 10cqw;
}
Acesta este un mod frumos de a scala distanța dintre marginile cardului și conținutul acestuia în mod constant, indiferent de locul în care cardul este utilizat la orice lățime dată de vizualizare. Nu sunt necesare interogări media!
O altă idee? Utilizare cqw
unități pentru dimensiunea fontului conținutului interior, apoi aplicați umplutură em
Unități:
.card__inner {
font-size: 5cqw;
padding: 2em;
}
5cqw
este o valoare arbitrară - doar una pe care am stabilit-o. Căptușeala este încă egală cu 10cqw
din moment ce em
unitatea este relativă la .card__inner
marimea fontului!
Ai prins asta? The 2em
este relativ la 5cqw
dimensiunea fontului care este setată pe același recipient. Containerele funcționează diferit de ceea ce ne-am obișnuit, ca em
unitățile sunt relativ la aceleași elemente font-size value
. Dar ceea ce am observat rapid este că se referă unitățile de interogare a containerelor cel mai apropiat părinte care este și container.
De exemplu, 5cqw
nu scala pe baza .card
lățimea elementului în acest exemplu:
.card {
container: card / size;
container-name: card;
font-size: 5cqw;
}
Mai degrabă, se extinde la orice părinte cel mai apropiat care este definit ca un container. De aceea am înființat un .card__inner
împachetare.
Cazul 2: Aspect alternativ
Aveam nevoie de încă o componentă de card într-un proiect diferit. De data aceasta, aveam nevoie de card pentru a trece de la un aspect peisaj la un aspect portret... apoi înapoi la peisaj și din nou la portret pe măsură ce ecranul devine mai mic.
Am făcut treaba murdară de a face ca această componentă să treacă la portret la acele două intervale specifice de vizualizare (strigă sintaxă a intervalului de interogare media nouă!), dar din nou, problema este că este apoi blocat la interogările media setate pe el, părintele său și orice altceva care ar putea răspunde la lățimea ferestrei de vizualizare. Ne dorim ceva care să funcționeze în orice condiție, fără a ne îngrijora să ne întrebăm unde se va sparge conținutul!
Interogările privind containerele ar fi făcut acest lucru o briză, datorită @container
regulă:
.info-card {
container-type: inline-size;
container-name: info-card;
}
@container info-card (max-width: 500px) {
.info-card__inner {
flex-direction: column;
}
}
O singură interogare, fluiditate infinită:
Dar stai! Este ceva la care ai putea dori să fii atent. Mai exact, ar putea fi dificil să utilizați o interogare de container ca aceasta într-un sistem de proiectare bazat pe suport. De exemplu, aceasta .info-card
componenta ar putea conține componente secundare care se bazează pe recuzită pentru a-și schimba aspectul.
De ce e mare lucru? Aspectul portret al cardului poate necesita stilul alternativ, dar nu puteți schimba elementele de recuzită JavaScript cu CSS. Ca atare, riscați să duplicați stilurile necesare. De fapt m-am atins de asta și cum să o rezolvi într-un alt articol. Dacă trebuie să utilizați interogări container pentru o parte semnificativă a stilului dvs., atunci poate fi necesar să vă bazați întregul sistem de design în jurul lor, mai degrabă decât să încercați să le încadrați într-un sistem de design existent, care este greu de interogări media.
Cazul 3: lovituri SVG
Iată un alt model foarte comun pe care l-am folosit recent, în cazul în care interogările privind dimensiunea containerului ar fi dus la un produs mai lustruit. Să presupunem că aveți o pictogramă blocată cu un titlu:
Heading
Este destul de simplu să scalați pictograma cu dimensiunea titlului, chiar și fără interogări media. Problema, însă, este că SVG-urile stroke-width
ar putea deveni prea subțire pentru a fi observat atât de bine la o dimensiune mai mică și poate atrage prea multă atenție cu o lovitură super groasă la o dimensiune mai mare.
A trebuit să creez și să aplic clase pentru fiecare instanță de pictogramă pentru a-i determina dimensiunea și lățimea trazei. Este în regulă dacă pictograma este lângă un titlu care are un stil cu o dimensiune fixă a fontului, cred, dar nu este atât de grozav când lucrezi cu tipul fluid care se schimbă constant.
Dimensiunea fontului titlului se poate baza pe lățimea ferestrei de vizualizare, așa că pictograma SVG trebuie să se ajusteze în consecință unde funcționează cursa sa la orice dimensiune. Puteți face lățimea cursei în raport cu cea a titlului font-size
punându-l în interior em
unitati. Dar dacă aveți un anumit set de dimensiuni ale cursei de care trebuie să respectați, atunci acest lucru nu ar funcționa, deoarece altfel se scalează liniar - nu există nicio modalitate de a-l ajusta la un anumit stroke-width
valoare în anumite puncte fără a recurge la interogări media pe lățimea ferestrei de vizualizare.
Dar iată ce aș fi făcut dacă aș fi avut luxul de interogări de container la acel moment:
.icon {
container: icon / size;
width: 1em;
height: 1em;
}
.icon svg {
width: 100%;
height: 100%;
fill: none;
stroke: #ccc;
stroke-width: 0.8;
}
@container icon (max-width: 70px) {
.icon svg {
stroke-width: 1.5;
}
}
@container icon (max-width: 35px) {
.icon svg {
stroke-width: 3;
}
}
Comparați implementările și vedeți cum versiunea de interogare a containerului fixează cursa SVG-ului la lățimile specifice pe care le doresc, în funcție de lățimea containerului.
Bonus: alte tipuri de interogări privind dimensiunea containerului
OK, deci nu m-am întâlnit cu asta într-un proiect real. Dar, în timp ce căutam informații despre interogările containerului, am observat că există lucruri suplimentare pe care le putem interoga pe un container care sunt legate de dimensiunea sau dimensiunile fizice ale containerului.
Cele mai multe exemple pe care le-am văzut interogă width
, max-width
, și min-width
, height
, block-size
, și inline-size
așa cum am făcut pe parcursul acestui articol.
@container info-card (max-width: 500px) {
.info-card__inner {
flex-direction: column;
}
}
dar MDN subliniază încă două lucruri putem interoga împotriva. Unul este orientation
ceea ce are perfect sens pentru că îl folosim tot timpul în interogări media. Nu este diferit cu interogările container:
@media screen (orientation: landscape) {
.info-card__inner {
/* Style away! */
}
}
@container info-card (orientation: landscape) {
.info-card__inner {
/* Style away! */
}
}
Celălalt? este aspect-ratio
, crezi sau nu:
@container info-card (aspect-ratio: 3/2) {
.info-card__inner {
/* Style away! */
}
}
Iată o demonstrație editabilă pentru a te juca cu ambele exemple:
Nu am găsit încă un caz de utilizare bun pentru niciunul dintre acestea. Dacă ai idei sau simți că te-ar fi putut ajuta în proiectele tale, spune-mi în comentarii!