CSS Container Queries vinner fortfarande dragkraft och många av oss blir blöta av dem, även om det är för små experiment eller vad inte. De är jättebra, men inte riktigt fulla, webbläsarsupport — tillräckligt för att motivera att använda dem i vissa projekt, men kanske inte i den utsträckningen att vi kan frestas att börja ersätta mediafrågor från tidigare projekt med skinande nya frågor om containerstorlek.
Fast de är säkert praktiska! Jag har faktiskt redan stött på några situationer där jag verkligen ville nå dem men bara inte kunde övervinna supportkraven. Om jag hade kunnat använda dem så hade det sett ut så här i de situationerna.
Alla följande demos visas bäst i Chrome eller Safari när detta skrivs. Firefox planerar att fartygsstöd i version 109.
Fall 1: Kortrutnät
Du var väl tvungen att förvänta dig den här? Det är ett så vanligt mönster att vi alla verkar stöta på det någon gång. Men faktum är att frågor om behållarestorlek skulle ha varit en enorm tidsbesparande för mig med ett bättre resultat om jag hade kunnat använda dem över vanliga mediefrågor.
Låt oss säga att du har fått i uppdrag att bygga det här kortrutnätet med kravet att varje kort måste behålla sitt bildförhållande 1:1:
Det är tuffare än det ser ut! Problemet är att storleken på en komponents innehåll på visningsportens bredd överlåter dig på nåd av hur komponenten svarar på visningsporten – liksom hur andra förfaderbehållare reagerar på den. Om du till exempel vill att teckenstorleken på en kortrubrik ska minska när kortet träffar en viss inlinestorlek finns det inget tillförlitligt sätt att göra det.
Du kan ställa in teckenstorleken vw
enheter, antar jag, men komponenten är fortfarande bunden till webbläsarens visningsportbredd. Och det kan orsaka problem när kortrutnätet används på annat sätt i sammanhang som kanske inte har samma brytpunkter.
I mitt verkliga projekt landade jag på en JavaScript-metod som skulle:
- Lyssna efter en händelse som ändrar storlek.
- Beräkna bredden på varje kort.
- Lägg till en inline teckenstorlek till varje kort baserat på dess bredd.
- Style allt inuti med hjälp av
em
enheter.
Det verkar vara mycket jobb, eller hur? Men det är en stabil lösning för att få den skalning som krävs över olika skärmstorlekar i olika sammanhang.
Containerförfrågningar skulle ha varit så mycket bättre eftersom de ger oss containerfrågeenheter, så som cqw
enhet. Du förstår förmodligen redan, men 1cqw
är lika med 1%
av en containers bredd. Vi har också cqi
enhet som är ett mått på en containers inline bredd, och cqb
för en containers blockbredd. Så, om vi har en kortbehållare alltså 500px
bred, a 50cqw
värde beräknas till 250px
.
Om jag hade kunnat använda containerfrågor i mitt kortrutnät hade jag kunnat ställa in .card
komponent som en behållare:
.card {
container: card / size;
}
Då hade jag kunnat sätta ett inre omslag med padding
som skalar på 10%
av .card
's bredd med hjälp av cqw
enhet:
.card__inner {
padding: 10cqw;
}
Det är ett bra sätt att skala avståndet mellan kortets kanter och dess innehåll konsekvent oavsett var kortet används vid en given visningsportbredd. Inga mediafrågor krävs!
En annan idé? Använda sig av cqw
enheter för teckenstorleken på det inre innehållet, applicera sedan utfyllnad em
enheter:
.card__inner {
font-size: 5cqw;
padding: 2em;
}
5cqw
är ett godtyckligt värde - bara ett som jag nöjt mig med. Den stoppningen är fortfarande lika med 10cqw
eftersom em
enhet är i förhållande till .card__inner
textstorlek!
Har du fattat det? De 2em
är relativt till 5cqw
teckenstorlek som är inställd på samma behållare. Containers fungerar annorlunda än vad vi är vana vid, som em
enheter är relativa till samma elements font-size value
. Men vad jag snabbt märkte är att containerfrågeenheter relaterar till närmaste förälder som också är en container.
Till exempel, 5cqw
skalas inte baserat på .card
elementets bredd i detta exempel:
.card {
container: card / size;
container-name: card;
font-size: 5cqw;
}
Snarare skalas den till den närmaste föräldern som definieras som en behållare. Det är därför jag satte upp en .card__inner
omslag.
Fall 2: Alternerande layout
Jag behövde ännu en kortkomponent i ett annat projekt. Den här gången behövde jag kortet för att övergå från en liggande layout till en stående layout... sedan tillbaka till liggande och tillbaka till stående igen när skärmen blir mindre.
Jag gjorde det smutsiga arbetet med att få den här komponenten att gå till stående vid de två specifika visningsområdena (ropa ut till ny syntax för mediafrågeintervall!), men återigen, problemet är att det sedan är låst till mediefrågorna som ställts in på det, dess förälder och allt annat som kan svara på visningsportens bredd. Vi vill ha något som fungerar i alla skick utan att oroa oss för att undra var innehållet kommer att gå sönder!
Containerförfrågningar skulle ha gjort detta till en lek, tack vare @container
regel:
.info-card {
container-type: inline-size;
container-name: info-card;
}
@container info-card (max-width: 500px) {
.info-card__inner {
flex-direction: column;
}
}
En fråga, oändlig flytbarhet:
Men håll ut! Det finns något du kanske vill se upp med. Specifikt kan det vara svårt att använda en containerfråga som denna inom ett rekvisitabaserat designsystem. Till exempel detta .info-card
komponent kan innehålla underordnade komponenter som är beroende av rekvisita för att ändra sitt utseende.
Varför är det en stor grej? Kortets stående layout kan kräva den alternativa stilen men du kan inte ändra JavaScript-rekvisita med CSS. Som sådan riskerar du att duplicera de nödvändiga stilarna. Jag berörde faktiskt detta och hur man kan kringgå det i en annan artikel. Om du behöver använda containerförfrågningar för en betydande del av din styling, kan du behöva basera hela ditt designsystem kring dem istället för att försöka lägga in dem i ett befintligt designsystem som är tungt på mediefrågor.
Fall 3: SVG-slag
Här är ett annat supervanligt mönster jag nyligen har använt där frågor om behållarestorlek skulle ha resulterat i en mer polerad produkt. Säg att du har en ikon låst med en rubrik:
Heading
Det är ganska enkelt att skala ikonen med titelns storlek, även utan mediefrågor. Problemet är dock att SVG:erna stroke-width
kan bli för tunn för att uppmärksammas så väl i en mindre storlek, och kanske fånga för mycket uppmärksamhet med ett supertjockt slag i en större storlek.
Jag har varit tvungen att skapa och tillämpa klasser på varje ikoninstans för att bestämma dess storlek och streckbredd. Det är OK om ikonen är bredvid en rubrik som har en fast teckenstorlek, antar jag, men det är inte så bra när man arbetar med flytande typ som ständigt ändras.
Rubrikens teckensnittsstorlek kan baseras på visningsportens bredd, så SVG-ikonen måste anpassas efter var dess linje fungerar oavsett storlek. Du kan göra slagbredden i förhållande till rubrikens font-size
genom att sätta in den em
enheter. Men om du har en specifik uppsättning slagstorlekar som du behöver hålla dig till, så skulle det här inte fungera eftersom det annars skalas linjärt - det finns inget sätt att justera det till en specifik stroke-width
värde vid vissa punkter utan att tillgripa mediefrågor på visningsportens bredd.
Men här är vad jag skulle ha gjort om jag hade lyxen med containerfrågor vid den tiden:
.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;
}
}
Jämför implementeringarna och se hur behållarfrågaversionen fäster SVG:s linje till de specifika bredderna jag vill ha baserat på behållarens bredd.
Bonus: Andra typer av frågor om containerstorlek
OK, så jag har faktiskt inte stött på det här på ett riktigt projekt. Men när jag letade igenom information om containerförfrågningar, märkte jag att det finns ytterligare saker vi kan fråga på en container som är relaterade till containerns storlek eller fysiska dimensioner.
De flesta exempel jag har sett frågar efter width
, max-width
och min-width
, height
, block-size
och inline-size
som jag har gjort genom hela den här artikeln.
@container info-card (max-width: 500px) {
.info-card__inner {
flex-direction: column;
}
}
Men MDN beskriver ytterligare två saker vi kan fråga mot. En är orientation
vilket är helt vettigt eftersom vi använder det hela tiden i mediefrågor. Det är inte annorlunda med containerfrågor:
@media screen (orientation: landscape) {
.info-card__inner {
/* Style away! */
}
}
@container info-card (orientation: landscape) {
.info-card__inner {
/* Style away! */
}
}
Den andra? Dess aspect-ratio
, tro det eller ej:
@container info-card (aspect-ratio: 3/2) {
.info-card__inner {
/* Style away! */
}
}
Här är en redigerbar demo att leka med båda exemplen:
Jag har inte riktigt hittat ett bra användningsfall för någon av dessa än. Om du har några idéer eller känner att det kunde ha hjälpt dig i dina projekt, låt mig veta i kommentarerna!