Zapytania kontenerowe CSS wciąż zyskują na popularności i wielu z nas ma z nimi ręce, nawet jeśli chodzi o małe eksperymenty lub cokolwiek innego. Mają świetne, ale nie do końca pełne, obsługa przeglądarki — wystarczająco, aby uzasadnić ich użycie w niektórych projektach, ale może nie w takim stopniu, w którym moglibyśmy pokusić się o wymianę zapytania o media z poprzednich projektów dzięki nowym, błyszczącym zapytaniom o rozmiar kontenera.
Z pewnością są jednak przydatne! W rzeczywistości spotkałem się już z kilkoma sytuacjami, w których naprawdę chciałem po nie sięgnąć, ale po prostu nie mogłem spełnić wymagań dotyczących wsparcia. Gdybym mógł je wykorzystać, tak by to wyglądało w tamtych sytuacjach.
Wszystkie poniższe wersje demonstracyjne najlepiej będzie oglądać w przeglądarce Chrome lub Safari w chwili pisania tego tekstu. Firefox planuje wsparcie statku w wersji 109.
Przypadek 1: Siatka kart
W pewnym sensie musiałeś się tego spodziewać, prawda? Jest to tak powszechny wzorzec, że wydaje się, że każdy z nas w pewnym momencie go napotkał. Ale faktem jest, że zapytania o rozmiar kontenera byłyby dla mnie ogromną oszczędnością czasu i lepszym wynikiem, gdybym mógł ich używać zamiast standardowych zapytań o media.
Załóżmy, że otrzymałeś zadanie zbudowania tej siatki kart z wymaganiem, aby każda karta zachowała proporcje 1:1:
Jest twardszy niż się wydaje! Problem polega na tym, że ustalanie rozmiaru zawartości komponentu na podstawie szerokości rzutni sprawia, że jesteś zdany na łaskę tego, jak komponent zareaguje na rzutnię — a także sposób, w jaki reagują na niego wszelkie inne kontenery nadrzędne. Jeśli na przykład chcesz zmniejszyć rozmiar czcionki nagłówka karty, gdy karta osiągnie określony rozmiar w tekście, nie ma na to niezawodnego sposobu.
Możesz ustawić rozmiar czcionki w vw
jednostek, jak sądzę, ale komponent jest nadal powiązany z szerokością okna przeglądarki. A to może powodować problemy, gdy siatka kart jest używana w innych kontekstach, które mogą nie mieć tych samych punktów przerwania.
W moim prawdziwym projekcie zdecydowałem się na podejście JavaScript, które:
- Posłuchaj zdarzenia zmiany rozmiaru.
- Oblicz szerokość każdej karty.
- Dodaj wewnętrzny rozmiar czcionki do każdej karty na podstawie jej szerokości.
- Stylizuj wszystko w środku za pomocą
em
jednostek.
Wydaje się dużo pracy, prawda? Ale jest to stabilne rozwiązanie, aby uzyskać wymagane skalowanie na różnych rozmiarach ekranu w różnych kontekstach.
Zapytania kontenerowe byłyby o wiele lepsze, ponieważ zapewniają nam jednostki zapytania kontenera, tak jak cqw
jednostka. Pewnie już to rozumiesz, ale 1cqw
jest równe 1%
szerokości kontenera. Mamy również cqi
jednostka, która jest miarą wewnętrznej szerokości kontenera i cqb
dla szerokości bloku kontenera. Tak więc, jeśli mamy pojemnik na karty, to znaczy 500px
szeroki, A 50cqw
wartość oblicza się 250px
.
Gdybym mógł używać zapytań kontenerowych w mojej siatce kart, mógłbym skonfigurować .card
komponent jako kontener:
.card {
container: card / size;
}
Wtedy mógłbym ustawić wewnętrzne opakowanie padding
to skala w 10%
ukończenia .card
szerokość za pomocą cqw
jednostka:
.card__inner {
padding: 10cqw;
}
To dobry sposób na spójne skalowanie odstępów między krawędziami karty i jej zawartością, bez względu na to, gdzie karta jest używana przy danej szerokości widocznego obszaru. Zapytania o media nie są wymagane!
Inny pomysł? Posługiwać się cqw
jednostki dla rozmiaru czcionki wewnętrznej zawartości, a następnie zastosuj dopełnienie em
jednostki:
.card__inner {
font-size: 5cqw;
padding: 2em;
}
5cqw
jest wartością arbitralną — taką, na której się zdecydowałem. To wypełnienie jest nadal równe 10cqw
ponieważ em
jednostka jest względna .card__inner
rozmiar czcionki!
Złapałeś to? The 2em
jest względem 5cqw
ustawiony rozmiar czcionki na tym samym pojemniku. Kontenery działają inaczej niż to, do czego jesteśmy przyzwyczajeni, jak np em
jednostki są względne względem tego samego elementu font-size value
. Ale szybko zauważyłem, że jednostki zapytań kontenerów odnoszą się do najbliższy rodzic, który jest również kontenerem.
Na przykład, 5cqw
nie skaluje się w oparciu o .card
szerokość elementu w tym przykładzie:
.card {
container: card / size;
container-name: card;
font-size: 5cqw;
}
Zamiast tego skaluje się do dowolnego najbliższego elementu nadrzędnego, który jest zdefiniowany jako kontener. Dlatego założyłem tzw .card__inner
obwoluta.
Przypadek 2: Naprzemienny układ
Potrzebowałem jeszcze jednego elementu karty w innym projekcie. Tym razem potrzebowałem karty, aby przejść z układu poziomego do układu pionowego… następnie z powrotem do układu poziomego iz powrotem do układu pionowego, gdy ekran się zmniejszy.
Wykonałem brudną robotę, zmieniając ten komponent w portret w tych dwóch określonych zakresach rzutni (krzyczeć do nowa składnia zakresu zapytań o media!), ale znowu problem polega na tym, że jest on następnie zablokowany dla ustawionych na nim zapytań o media, jego rodzica i wszystkiego innego, co może odpowiadać na szerokość widocznego obszaru. Chcemy czegoś, co działa w każdych warunkach, nie martwiąc się o to, gdzie zawartość się zepsuje!
Zapytania o kontenery ułatwiłyby to zadanie dzięki @container
reguła:
.info-card {
container-type: inline-size;
container-name: info-card;
}
@container info-card (max-width: 500px) {
.info-card__inner {
flex-direction: column;
}
}
Jedno zapytanie, nieskończona płynność:
Ale trzymaj się! Jest coś, na co możesz chcieć uważać. W szczególności użycie takiego zapytania kontenera w systemie projektowania opartym na rekwizytach może być trudne. Na przykład to .info-card
komponent może zawierać komponenty potomne, których wygląd zależy od rekwizytów.
Dlaczego to wielka sprawa? Układ pionowy karty może wymagać alternatywnego stylu, ale nie można zmienić rekwizytów JavaScript za pomocą CSS. W związku z tym ryzykujesz powielenie wymaganych stylów. Właściwie dotknąłem tego i jak to obejść w innym artykule. Jeśli potrzebujesz użyć zapytań kontenerowych dla znacznej części swojego stylu, być może będziesz musiał oprzeć na nich cały system projektowy, zamiast próbować wcisnąć je do istniejącego systemu projektowego, który jest obciążony zapytaniami o media.
Przypadek 3: obrysy SVG
Oto kolejny bardzo powszechny wzorzec, którego ostatnio użyłem, w którym zapytania o rozmiar kontenera skutkowałyby bardziej dopracowanym produktem. Załóżmy, że masz zamkniętą ikonę z nagłówkiem:
Heading
Skalowanie ikony za pomocą rozmiaru tytułu jest dość proste, nawet bez zapytań o media. Problem polega jednak na tym, że pliki SVG stroke-width
może stać się zbyt chudy, aby można go było tak dobrze zauważyć w mniejszym rozmiarze, i być może przykuć zbyt wiele uwagi super grubym pociągnięciem w większym rozmiarze.
Musiałem utworzyć i zastosować klasy do każdej instancji ikony, aby określić jej rozmiar i szerokość obrysu. To jest OK, jeśli ikona znajduje się obok nagłówka, który jest stylizowany na stały rozmiar czcionki, jak sądzę, ale nie jest tak dobrze, gdy pracuje się z płynnym typem, który ciągle się zmienia.
Rozmiar czcionki nagłówka może być oparty na szerokości widocznego obszaru, więc ikona SVG musi być odpowiednio dostosowana tam, gdzie jej obrys działa w dowolnym rozmiarze. Możesz ustawić szerokość obrysu w stosunku do nagłówka font-size
poprzez ustawienie go em
jednostki. Ale jeśli masz określony zestaw rozmiarów obrysu, którego musisz się trzymać, to nie zadziała, ponieważ w przeciwnym razie skaluje się liniowo — nie ma sposobu, aby dostosować go do określonego stroke-width
wartości w określonych punktach bez uciekania się do zapytań o media dotyczących szerokości widocznego obszaru.
Ale oto, co bym zrobił, gdybym miał luksus zapytań o kontenery w tamtym czasie:
.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;
}
}
Porównaj implementacje i zobacz, jak wersja zapytania kontenera przyciąga obrys SVG do określonych szerokości, które chcę na podstawie szerokości kontenera.
Bonus: inne typy zapytań o rozmiar kontenera
OK, więc nie spotkałem się z tym w prawdziwym projekcie. Ale kiedy przeglądałem informacje na temat zapytań o kontenery, zauważyłem, że istnieją dodatkowe rzeczy, które możemy zapytać o kontener, które są związane z rozmiarem kontenera lub wymiarami fizycznymi.
Większość przykładów, które widziałem, dotyczy zapytania width
, max-width
, min-width
, height
, block-size
, inline-size
tak jak robiłem przez cały ten artykuł.
@container info-card (max-width: 500px) {
.info-card__inner {
flex-direction: column;
}
}
Ale MDN przedstawia jeszcze dwie rzeczy możemy zapytać przeciwko. Jeden jest orientation
co ma sens, ponieważ używamy go cały czas w zapytaniach o media. Nie inaczej jest w przypadku zapytań kontenerowych:
@media screen (orientation: landscape) {
.info-card__inner {
/* Style away! */
}
}
@container info-card (orientation: landscape) {
.info-card__inner {
/* Style away! */
}
}
Inny? Jego aspect-ratio
, Uwierz lub nie:
@container info-card (aspect-ratio: 3/2) {
.info-card__inner {
/* Style away! */
}
}
Oto edytowalne demo do zabawy z obydwoma przykładami:
Nie znalazłem jeszcze dobrego zastosowania dla żadnego z nich. Jeśli masz jakieś pomysły lub czujesz, że mogłoby to pomóc w twoich projektach, daj mi znać w komentarzach!