W ostatnich latach ruch w sieci w przeważającym stopniu przebiega z wykorzystaniem przeglądarek opartych o trzy podstawowe silniki (Blink, Gecko oraz WebKit). Tak zwane modern browsers są rozwijane i aktualizowane w modelu evergreen, bez konieczności “ręcznego” instalowania aktualizacji (najczęściej odbywa się to “w tle” podczas restartu programu). Oznacza to, że nowe funkcjonalności mogą być wypuszczane są z większą regularnością.
Dzięki temu ostatnie lata przyniosły wiele ekscytujących nowości w świecie CSS, z niektórymi właściwościami zdążyliśmy już dawno okrzepnąć. Nie wyobrażam sobie obecnie tworzenia layoutów bez flexbox, css grid, czy css variables. Niedawno jednak wsparcia doczekało się również wiele ciekawych konceptów opracowywanych przez CSS Working Group.
W tym artykule postaram się przybliżyć 5 nowości, które na pewno zagoszczą na stałe w zestawie narzędzi, którymi posługuje się na co dzień. Wszystkie opisane funkcjonalności są wspierane przez ostatnie wersje nowoczesnych przeglądarek internetowych.
Właściwości i wartości logiczne
Właściwości logiczne pozwalają uporządkować i uspójnić nomenklaturę i działania związane z wymiarami elementów oraz przepływem tekstu. Do tej pory używaliśmy właściwości fizycznych odnoszących się do wymiarów fizycznych urządzenia. Właściwości i wartości logiczne odnoszą się do logicznych właściwości przeglądanych treści. Kluczowe słowa inline oraz block definiowane są poprzez wertykalny i horyzontalny kierunek przepływu tekstu. Dzięki temu w prostszy sposób możemy rozwiązać problemy związane na przykład ze zmianą kierunku tekstu. Przykładowo gdy przystosowujemy szablon z rynku anglojęzycznego do rynków arabskojęzycznego, lub japońskiego – dotychczas musieliśmy nadpisywać wiele właściwości żeby tekst pisany od prawej do lewej i jego położenie wyglądało poprawnie. Dobrze obrazuje to poniższy przykład gdzie używając właściwości logicznych otrzymujemy ten sam efekt wizualny pisząc niemal dwukrotnie mniej kodu, bez potrzeby nadpisywania styli gdy zmienia się kierunek przepływu pisma.
Przykład zapisany z użyciem właściwości fizycznych:
Przykład zapisany z użyciem właściwości logicznych:
Pełna lista właściwości i własności które mają logiczne odpowiedniki znajdziesz tutaj: CSS logical properties and values
Dynamiczne jednostki
Każdy kto próbował ustawić wysokość jakiegoś elementu w taki sposób, aby zajmował całą wysokość widocznego ekranu na pewno zmierzył się z problemem na który w końcu mamy rozwiązanie. Użycie 100vh w takim przypadku nie było nigdy w pełni poprawnym rozwiązaniem, na urządzeniach mobilnych oznacza to 100% wysokości viewportu, włączamy w to pasek adresu oraz pozostałe elementu UI, które w większości przypadków podczas scrollowania się chowają lub pokazują.


Nasz element zajmuje wtedy więcej miejsca niż byśmy chcieli. Na ratunek przychodzą nam nowe jednostki:

- Small Viewport – odpowiada wielkości viewportu gdy elementy UI przeglądarki są rozwinięte. Jednostki rozpoczynają się prefixem sv*:
- svh – wysokość małego viewportu
- svw – szerokość małego viewportu
- svb – wysokość małego viewportu w znaczeniu logicznym
- svi – szerokość małego viewportu w znaczeniu logicznym
- svmin – przyjmuję mniejszą wartość spośród svh i svw
- svmax – przyjmuje większą wartość spośród svh i svw
- Large Viewport – odpowiada wielkości viewportu gdy elementy UI są niewidoczne. Jednostki są analogiczne do jednostek małego viewportu tylko z prefixem lv*
- Dynamic Viewport – przyjmuje wartość małego lub dużego viewportu w zależności od tego czy elementy UI są widoczne w danej chwili czy nie. Jednostki są analogiczne do jednostek małego viewportu tylko z prefixem dv*
Warto pamiętać że domyślnie wirtualna klawiatura nie jest brana pod uwagę jako element UI, więc pojawienie się jej na ekranie nie spowoduje przeliczenia rozmiarów elementu dla którego użyto dynamiczne jednostki.
CSS Container Queries
Container Queries umożliwiają stylowanie elementów w zależności wymiarów zdefiniowanego kontenera. Do tej pory aby np. zmienić layout elementu w zależności od jego rozmiaru mogliśmy się posłużyć media queries gdzie zdefiniowaliśmy w obrębie jakiego rozmiaru viewportu element ma się zmienić. Dzięki container queries możemy zmieniać layout w zależności od szerokości elementu który stylujemy. W erze komponentów ta funkcjonalność może okazać się wielce przydatną. Na przykładzie poniżej widzimy identyczny element umieszczony w różnym kontekście, layout jest zmienny w zależności od szerokości poszczególnych elementów.
Aby użyć container query musimy utworzyć element który będzie kontenerem dla naszego elementu. Warto zauważyć że ten kontener nie może być stylizowany wewnątrz container query który się do niego odnosi. Definiujemy tutaj kontener oraz typ kontenera. Container queries odnoszące się do wymiarów elementu mogą mieć typ inline-size (szerokości elementu) lub size (szerokość i wysokość elementu). Istnieje również typ normal który będzie definiował kontener w zależności od innych właściwości elementu, tego typu queries nie mają jeszcze większego wsparcia w przeglądarkach dlatego nie będę w tym artykule rozwijał tego tematu.
<div class="card-outer">
<div class="card">[...]</div>
</div>
.card-outer {
container: card / inline-size;
/* this is a shorthand
container-type: inline-size;
container-name: card;
*/
}
Mając tak zdefiniowany kontener możemy go używać w następujący sposób:
.card {
...
/* styles when container width is wider than 768px */
@container card (min-width: 768px) {
...
}
/* styles when container width is wider than 992px */
@container card (min-width: 768px) {
...
}
}
Wraz z container queries pojawiły się nowe jednostki odnoszące się do wymiarów zdefiniowanego kontenera. Jednostki cqi | cqb | cqw | cqh | cqmin | cqmax odnoszą się do odpowiednio do szerokości logicznej | wysokości logicznej | szerokości | wysokości | mniejszej wartości z zakresu szerokości i wysokości | większej wartości z zakresu szerokości i wysokości.
/* New container query units refering to size of the container: cqi | cqb | cqw | cqh | cqmin | cqmax */
.card {
dispaly: flex;
gap: 5cqi; /* -> 5% inline size of container */
}
Pseudo-klasa :has()
Długo wyczekiwany feature dzięki któremu jesteśmy w stanie pisać style elementu nadrzędnego w zależności od wewnętrznych lub sąsiednich elementów.
Bardzo częstym przypadkiem było customowe ostylowanie elementu input typu checkbox. Dotychczas przeważnie korzystaliśmy z kombinatora ‘+’ i ostylowywaliśmy element znajdujący się w bezpośrednim sąsiedztwie elementu input. Nie zawsze możemy jednak zmienić markup.
Z wykorzystaniem :has() jesteśmy w stanie zrobić to prościej. Zastosowanie tej pseudoklasy nie kończy się jednak na tym, myślę że użycie jej będzie powszechne i ułatwi nam rozwiązanie bardzo wielu problemów efektywniej.
Zobacz przykład poniżej:
CSS Cascade Layers
Koncept warstw jest rozszerzeniem kaskady css. Warstwy umiejscawiają się między szczegółowością selektorów (selector specificity), a stylami inline. Zaktualizowaną kaskadę CSS dobrze obrazuje poniższy obrazek:

Podstawowe założenia i zagadnienia związane z CSS Cascade Layers:
- Priorytet warstw zależny jest od miejsca w którym zostały zdefiniowane, warto więc definiować warstwy na początku dokumentu.
- Style bez zdefiniowanej warstwy mają wyższy priorytet niż style wewnątrz warstw.
- Możemy importować cały arkusz styli do warstwy. Może okazać się to przydatne np. w przypadku konfliktu nazw warstw.
- Możemy tworzyć wielopoziomowe warstwy.
- Możemy tworzyć anonimowe warstwy – każda z takich warstw będzie unikalna, a jej kolejność będzie zależeć od miejsca użycia w dokumencie.
- Słowo kluczowe revert-layer (jako wartość właściwości) pozwala na “cofnięcie” kaskady i użycie dowolnej wartości zdefiniowanej w poprzedniej warstwie.
Przykład użycia CSS Layers:
Ostrożnie z dyrektywą !important
Omawiając temat priorytetów należy wspomnieć o dyrektywie !important. W idealnym świecie nie powinniśmy musieć z niej korzystać, jednak dobrze wiemy jak się to ma do rzeczywistości. W kontekście warstw należy pamiętać że priorytet jest następujący:

Taki priorytet jest analogiczny do znanego schematu w ramach pochodzenia stylów, gdzie priorytet dla przypomnienia jest jak na poniższym obrazku:

Wprowadzenie warstw powinno w znacznym stopniu zmniejszyć potrzebę wykorzystywania dyrektywy !important, warto jednak pamiętać o rozkładzie priorytetów zaprezentowanym powyżej.
Tailwind i słowo kluczowe @layer
Jeśli korzystałeś kiedykolwiek z frameworku Tailwind to być może spotkałeś się już z konceptem warstw. W Tailwind możemy definiować style w ramach warstw base, components, utilities. Należy jednak pamiętać, że używając Tailwind te trzy warstwy nie będą kompilowane jako natywne warstwy CSS, a będą odnosić się do dyrektywy @tailwind za pomocą której “importujemy” style tailwind. Więcej o dyrektywach @tailwind i @layer we frameworku tailwind. Czytaj jak efektywnie poradzić sobie z CSS layers oraz dyrektywą @layer w tailwind.
Pozostałe nowości z których możesz korzystać już dziś o których warto wspomnieć
- Native CSS nesting – natywne zagnieżdżanie w CSS (w przykładach w artykule wykorzystuję tą funkcjonalność)
- pseudo-klasy :is(), :where()
- CSS Masking
- text-wrap: balance
- funkcja color-mix
- nowe gamy kolorów (lch, oklch, lab, oklab)
- pseudo-klasy :user-valid i :user-invalid dla elementu input
- subgrid – pozwala na użycie siatki wyznaczonej przez rodzica z display: grid
- aspect-ratio – możliwość ustawienia dla elementu stałej proporcji szerokości do wysokości
- text-underline-offset – odstęp między tekstem a podkreśleniem
- accent-color – ustawienie akcentu kolorystycznego dla niektórych elementów UI takich jak input:checkbox, :radio
- funkcje trygonometryczne
- align-content dla elementów blokowych
Podsumowanie
CSS kontynuuje swoją ewolucję, opisane powyżej funkcjonalności przynoszą nam potężne narzędzia. Dzięki nim będziemy mogli w bardziej efektywny sposób organizować nasz kod co powinno wpłynąć zarówno na jakość naszych projektów jak i rozmiar plików CSS, a każdy bajt to jak wiemy cenny zasób.
Bibliografia i przydatne linki
- Modern CSS in Real Life | Chris Coyier
- CSS Wrapped: 2023! | Una Kravets, Bramus, Adam Argyle
- An Interactive Guide to CSS Container Queries
- Say Hello To CSS Container Queries | Ahmad Shadeed
- CSS Container Queries For Designers | Ahmad Shadeed
- Style Container Queries | Una Kravets
- Future CSS: State Container Queries | Ahmad Shadeed
- A Complete Guide to CSS Cascade Layers | CSS Tricks | Miriam Suzanne
- Cascade layers are coming to your browser | Una Kravets
- :has | MDN
- Modern CSS for 2024: Use Cases for :has() | YOAV GANBAR
- CSS logical properties and values | MDN web docs
- The large, small, and dynamic viewport units | Bramus
- New CSS Viewport Units Do Not Solve The Classic Scrollbar Problem | Šime Vidas
- CSS Nesting | Adam Argyle
- CSS Nesting | MDN
- CSS Masking | Ahmad Shadeed
- mask | MDN
- inset | MDN web docs
- text-wrap: balance | MDN
- color-mix() | MDN
- OKLCH in CSS: why we moved from RGB and HSL | Andrey Sitnik, Travis Turner
- Modern CSS Solutions for Old CSS Problems | Stephanie Eckles