- 1 Informacje podstawowe
- 2 Flexbox
- 3 Siatka i podsiatka
- 4 Zapytania o kontenery
- 5 Natywne nakładki, pozycjonowanie kotwic i konteksty stosu
- 6 Śledzenie przepełnienia i stabilność układu
- 7 Mechanika widocznego obszaru i dystrybucja ścieżek
- 8 Siatka (tzw. mur)
1 Fundamentals
Jeśli to możliwe, korzystaj z silnika układu przeglądarki, aby zwiększyć wydajność. Zanim sięgniesz po zakodowane na stałe wymiary lub skomplikowane zapytania o media, wypróbuj rozmiary wewnętrzne, właściwości logiczne i aspect-ratio.
1.1 Który tryb układu wybrać?
Przejdź przez drzewo decyzyjne od góry do dołu i zatrzymaj się na pierwszym dopasowaniu. Pamiętaj, że układy mogą być zagnieżdżone w sobie, a każda decyzja jest podejmowana na podstawie przypadku użycia danego kontenera.
- Czy jest to prosty wiersz LUB kolumna elementów? Użyj flexbox – 1D, najpierw treść, treść jest rozprowadzana wzdłuż jednej osi.
- Czy element zagnieżdżony musi być wyrównany ze ścieżkami siatki elementu nadrzędnego wyższego poziomu? Użyj subgrid – 2D, relacja na pierwszym miejscu, dziedziczy ścieżki nadrzędne, dzięki czemu elementy podrzędne mogą wyrównywać się względem elementów równorzędnych.
- Czy jest to złożona struktura strony lub komponentu z wierszami ORAZ kolumnami? Użyj siatki – 2D, najpierw układ, definiujesz szkielet, a treść go wypełnia.
- Czy treść to długi tekst, który powinien zostać podzielony na równe kolumny? Użyj wielu kolumn – układ jednowymiarowy, styl gazety.
- Czy produkty mają różne wysokości i muszą być ciasno zapakowane? Używaj grid z
grid-auto-flow: densejuż dziś. Po natywne układy masonry (tzw. „grid lanes”) sięgaj tylko wtedy, gdy są one dostępne w Twojej wersji Baseline (patrz §8). - Czy element musi unosić się nad stroną i pozostawać przestrzennie powiązany z elementem aktywującym, nawet poza granicami DOM lub kontekstami stosu? Użyj pozycjonowania zakotwiczonego –
anchor-namew przypadku elementu aktywującego,position-anchorw przypadku nakładki (patrz §5).
1.2 Zasady pracy
- Używaj właściwości logicznych (
inline-size,block-size,margin-inline,padding-block,inset-inline-start) do określania wymiarów i odstępów układu – pełne informacje znajdziesz w artykule CSS: Modern Architecture. - Zastosuj model mentalny „najpierw treść” lub „najpierw układ”: flexbox, gdy elementy dyktują przepływ, siatka, gdy najpierw definiujesz szkielet.
- Użyj skrótów
place-*(place-content,place-items,place-self), aby wyrównać elementy w obu osiach w jednej deklaracji. - Zanim użyjesz stałych wartości
width/height, wypróbuj rozmiary wewnętrzne (min-content,max-content,fit-content()) i elastyczne ścieżki (fr,minmax()) – mniej zapytań o media, bardziej odporne układy. - NIE używaj
overflow: hiddendo maskowania problemów z układem – rozwiąż je u źródła. Na przykład niektóre zastąpione elementy, takie jak<canvas>,<img>,<svg>,<video>,<iframe>, domyślnie używajądisplay: inline, co może powodować luki w niektórych układach. Zamiast przycinać odstęp za pomocąoverflow, usuń go, stosując wartość display-outside (np.display: block,grid,flex). - Użyj
aspect-ratio, aby zarezerwować miejsce na multimedia i zapobiec przesunięciu układu przed załadowaniem zasobów.
.sidebar { inline-size: max-content; } /* Size to longest unbreakable token. */
.main-content { inline-size: fit-content; } /* Grow to available space, no further. */
.media { aspect-ratio: 16 / 9; inline-size: 100%; block-size: auto; }
body.centered { display: grid; place-content: center; min-block-size: 100dvb; }
Informacje o
calc-size()i rozmiarze wewnętrznym uwzględniającym ograniczenia znajdziesz w artykule Obliczanie z użyciem rozmiarów wewnętrznych.
2 Flexbox
Układ jednowymiarowy – elementy są rozmieszczone wzdłuż jednej osi głównej i wyrównane względem osi poprzecznej. Można go używać w paskach nawigacyjnych, paskach narzędzi, wierszach elementów i dowolnych układach z jednym wierszem lub jedną kolumną.
Zalecane czynności:
- Ustal kontekst za pomocą
display: flexi ustaw oś główną za pomocąflex-direction(domyślnierow). - Używaj
flex-wrap: wrap, gdy istnieje możliwość przepełnienia –nowrapbezoverflow: auto/hiddenbędzie się rozlewać w wąskich widocznych obszarach. - Warstwa
flex-wrap: balancepoflex-wrap: wrapw zawijanych wierszach elementów kompaktowych (takich jak chmury tagów, pigułki filtrów, grupy przycisków lub linki nawigacyjne) umożliwia równomierne rozmieszczenie elementów w wierszach i zapobiega pozostawieniu pojedynczego elementu w ostatnim wierszu. Przeglądarki, które nie obsługują tej funkcji, korzystają zwrap. - Użyj skrótu
flex<grow> <shrink> <basis>(np.flex: 1 1 250px) w przypadku elementów zamiast ustawiać osobnoflex-grow/flex-shrink/flex-basis. - Do określania odstępów między elementami używaj
gap(lub pełnej wersjirow-gap/column-gap) zamiast marginesów elementów podrzędnych. - Dodaj prefiks wyrównania pozycji z
safe(np.align-items: safe center), aby treść, którą można zaznaczyć, nie była przycinana, gdy kontener jest węższy niż jego zawartość. - Przesuń pojedynczy element na koniec głównej osi za pomocą
margin-inline-start: auto(lubmargin-block-start: auto) – to standardowe rozwiązanie. - Zastąp wyrównanie względem osi poprzecznej dla poszczególnych elementów za pomocą właściwości
align-self. - Użyj
align-items, aby wyśrodkować wszystkie elementy na osi poprzecznej. Użyjmargin: autona pojedynczym elemencie, aby wyśrodkować go niezależnie na obu osiach. Użyjalign-contenttylko wtedy, gdy kontener zawija się i ma dodatkowe miejsce między wierszami. - Ustaw
min-inline-size: 0(lubmin-width: 0) w elementach flex, które zawierają długie, niepodzielne treści (adresy URL, kod, długie ciągi znaków) – elementy flex nie będą domyślnie zmniejszane poniżej rozmiaru zawartości, co powoduje przepełnienie.
Czego nie należy robić:
- Nie używaj właściwości
justify-selfw przypadku elementów elastycznych – działa ona tylko w układach siatki, blokowych i pozycjonowanych bezwzględnie. Zamiast tego użyj marginesów automatycznych. - Nie używaj
orderaniflex-direction: *-reversedo zmiany kolejności treści interaktywnych. Zmieniają one tylko kolejność wizualną. Kolejność DOM nadal określa sekwencyjne zaznaczanie, więc przepływ kart klawiatury nie będzie odpowiadał temu, co widzi użytkownik. - Nie pomyl
space-around(połowa odstępu na końcach) zspace-evenly(równe odstępy przed, pomiędzy i po). - Pamiętaj o odwróceniu osi: gdy
flex-direction: column,justify-contentwyrównuje się na osi blokowej, aalign-itemswyrównuje się na osi liniowej – odwrotnie niż domyślnie. - Nie ustawiaj rozmiaru kontenera i jego elementów podrzędnych tak, aby wypełniały się nawzajem – jest to częsta przyczyna przepełnienia i nieoczekiwanych wyników. Określ rozmiar jednej strony.
- Nie ustawiaj właściwości
flex-basisiwidth/inline-sizew tym samym elemencie – w kontekście flex właściwośćflex-basisma pierwszeństwo, a właściwośćwidthjest ignorowana. Używajflex-basis(lub skrótuflex) jako jedynego źródła wiarygodnych danych do określania rozmiaru elementów flex.
.card-grid { display: flex; flex-flow: row wrap; gap: 1rem; }
.card-item { flex: 1 1 250px; } /* grow, shrink, basis */
.card-item-action { margin-inline-start: auto; } /* Push to main-axis end. */
.toolbar { display: flex; align-items: safe center; }
.tag-list { display: flex; flex-wrap: wrap; flex-wrap: balance; gap: 0.5rem; }
3 Siatka i podsiatka
Układ dwuwymiarowy – zdefiniuj wiersze ORAZ kolumny lub pozwól silnikowi je wygenerować. Siatka podrzędna umożliwia zagnieżdżonej siatce dziedziczenie ścieżek nadrzędnych, dzięki czemu elementy podrzędne są wyrównane względem elementów równorzędnych.
Wybór funkcji siatki:
- Czy wiesz dokładnie, ile kolumn potrzebujesz?
- Tak – używaj utworów z wulgaryzmami (
grid-template-columns: 200px 1fr,repeat(3, 1fr)itd.) - Czy różne kolumny wymagają różnych rozmiarów (pasek boczny + główny, nagłówek obejmujący wszystkie)? → używaj
grid-template-areasdo oznaczania nazwanych, czytelnych regionów - Czy wszystkie kolumny są jednolite, czy też są pozycjonowane wyłącznie według numeru wiersza? → użyj
repeat(N, ...)lub nazwanych linii - Nie (elastyczny, nieznana liczba elementów) – użyj
repeat(auto-fit, minmax(min, 1fr)) - Czy elementy w ostatnim wierszu powinny się rozciągać, aby wypełnić pozostałe miejsce? →
auto-fit - Czy puste ścieżki w ostatnim wierszu powinny zachować minimalny rozmiar (zachowując puste miejsca w kolumnach)? →
auto-fill
- Tak – używaj utworów z wulgaryzmami (
- Czy musisz umieścić element w określonej lokalizacji?
- Tak – użyj
grid-column: <start> / <end>lubgrid-area: <name>. - Nie (tylko obejmuje wiele ścieżek, pozycja przepływu nie ma znaczenia) – użyj
grid-column: span <n>
- Tak – użyj
- Czy elementy podrzędne muszą dziedziczyć rozmiary ścieżek siatki nadrzędnej (wyrównanie do nieregularnych krawędzi między elementami równorzędnymi)?
- Tak – użyj podsiatki na osi, której dotyczy problem.
- Czy liczba dzieci na komórkę jest zmienna? → podsiatka tylko na jednej osi; na drugiej użyj
grid-auto-rows/grid-auto-columns - Czy liczba dzieci jest stała? → podsiatka na obu osiach jest w porządku
- No – standardowa siatka, nie jest potrzebna podsiatka.
Zalecane czynności:
- Ustal kontekst za pomocą
display: grid. - Używaj
grid-template-areasw przypadku złożonych układów na poziomie strony – nazwy obszarów są zrozumiałe, a deklarację można wyrównać w wierszach i kolumnach, aby była czytelna na pierwszy rzut oka. - Użyj
repeat(auto-fit, minmax(200px, 1fr))w przypadku elastycznych siatek kart, które rozciągają wypełnione ścieżki, aby wypełnić wiersz, lubauto-fill, aby zachować puste powtarzające się ścieżki w ich minimalnym rozmiarze. - Użyj
fr, aby uzyskać proporcjonalny rozkład ścieżek, iminmax(min, max), aby uzyskać elastyczne, ale ograniczone ścieżki. - Użyj
grid-column: span <n>, aby określić rozmiar elementów na ścieżkach,grid-column: <start> / <end>, aby umieścić je w określonych wierszach, lubgrid-area: <name>, aby umieścić je w nazwanych regionach. - Użyj podsiatki (
grid-template-columns: subgridlubgrid-template-rows: subgrid), aby rozwiązać problem „nierównych krawędzi” na listach kart – elementy wewnętrzne, takie jak tytuły, metadane i wezwania do działania, będą wyrównane względem elementów równorzędnych. - Połącz deklarację subgrid z poprzedzającą ją jawną deklaracją
grid-template-rows/-columnsjako kreację zastępczą w tej samej kaskadzie dla starszych przeglądarek.
Czego nie należy robić:
- Nie oczekuj, że rozmiar
auto-fit/auto-fillbędzie pochodzić z zawartości elementu – pochodzi on z argumentu rozmiarurepeat(). - Nie używaj atrybutu
grid-auto-flow: densew treściach interaktywnych. Efektywnie pakuje elementy, ale zmienia ich kolejność wizualną, co zakłóca przepływ kart klawiatury w kolejności DOM. - Nie stosuj podsiatki do obu osi, gdy liczba elementów podrzędnych jest zmienna. Dodatki lądują na ostatniej ścieżce. Zamiast tego użyj
grid-auto-rows/grid-auto-columnsdla osi niejawnej. - Nie należy mylić
justify-items/align-items(wyrównuje zawartość elementu w jego ścieżce) zjustify-content/align-content(wyrównuje ścieżki siatki w kontenerze). Użycie niewłaściwego nie przyniesie żadnego efektu. - Nie używaj
repeat(auto-fit/auto-fill, ...)bez określonegoinline-sizew kontenerze – wewnątrzdisplay: inline-gridlub elementu flex bez rozmiaru kontener nie ma szerokości do podziału, co sprawia, że liczba ścieżek jest nieprzewidywalna.
3.1 Przykładowy kod: siatka i podsiatka
Powłoka strony: <main class="page-layout"> zawiera <header>, <aside>, <section class="card-grid"> z <div class="card"> elementami podrzędnymi i <footer>.
/* Align grid-template-areas in rows and columns for readability. */
.page-layout {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-template-areas:
"header header header"
"sidebar main main"
"footer footer footer";
gap: 1.5rem;
}
header { grid-area: header; }
aside { grid-area: sidebar; }
footer { grid-area: footer; }
.card-grid {
grid-area: main;
display: grid;
grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
grid-template-rows: auto 1fr; /* title block, body block */
gap: 1rem;
}
.card {
grid-row: span 2;
display: grid;
/* Same-cascade fallback: ignored when subgrid is supported. */
grid-template-rows: auto 1fr;
grid-template-rows: subgrid;
}
4 Zapytania dotyczące kontenerów
Sprawdź rozmiar (lub obliczony styl) kontenera nadrzędnego, a nie widocznego obszaru. Model mentalny: zapytania o kontener = kontekst komponentu; zapytania o media = globalny układ strony i preferencje użytkownika (prefers-color-scheme, prefers-reduced-motion).
Zalecane czynności:
- Ustaw kontekst kontenera za pomocą
container-type: inline-size(zapytania dotyczące tylko szerokości) lubcontainer-type: size(obie osie) w elemencie nadrzędnym, zanim będzie można wysyłać zapytania do elementów podrzędnych. - Nazwij kontenery za pomocą
container-name(lub skrótucontainer:container: card / inline-size), gdy zagnieżdżone konteksty mogą kolidować. - Uwzględniaj jednostki zapytań o kontener podczas obliczania płynnego typu i odstępów:
cqi/cqb(logiczne w wierszu/blokowe),cqw/cqh(fizyczne),cqmin/cqmax. - Jeśli używasz
container-type: size, zawsze podawaj konkretną wartośćblock-sizekontenera. Bez tego elementy podrzędne zostaną zwinięte, ponieważ ograniczenie rozmiaru wymusza na kontenerze ignorowanie zawartości.
Czego nie należy robić:
- Nie używaj wartości
block-sizejako wartościcontainer-type– jest ona nieprawidłowa. Użyjsizedla obu osi. - Po zadeklarowaniu
container-typenie oczekuj, że rozmiar wewnętrzny elementów podrzędnych będzie miał wpływ na kontener. Gdy kontener jest aktywny, jest obliczany tak, jakby nie miał elementów podrzędnych. - Nie polegaj na jednostkach zapytań o kontener w elementach podrzędnych niekwalifikującego się elementu nadrzędnego. W takim przypadku następuje powrót do małego widocznego obszaru (
svw/svh).
4.1. Przykład kodu: płynna typografia z użyciem jednostek zapytania o kontener
.card-wrapper {
container: card / inline-size; /* shorthand for container-name / container-type */
}
@container card (inline-size > 400px) {
.content {
display: flex;
gap: 2rem;
}
}
.title {
/* Fluid type bound to the container width, not the viewport. */
font-size: clamp(1rem, 4cqi, 2rem);
}
Wzorce stylów elastycznych opartych na komponentach znajdziesz w artykułach Stylizacja uwzględniająca rozmiar i Skalowanie płynne.
5 Natywne nakładki, pozycjonowanie zakotwiczone i konteksty stosu
Kiedy używać poszczególnych elementów podstawowych nakładki:
- Używaj elementu
popoverw przypadku tymczasowego, niemodalnego interfejsu (menu wyskakujące, wyskakujące powiadomienia, etykietki) – znajduje się on w górnej warstwie i nie wymaga zarządzania elementemz-index. - Używaj
<dialog>z.showModal()w przypadku interakcji modalnych, które wymagają blokowania zaznaczenia i nieaktywnego tła. - Nie łącz
popoveri.showModal()w tym samym elemencie – są to wzajemnie wykluczające się stany środowiska wykonawczego.
Pozycjonowanie kotwicy (układ przestrzenny nakładek):
- Użyj
position-area(lubanchor()w przypadku wstawek) ianchor-size(), aby określić położenie i rozmiar nakładki względem jej aktywatora. - Użyj
position-try-fallbacks: flip-block(lubflip-inline), aby umożliwić przeglądarce zmianę pozycji, gdy nakładka przekracza widoczny obszar. - Nie mieszaj fizycznych i logicznych słów kluczowych w jednej wartości
position-area– wybierz jeden układ współrzędnych. - Wykrywaj funkcje za pomocą
@supports (anchor-name: --x)i zapewnij kreację zastępczą z pozycją bezwzględną.
Pełne informacje o implementacji, strategie polyfill i odniesienia do wartości
popoverznajdziesz w artykułach Declarative Dialog and Popover Control i Position Aware Tooltips. Informacje o pozycjonowaniu zakotwiczonym stosowanym w przypadku menu, wyskakujących okienek i wskaźników kart znajdziesz w artykułach Menu uwzględniające widoczny obszar i Podkreślenie karty pozycjonowania zakotwiczonego.
6 Śledzenie przepełnienia i stabilność układu
Zarządzaj przesunięciami układu, paskami przewijania i przycinaniem w przewidywalny sposób.
Zalecane czynności:
- Użyj
overflow: auto, aby paski przewijania pojawiały się tylko wtedy, gdy treść faktycznie się przelewa. - Użyj
overflow: clip, aby przyciąć zawartość bez tworzenia kontenera przewijania. Aby włączyć przepełnienie, użyjoverflow-clip-margin. - Użyj
scrollbar-gutter: stable, aby zarezerwować miejsce na paski przewijania i zapobiec przesunięciom układu, gdy treści się powiększają. - Użyj
overscroll-behavior: contain(lubnone) w zagnieżdżonych obszarach przewijania (takich jak paski boczne, okna modalne i listy), aby zapobiec przenoszeniu łańcuchów przewijania na stronę, luboverscroll-behavior: chainw pośrednich kontenerach przewijania (takich jak ścieżki przesunięcia, aby odsłonić), gdy nadmierne przewijanie powinno być przenoszone do nadrzędnego elementu przewijania bez wywoływania lokalnego efektu gumki. Użyj triady
-webkit-line-clamp+display: -webkit-box+-webkit-box-orient: verticaldo obcinania wielowierszowego – pomimo prefiksu ten wzorzec jest w pełni określony i nie jest wycofany. Zadeklaruj obok niego skrótline-clampbez prefiksu. Przeglądarki, które jeszcze go nie obsługują, zignorują tę właściwość bez żadnych konsekwencji. Czego nie należy robić:Nie używaj
overflow: scroll, gdy wystarczyauto–scrollwymusza paski przewijania, nawet gdy nie ma czego przewijać.Nie używaj właściwości
overflow: hidden, gdy chcesz tylko przyciąć –hiddentworzy kontener przewijania, który można przewijać programowo.
.scrollable-list {
max-block-size: 400px;
overflow-y: auto;
scrollbar-gutter: stable; /* Reserve scrollbar space. */
overscroll-behavior: contain; /* No scroll chaining into the page. */
}
.snippet {
display: -webkit-box;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
line-clamp: 3; /* Ignored where unsupported. */
overflow: clip;
}
Szczegółowe informacje o
overflow: clipioverflow-clip-marginznajdziesz w artykule Kontrola przycinania przepełnienia. Informacje o przekazywaniu zagnieżdżonego przewijania za pomocąoverscroll-behavior: chainw interfejsie przesuwania w celu wyświetlenia znajdziesz w artykule Przesuwanie w celu wyświetlenia. Informacje o kolorze, rozmiarze i motywie paska przewijania znajdziesz w artykułach Dostosowywanie koloru lub grubości paska przewijania, Tryb ciemny i Dostosowywanie paska przewijania do preferencji dotyczących wysokiego kontrastu.
7 Mechanizmy widocznego obszaru i dystrybucja ścieżek
- Używaj
dvh/dvww przypadku kontenerów układu mobilnego, które muszą uwzględniać zmiany interfejsu przeglądarki (zwijanie/rozwijanie paska adresu URL). - Nie używaj
100vww przypadku układu o pełnej szerokości – ignoruje on szerokość paska przewijania i powoduje przepełnienie w poziomie. Zamiast niej użyj zasad100%,100dvwlub100svw.
Informacje o punkcie wejścia elastycznego projektowania stron (dynamiczne jednostki widocznego obszaru, rezerwowanie miejsca na multimedia, płynna typografia) znajdziesz w artykule Elastyczne projektowanie stron.
8 Pasy siatki (tzw. mur)
Specyfikacja jest rozwijana pod nazwą „grid lanes” (np. display: grid-lanes), podczas gdy we wcześniejszych eksperymentalnych prototypach używano grid-template-rows: masonry.
Zalecane czynności:
- Użyj siatki z właściwością
grid-auto-flow: dense, aby uzyskać ciasne upakowanie, akceptując, że kolejność DOM może nie odpowiadać kolejności wizualnej. - Używaj układu wielokolumnowego (
columns: 3; column-gap: 1rem) w przypadku treści o dużej objętości, gdy elementy są fragmentami dokumentu, a nie kartami o jednakowej wadze. - Traktuj
grid-template-rows: masonrytylko jako progresywne ulepszanie – wykrywaj funkcje za pomocą@supports.
Czego nie należy robić:
- Nie wprowadzaj
grid-template-rows: masonryjako twardego wymagania, dopóki nie zostanie osiągnięty cel Baseline.
.gallery { columns: 3 200px; column-gap: 1rem; }
.gallery > * { break-inside: avoid; margin-block-end: 1rem; }
@supports (grid-template-rows: masonry) {
.gallery {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
grid-template-rows: masonry;
gap: 1rem;
columns: unset;
}
}