Zapytania kontenerowe a zapytania mediów: decyzje dotyczące strony i komponentów
Dowiedz się, kiedy warto użyć zapytania mediowego, a kiedy lepiej sprawdzi się zapytanie kontenera, dzięki przykładom karty, panelu sterowania i jednostki, które umożliwiają dostosowanie ponownie używalnych komponentów.
Źródła: Container Queries vs Media Queries: How Modern CSS Changes Responsive Design
Najlepsze rozwiązania responsywne w CSS nadal opierają się na jednym parametrze: szerokości okna przeglądarki. Działa to dobrze dla całej strony, ale sprawia problemy przy komponentach wielokrotnie używanych, ponieważ karta wyświetlana w pasku bocznym i ta sama karta w szerokiej kolumnie głównej mają dokładnie tę samą przestrzeń widoku, choć dysponują zupełnie różną ilością miejsca. Ten przewodnik pokazuje, w jaki sposób zapytania kontenerowe mogą zamknąć tę luki, gdzie zapytania mediów pozostają lepszym narzędziem, oraz jak połączyć oba te podejścia z jednostkami płynnymi, tworząc responsywne systemy, którymi można się kierować.
Klasyczna zasada oparta na przestrzeni widoku wygląda tak: gdy szerokość okna spadnie poniżej określonego progu, karta układa swój content pionowo.
@media (max-width: 768px) {
.card {
flex-direction: column;
}
}
Nic tu nie jest zepsute. Słabość leży w koncepcji: reguła uczy się, jak szeroki jest okno, ale nigdy nie bierze pod uwagę szerokości karty. W małej demonstracji te wartości idą w parze; w aplikacji pełnej siatek, pasków bocznych i paneli rozchodzą się od siebie, a właśnie ta luka powoduje błędy w układzie. Zapytania kontenera pozwalają komponentowi zapytać „ile miejsca faktycznie mam?”, zamiast „jak szeroki jest ekran?”.
Dlaczego punkt przerwania widoku myli kartę wielokrotnie używalną
Weźmy prostą kartę produktu: obrazek obok bloku tekstu zawierającego tytuł, krótki opis i wezwanie do działania. Składnia jest tu podzielona na dwa fragmenty, ale to jeden element.
<article class="product-card">
<img src="product.jpg" alt="Product">
<div class="product-info">
<h2>Wireless Headphones</h2>
<p>Noise cancellation with 30-hour battery life.</p>
<button>Buy now</button>
</div>
</article>
Pierwsza faza stylizacji zazwyczaj umieszcza obrazek i tekst obok siebie za pomocą flexbox, a następnie dodaje punkt przerwania widoku, aby na małych ekranach umieścić je jedno pod drugim.
.product-card {
display: flex;
gap: 1rem;
}
@media (max-width: 768px) {
.product-card {
flex-direction: column;
}
}
Wszystko wydaje się w porządku, dopóki karta nie jest ponownie używana. Na szerokiej stronie desktopowej jest mnóstwo przestrzeni poziomej, więc układ obok siebie wygląda dobrze.
Desktop page
┌───────────────────────────────────────────┐
│ │
│ Product Card │
│ ┌──────────┐ ┌─────────────────────┐ │
│ │ Image │ │ Product information │ │
│ └──────────┘ └─────────────────────┘ │
│ │
└───────────────────────────────────────────┘
Gdy ta sama karta zostanie umieszczona w wąskiej pasku bocznym, potrzebuje układu warstwowego, mimo że okno nadal ma rozmiar desktopowy.
┌───────────────┐
│ │
│ Sidebar │
│ │
│ ┌───────────┐ │
│ │ Image │ │
│ ├───────────┤ │
│ │ Info │ │
│ └───────────┘ │
│ │
└───────────────┘
Gdy umieści się kilka takich kart w jednym rzędzie na panelu sterowania, każda z nich otrzymuje inną część szerokości w zależności od swojej kolumny.
┌───────────────────────────────────────────┐
│ ┌─────────────┐ ┌──────────────────────┐ │
│ │ Card │ │ Card │ │
│ └─────────────┘ └──────────────────────┘ │
└───────────────────────────────────────────┘
Trzy różne umiejscowienia, trzy różne szerokości, jeden niezmieniony obszar widoku. Zasada oparta na rozmiarze okna nie potrafi ich odróżnić, więc karta w pasku bocznym pozostaje ciasna.
Czym naprawdę są dobre zapytania mediów
Zapytania mediowe oceniają właściwości środowiska, w którym wyświetlana jest strona: wymiary obszaru widoku, orientację, układ kolorów, typ wskaźnika, ustawienia dotyczące ograniczenia ruchu itp. Zapytanie dotyczące szerokości to najczęstszy przypadek.
@media (max-width: 768px) {
...
}
Przepływ informacji jest prosty: przeglądarka mierzy obszar widoku, sprawdza, czy zapytanie pasuje, a następnie układ reaguje.
Viewport
↓
Media Query
↓
Layout changes
Dlatego zapytania mediowe stanowią odpowiedni narzędzie do podejmowania decyzji, które faktycznie dotyczą całej strony. Typowym przykładem jest struktura z dwoma kolumnami i paskiem bocznym o stałej szerokości:
.page-layout {
display: grid;
grid-template-columns: 1fr 300px;
}
Poniżej określonej szerokości okna struktura zmienia się na jedną kolumnę:
@media (max-width: 900px) {
.page-layout {
grid-template-columns: 1fr;
}
}
To jest właściwe wykorzystanie zapytania mediowego: to, czy strona ma miejsce na pasek boczny, rzeczywiście jest kwestią obszaru widoku. Problemy pojawiają się, gdy ten sam mechanizm decyduje o tym, jak poszczególne komponenty układają swoje elementy wewnętrzne.
Jak działają zapytania kontenerów
Zapytanie kontenera umożliwia elementowi reagowanie na rozmiar przodka, który wyraźnie oznaczyłeś jako kontener zapytania. Jego konfiguracja wymaga dwóch kroków. Najpierw należy zadeklarować kontener:
.card-container {
container-type: inline-size;
}
Wartość inline-size informuje przeglądarkę, że potomki mogą pytać o wymiar wierszowy kontenera, który to jest jego szerokość w trybach pisania poziomego. Następnie należy napisać regułę dotyczącą tego kontenera:
@container (max-width: 500px) {
.product-card {
flex-direction: column;
}
}
Informacje przepływają teraz z kontenera, a nie z okna:
Container
↓
Container Query
↓
Component layout
Karta już nie przejmuje się tym, czy użytkownik korzysta z telefonu, czy z dużego monitora; reaguje na przestrzeń, którą daje jej rodzic.
Jeden szczegół, który sprawia problemy
Zapytanie kontenera stylizuje potomków kontenera, a nigdy samego kontenera. Dlatego przykłady zawsze łączą element otaczający (.card-container, .card-wrapper) z elementem wewnętrznym (.product-card). Jeśli umieścisz container-type w elemencie .product-card, a następnie użyjesz zapytania, aby zmienić jego własną wartość flex-direction, nic się nie wydarzy. Traktuj element otaczający i komponent jako odrębne elementy.
Drugi szczegół: mechanizm inline-size oznacza, że szerokość kontenera nie może być już wyliczana na podstawie jego zawartości. Kontener, który jest dzieckiem na poziomie bloku w standardowym układzie, funkcjonuje bez problemów, ponieważ jego szerokość pochodzi od rodzica. Kontener, który polega na skalowaniu do odpowiedniej wielkości, takie jak element typu inline-block lub element umieszczony absolutnie bez wyraźnej szerokości, może zmniejszyć się do szerokości zero po zastosowaniu tego mechanizmu.
Szerokość widoku przeglądarki versus szerokość komponentu
Różnica ta staje się widoczna w panelu sterowania z szeroką główną kolumną i węższą kolumną boczną:
.dashboard {
display: grid;
grid-template-columns: 2fr 1fr;
gap: 1rem;
}
Załóżmy okno o szerokości 1440px. Zasada oparta na widoku przeglądarki dla karty wyglądałaby w ten sposób:
@media (max-width: 768px) {
.card {
flex-direction: column;
}
}
W takim oknie ta zasada nigdy się nie sprawdza. Tymczasem karta znajdująca się w węższej kolumnie może mieć szerokość zaledwie około 350px. Zapytanie mediowe bierze pod uwagę tylko jedną wartość:
Viewport = 1440px
Karta znajduje się razem z inną:
Component width = 350px
Tylko druga liczba opisuje rzeczywiste warunki karty, a tylko zapytanie kontenera może na to odpowiedzieć.
Minimalna konfiguracja zapytania kontenera
Implementacja jest prosta. Oznacz element otaczający jako kontener:
.card-wrapper {
container-type: inline-size;
}
Ustaw grid z dwoma kolumnami dla karty, gdy jej kontener ma co najmniej 600px szerokości:
@container (min-width: 600px) {
.product-card {
display: grid;
grid-template-columns: 200px 1fr;
}
}
W razie potrzeby użyj prostego układu blokowego poniżej:
@container (max-width: 599px) {
.product-card {
display: block;
}
}
W markupie wystarcza tylko element otaczający kartę:
<div class="card-wrapper">
<article class="product-card">
...
</article>
</div>
Rozkład karty pochodzi teraz od jej kontenera, więc przeniesienie otoczenia do innej kolumny automatycznie tworzy odpowiedni układ. Należy zauważyć, że obie reguły używają wartości min-width: 600px oraz max-width: 599px; przy użyciu ułamkowych szerokości kontener może mieć wartość pomiędzy tymi granicami. Nowsza składnia zakresów, @container (width >= 600px) oraz @container (width < 600px), eliminuje tę luki i zasługuje na preferencję w nowym kodzie.
Dlaczego to pasuje do architektury opartej na komponentach
Zapytania kontenerowe są ważniejsze niż typowa nowa funkcjonalność CSS, ponieważ nowoczesne interfejsy użytkownika są budowane z elementów wielokrotnego użycia – czy to komponentów frameworków takich jak React, Vue czy Angular, komponentów Web bez frameworku, czy elementów składowych wspólnego systemu projektowego. Żaden z tych elementów nie powinien musieć wiedzieć, w której części strony się znajduje. Weźmy na przykład element user-card. Może być wyświetlany w głównej obszarze treści:
<main>
<user-card></user-card>
</main>
Może być również wyświetlany w sekcji bocznej:
<aside>
<user-card></user-card>
</aside>
Albo może być powtarzany w siatce panelu sterowania:
<div class="dashboard-grid">
<user-card></user-card>
<user-card></user-card>
<user-card></user-card>
</div>
Ustalanie wartości punktu przerwania widoku w sposób sztywny w tym komponencie zakłada coś, czego nie ma możliwości zweryfikowania:
@media (max-width: 768px) {
...
}
Liczba 768 nie mówi nic o rzeczywistym kontekście komponentu. Zapytanie kontenera oferuje lepszą strukturę: przy tak dużym dostępnym przestrzeni należy zastosować ten układ. Jeśli twoje komponenty są elementami budulcowymi niezależnymi od konkretnego frameworka, omówienie miejsca, w którym powinna znajdować się granica frameworka w wielokrotnie używalnej strukturze interfejsu stanowi przydatne uzupełnienie tej koncepcji.
Pozwolenie karcie profilu na dostosowanie się do otoczenia
Oto kompaktowa karta profilu, która umieszcza awatar obok imienia i roli:
.profile-card {
display: flex;
gap: 1rem;
align-items: center;
}
Jego otoczka staje się kontenerem zapytania:
.profile-container {
container-type: inline-size;
}
Gdy szerokość tego kontenera wynosi 400 px lub mniej, karta układa swoją zawartość w formie stosu i centruje ją:
@container (max-width: 400px) {
.profile-card {
flex-direction: column;
text-align: center;
}
}
W przestronnym kontenerze awatar znajduje się obok tekstu:
┌──────────────────────────────────────┐
│ [Avatar] John Smith │
│ Senior Developer │
└──────────────────────────────────────┘
W trudnej sytuacji ten sam komponent przestawia się pionowo:
┌──────────────────┐
│ │
│ [Avatar] │
│ │
│ John Smith │
│ Senior Developer │
│ │
└──────────────────┘
Brak obserwatora zmian rozmiaru, brak drugiej wersji „kompaktowej”, brak klasy włączanej przez stronę nadrzędną.
Zapytania mediowe wciąż są potrzebne
Zapytania kontenera nie zastępują zapytań mediowych; odpowiadają na inne pytania. Oto szybki sposób uporządkowania często występujących decyzji:
- Zamykanie głównej nawigacji: zapytanie mediowe.
- Usuwanie bocznej pasku na poziomie strony: zapytanie mediowe.
- Zmiana układu karty między poziomym a pionowym: zapytanie kontenera.
- Przystosowanie komponentu wielokrotnego użytku do jego miejsca: zapytanie kontenera.
- Dostosowywanie typografii na całej stronie: zapytanie mediowe.
- Pozwolenie widgetowi na panelu kontrolnego na reagowanie na szerokość kolumny: zapytanie kontenera.
- Zmiana całej struktury aplikacji na inny układ: zapytanie mediowe.
Model mentalny: decyzje globalne i decyzje komponentów
Najjaśniejszy sposób podziału zadań polega na rozdzieleniu tego, co decyduje strona, od tego, co decyduje każdy komponent.
Zapytania mediowe dotyczą przeglądarki
Pytanie stojące za zapytaniem mediowym brzmi:
"What is the viewport doing?"
Są one odpowiednie do:
- Struktury strony
- Nawigacji
- Globalnego odstępu między elementami
- Globalnej typografii
- Głównych zmian w układzie
Zapytania kontenera dotyczą otoczenia komponentu
Pytanie stojące za zapytaniem kontenera brzmi:
"What is my component's environment doing?"
Są one odpowiednie do:
- Kart
- Widgetów
- Paneli
- Komponentów interfejsu użytkownika wielokrotnie używalnych
- Modułów panelu sterowania
- Komponentów systemu projektowego
Dostosowywanie rozmiarów za pomocą jednostek zapytań kontenera
Zapytania kontenerów to nie tylko bloki warunkowe. CSS definiuje również jednostki długości względem najbliższego kontenera zapytania, dzięki czemu wartości mogą się skalować w sposób ciągły, zamiast skakać przy określonych punktach przerwania:
.title {
font-size: 5cqi;
}
Tutaj cqi oznacza jeden procent rozmiaru wierszowego kontenera, więc 5cqi to pięć procent jego szerokości. Pełny zestaw jednostek:
cqw → container width
cqh → container height
cqi → container inline size
cqb → container block size
cqmin → smaller container dimension
cqmax → larger container dimension
Powszechnym wzorcem jest otoczenie jednostki kontenera funkcją clamp(), aby wartość skalowała się wraz z kontenerem, ale nigdy nie wychodziła poza rozsądny zakres:
.card-title {
font-size: clamp(1rem, 4cqi, 2rem);
}
Tytuł teraz skaluje się zgodnie z przestrzenią komponentu, a nie okna, co uniemożliwia wyrażenie takich jednostek widoku jak vw. Istnieją dwie uwagi. Jeśli element nie ma kontenera typu query, te jednostki przechodzą na mniejsze jednostki widoku, więc nadal będą dostarczać wartość, choć nie tę, której oczekiwaliśmy. Ponadto ustawienie dolnej i górnej granicy dla rem w funkcji clamp(), jak opisano powyżej, ma znaczenie dla dostępności: rozmiar czcionki determinowany wyłącznie szerokością kontenera nie reaguje na ustawienia rozmiaru tekstu użytkownika.
Nazewnictwo kontenerów w większych aplikacjach
Dla małej strony wystarczy anonimowy kontener:
.container {
container-type: inline-size;
}
Gdy kontenery są nawzajem zawarte, zwykłe reguły @container pasują do najbliższego kontenera-nadkażdącego, który może nie być tym, którego szukasz. Skrót container pozwala nadać kontenerowi nazwę wraz z jego typem:
.dashboard {
container: dashboard / inline-size;
}
Następnie reguły mogą bezpośrednio odnosić się do tego kontenera:
@container dashboard (min-width: 700px) {
.widget {
grid-template-columns: 1fr 1fr;
}
}
Porównaj warunek bez nazwy:
@container (min-width: 700px)
z warunkiem o nazwie:
@container dashboard (min-width: 700px)
Wersja z nazwą jasno określa intencję i nadal funkcjonuje, nawet jeśli ktoś później doda kolejny kontener między panel sterowania a widgetem.
Rozważnie wybieraj granice kontenerów
Zapytania kontenerowe są potężne, ale to nie jest powód, by dodawać tę deklarację do każdego elementu:
container-type: inline-size;
Każdy kontener stosuje układ, styl oraz ograniczenia rozmiaru w formie wartości inline-size, co wpływa na sposób określania rozmiaru danego elementu; dlatego kontenery powinny wyznaczać jasne granice komponentów, zamiast być rozrzuconymi wszędzie. Rozważmy panel sterowania zawierający w sobie widgety:
<section class="dashboard">
<article class="widget">
<div class="widget-content">
...
</div>
</article>
</section>
Rozsądnym rozwiązaniem jest uczynienie z tego panelu sterowania nazwanego kontenera:
.dashboard {
container: dashboard / inline-size;
}
i pozwolenie każdemu widgetowi na reagowanie na niego. Zasada brzmi nie „używaj zapytań kontenerowych wszędzie”, lecz „używaj ich tam, gdzie zachowanie zależy od dostępnej przestrzeni”.
Zastępowanie punktów przerwania typu breakpoint stack punktami przerwania opartymi na treści
Wiele plików stylów zawiera taką strukturę punktów przerwania widoku:
@media (max-width: 1200px) {
...
}
@media (max-width: 1024px) {
...
}@media (max-width: 900px) {
...
}@media (max-width: 768px) {
...
}@media (max-width: 640px) {
...
}@media (max-width: 480px) {
...
}
Czasami taka struktura jest uzasadniona. Często wskazuje to na to, że komponenty zostały zaprojektowane w oparciu o szerokość urządzenia, a nie o ich własną zawartość. Zapytania kontenerowe skłaniają nas do innego pytania. Zamiast „którego punktu przerwania zwykle używa zespół?”, zadajmy sobie pytanie: „przy jakiej szerokości ten komponent przestaje wyglądać dobrze?”. Odpowiedź daje nam punkt przerwania oparty na zawartości:
@container (max-width: 420px) {
.card {
flex-direction: column;
}
}
Żadna wartość 420px nie odpowiada konkretnemu telefonowi; to po prostu szerokość, przy której karta kończy się przestrzenią. Punkty przerwania wybrane w ten sposób przetrwają zmiany w układzie oraz nowe urządzenia.
Projektowanie komponentów niezależnych od pozycjonowania
Zapytania kontenerowe pomagają również zespołom tworzyć naprawdę niezależne komponenty, których zachowanie jest przewidywalne bez względu na to, gdzie są renderowane. Wyobraźmy sobie grupę przycisków z systemu projektowego. Może ona znajdować się wewnątrz formularza na stronie:
Page
└── Form
└── Button Group
wewnątrz karty na panelu sterowania:
Dashboard
└── Card
└── Button Group
lub wewnątrz karty w pasku bocznym:
Sidebar
└── Card
└── Button Group
Przeglądarka wyświetla się identycznie we wszystkich trzech przypadkach; przestrzeń jest inna. Dzięki zapytaniom kontenerowym grupa dostosowuje się bez konieczności znajomości struktury nad nią.
Wzorzec responsywnej karty wielokrotnego użycia
Oto kompletny wzorzec, który można od razu zastosować. Znaczniki otaczają kartę elementem kontenera; ponownie HTML jest pokazany w dwóch kolejnych częściach.
<div class="card-container">
<article class="card">
<img src="image.jpg" alt="">
<div class="card-content">
<h2>Performance Dashboard</h2>
<p>
Monitor application performance and infrastructure metrics.
</p>
<a href="#">View dashboard</a>
</div>
</article>
</div>
Element otaczający jest deklarowany jako kontener:
.card-container {
container-type: inline-size;
}
Karta zaczyna się jako siatka jednej kolumny z obrazem w proporcjach 16:9. Gdy jej kontener osiągnie szerokość 600px, przechodzi na układ z stałą kolumną obrazu obok treści i sprawia, że obraz staje się kwadratowy. Zasady są zapisane bez przerw między nimi, co jest poprawnym CSS, ale warto je przeformatować po wklejeniu do bazy kodu.
.card {
display: grid;
gap: 1rem;
}.card img {
width: 100%;
aspect-ratio: 16 / 9;
object-fit: cover;
}@container (min-width: 600px) {
.card {
grid-template-columns: 200px 1fr;
align-items: center;
} .card img {
aspect-ratio: 1;
}
}
Zwróć uwagę, czego ta szablona stylów nie zawiera:
@media (max-width: 768px)
Karta nigdy nie bierze pod uwagę obszaru wyświetlania. Wszystkie jej decyzje opierają się na kontenerze.
Łączenie zapytań kontenera z siatką automatycznie dostosowującą się
Zapytania kontenera doskonale łączą się ze siatką, która sama określa liczbę kolumn:
.dashboard {
display: grid;
grid-template-columns:
repeat(auto-fit, minmax(280px, 1fr));
gap: 1rem;
}
Użycie repeat(auto-fit, minmax(280px, 1fr)) sprawia, że przeglądarka tworzy tyle kolumn o szerokości co najmniej 280px, ile pozwala wiersz, i rozciąga je, aby wypełnić pozostałą przestrzeń. Każdy element otrzymuje wtedy własny kontener:
.widget-container {
container-type: inline-size;
}
i przechodzi na dwukolumnową strukturę wewnętrzną, gdy jego miejsce jest wystarczająco szerokie:
@container (min-width: 500px) {
.widget {
grid-template-columns: 1fr 1fr;
}
}
Panel sterowania dostosowuje się do szerokości w bardzo dużym zakresie bez konieczności użycia punktów przerwania widoku: siatka określa, ile przestrzeni otrzyma każdy element, a każdy element decyduje, jak ją wykorzystać.
Layout responsywny to również kwestia użyteczności
To, że element pasuje na ekranie, nie oznacza automatycznie, że jest łatwy w użyciu. Rząd przycisków, który technicznie mieści się na wąskiej karcie, może nadal być zbyt ciasny i utrudniać klikanie. Zapytanie kontenera może ułożyć te przyciski jeden pod drugim i rozciągnąć je na pełną szerokość, gdy karta jest wąska (zasada ta jest przedstawiona w dwóch fragmentach kodu):
@container (max-width: 350px) {
.actions {
flex-direction: column;
}
.actions button {
width: 100%;
}
}
Przyciski ułożone w pełnej szerokości zapewniają większe obszary do dotknięcia i zmniejszają ryzyko przypadkowych kliknięć. Ten sam mechanizm może być zastosowany do tekstu – jego rozmiar powinien się zmieniać w granicach możliwości w zależności od szerokości komponentu:
.card-title {
font-size: clamp(1rem, 4cqi, 1.75rem);
}
Konkretne wartości mają mniejsze znaczenie niż zasada, na której się opierają: behawior responsywny powinien odzwierciedlać warunki, w których faktycznie jest używany komponent, a nie przypuszczenia oparte na rozmiarze okna.
Gdzie zapytania mediowe pozostają właściwym wyborem
Zapytania kontenerów nie są automatycznie lepszą opcją. Globalna nawigacja to wyraźny przypadek, w którym należy użyć zapytania mediowego – ukrywanie pełnego menu i pokazywanie przycisku menu to decyzja dotycząca struktury strony (ta zasada jest również podzielona na dwie części):
@media (max-width: 900px) {
.navigation {
display: none;
}
.menu-button {
display: block;
}
}
Ustawienia użytkownika to zupełnie inna kategoria. Zmniejszenie szybkości animacji dla osób, które poprosiły swój system operacyjny o mniej ruchu, nie ma nic wspólnego z żadnym kontenerem:
@media (prefers-reduced-motion: reduce) {
* {
animation-duration: 0.01ms;
animation-iteration-count: 1;
}
}
To jest ustawienie środowiskowe, które może odczytać tylko zapytanie mediów. Celem nie jest eliminacja zapytań mediów, lecz tylko zaprzestanie ich używania do podejmowania decyzji dotyczących komponentów.
Trójwarstwowe podejście do responsywnego CSS
W aplikacjach opartych na komponentach pomocne jest myślenie o stylizacji responsywnej w trzech warstwach.
Warstwa 1: responsywność globalna za pomocą zapytań mediów
Zapytania mediów zajmują się kwestiami dotyczącymi całej strony:
Page layout
Navigation
Global typography
Major structural changes
Application shell
Warstwa 2: responsywność komponentów za pomocą zapytań kontenera
Zapytania kontenera zajmują się wewnętrznym układem samodzielnych elementów:
Cards
Widgets
Panels
Reusable components
Design-system components
Dashboard modules
Warstwa 3: płynne zachowanie za pomocą funkcji i jednostek
Gdy nie jest potrzebny sztywny punkt przerwania, wartości mogą się skalować w sposób ciągły dzięki nowoczesnym funkcjom i jednostkom:
clamp()
min()
max()
minmax()
cqi
cqw
Naprzимер, nagłówek może rosnąć wraz ze swoim kontenerem pomiędzy dwoma ustalonymi granicami:
.heading {
font-size: clamp(1.5rem, 3cqi, 3rem);
}
Wspólnie warstwy te tworzą system, a nie zbiór pojedynczych rozwiązań dotyczących punktów przerwania.
Prawdziwa zmiana to to, kto podejmuje decyzję
Kuszące jest ujmowanie zapytań do kontenerów jako „zapytań mediowych dla elementów”. Jest to technicznie dokładne, ale pomija sedno sprawy. Zmienia się model odpowiedzialności. W tradycyjnym responsywnym CSS to strona faktycznie określa, jak ma się zachowywać każdy komponent:
Viewport
↓
Media Query
↓
Component
Za pomocą zapytań do kontenerów każdy komponent czerpie wskazówki od swojego własnego kontenera:
Component Container
↓
Container Query
↓
Component
Komponenty, które zawierają własne zasady responsywności, są łatwiejsze do ponownego użycia, przenoszenia, testowania w izolacji oraz konserwacji. To przekazanie odpowiedzialności stanowi trwałą korzyść.
Jedno pytanie do rozstrzygnięcia każdego przypadku
Gdy nie jesteś pewien, jakiego narzędzia użyć, zapytaj się, czy decyzja dotyczy strony, czy komponentu. Jeśli dotyczy strony, użyj zapytania mediowego. Jeśli dotyczy przestrzeni przeznaczonej dla komponentu, użyj zapytania kontenerowego. Stosuje się to w przypadkach powtarzających się:
Should the sidebar disappear?
↓
Media Query
Should this card switch from horizontal
to vertical?
↓
Container Query
Should the navigation collapse?
↓
Media Query
Should this reusable widget change
its internal layout?
↓
Container Query
Główne wnioski
- Zapytania mediowe opisują widok przeglądarki i środowisko użytkownika, dlatego pasują do struktury strony, nawigacji, globalnej typografii oraz ustawień takich jak ograniczenie ruchu.
- Zapytania kontenerowe opisują przestrzeń, którą otrzymuje komponent, dlatego pasują do kart, elementów interfejsu, paneli oraz komponentów systemu projektowego.
cqi i cqw, umieszczone w funkcji clamp() z ograniczeniami w postaci rem, zapewniają elastyczne rozmiary bez rezygnacji z ustawień rozmiaru tekstu użytkownika.Literatura pokrewna
- CSS Custom Properties w czasie wykonywania: tematyzacja, mosty JS i @property — Dowiedz się, w jaki sposób CSS custom properties różnią się od zmiennych Sass oraz jak wykorzystać je do tematyzacji, efektów sterowanych JavaScriptem, dynamicznego formatowania tekstu, wariantów komponentów oraz animacji typowanych.
- Zapobieganie efektowi Cumulative Layout Shift przy użyciu tła wideo w Next.js — Poznaj praktyczne techniki CSS i układu, które pomagają uniknąć efektu Cumulative Layout Shift spowodowanego wideo tła w Next.js na różnych urządzeniach i przy różnych prędkościach łącza.