
Komponenty w React renderują UI na podstawie albo stanu wewnętrznego, albo przekazanych propsów:
Choć widzimy i rozumiemy w jaki sposób dodawane są klasy, czy możemy być pewni jak komponent będzie wyglądał? Nie, ponieważ:
- Niekoniecznie wiemy gdzie zdefiniowane są klasy dla przycisku
- Jeżeli wiemy, niekoniecznie wiemy czy przypadkowo gdzieś ich nie nadpiszemy
- Jeżeli sprawdziliśmy i wiemy, że nie są nadpisane – ktoś kto używa tego komponentu poza naszym projektem może te klasy nadpisać i zmienić zachowanie komponentu nawet nie mając takiego zamiaru
Dodatkowo – jeżeli chcemy sprawdzić co konkretnie kryje się pod każdą klasą, musimy szukać w pliku stylów – poza komponentem. Musimy też o pliku stylów pamiętać podczas przenoszenia np do innego projektu, co ogranicza przenaszalność kodu.
Jeżeli chcielibyśmy uniknąć tego typu problemów możemy napisać style inline:
Ale zabiera nam to na przykład pseudoselektory czy media query.
Jednym z możliwych rozwiązań jest CSS-in-JS.
Spis treści
- CSS in JS
- Styled-components
- Inne biblioteki CSS-in-JS
- Porównanie popularności bibliotek CSS-in-JS
- Podsumowanie
CSS in JS
CSS in JS to podejście czerpiące to co najlepsze z obu światów:
- Zapewnia pseudoselektory, media query i inne rzeczy ze zwykłego stylowania
- Pozwala nam zapomnieć o problemach z klasami CSS
CSS in JS to podejście a nie biblioteka – może zostać zaimplementowane w różny sposób. Główna idea jest taka, że piszemy style niejako „inline” w komponencie, biblioteka transformuje je do selektorów CSS – na przykład do klas.
Dzięki temu że kod HTML (JSX), JS i CSS są zawarte w jednym pliku komponenty są łatwo przenaszalne. Ponieważ style są wpisane w komponent widzimy bezpośrednio jak zmiany w stanie/propsach wpłyną na komponent – nie musimy nigdzie szukać jaki kolor przycisku ustawia np klasa button--primary
.
Jeśli komuś pojęcie CSS in JS jest znajome, pierwszym skojarzeniem jest zapewne biblioteka styled-components.
Styled-components
Styled components zostało przeze mnie opisane w poprzednim wpisie:
Styled-components nie jest jednak jedyną opcją.
Inne biblioteki CSS-in-JS
Emotion
Emotion to biblioteka CSS-in-JS niepowiązana bezpośrednio z Reactem. Wystarczy zainstalować główną paczkę:
I można używać Emotion bez konieczności grzebania w konfiguracji – więc bez problemu użyjemy jej w aplikacji CRA. W porównaniu do styled-components ma nieco inną składnię – w standardowej wersji styl przypisujemy do parametru className
:
Jeżeli chcemy dopisać np pseudoselektor, używamy składni wklejania selektoru rodzica:
Składnia ta jest bardzo często używana w SCSS do zagnieżdżania selektorów bądź do uproszczonego zapisu klas w metodologii BEM.
Emotion-core dla Reacta
By móc lepiej wykorzystać Emotion w React, możemy zainstalować bibliotekę emotion-core
dedykowaną dla Reacta:
Niestety, paczka ta nie zadziała z automatu z aplikacją CRA i trzeba będzie zrobić eject by móc zmodyfikować konfigurację – zyskamy jednak wsparcie dla Server-Side Renderingu.
Składnia nieco różni się od wersji głównej – zamiast do className
przypisujemy do atrybutu css
:
Do parametru css możemy przekazywać tablicę, co pozwala nam łatwo komponować style i zachować porządek w stylowaniu:
Style nadawane są w kolejności ich użycia, ostatni nadpisuje poprzednie – co w powyższym przykładzie oznacza, że początkowa deklaracja background: green
zostanie nadpisana którąś z deklaracji występujących później.
Przekazywanie parametrów jako obiekt
Zamiast template string możemy do parametru css przekazać obiekt. Pod kilkoma względami może być to lepsze rozwiązanie niż template string:
- Nie ma potrzeby importować funkcji
css
- Używamy składni camelCase zamiast snake-case, np
backgroundColor
zamiastbackground-color
– dzięki temu zachowujemy spójność z czystym JS, w którym do stylu elementu odnosimy się poprzez camelCase:element.style.backgroundColor = 'white';
Przykład – pogrubione kody są równoważne:
Używając obiektów możemy również stosować np pseudoselektory zagnieżdżając kolejny obiekt – wtedy jednak należy nazwę klucza ująć w znaki cudzysłowu:
Emotion theme (skórki)
Podobnie jak styled-components, emotion umożliwia tworzenie skórek. Należy zainstalować paczkę emotion-theming
:
Następnie trzeba użyć ThemeProvider
do dostarczenia skórki do naszej aplikacji. Skórka może być jednym ze sposobów implementacji przełączania pomiędzy trybem jasnym i ciemnym:
Theming jest dostępny tylko jeżeli użyjemy wersji Reactowej, @emotion/core
Emotion-styled
Choć osobiście składnię Emotion uważam za czytelniejszą niż składnię styled-components, dla uważających inaczej jest możliwość zainstalowania paczki emotion-styled
i pisania kodu w API podobnym do styled-components:
Przykładowy kod mógłby wyglądać tak:
Ciekawostka o Emotion
Emotion została oficjalnym następcą biblioteki Glamorous – zaimplementowany został nawet skrypt automatyzujący migrację do Emotion.
JSS
Biblioteka JSS jest niezależna od Reacta, style deklarujemy w niej jako obiekt gdzie klucz będzie przypisany do klasy elementu HTML a wartość będzie stylami tej klasy:
JSS posiada dedykowaną paczkę dla Reacta: React-JSS. Zajmiemy się nią, ponieważ podobnie jak w przypadku Emotion paczka ta dodaje sporo nowych możliwości do biblioteki głównej.
React-JSS
React-JSS dodaje kilka ciekawych funkcjonalności:
- Możliwość użycia skórek oraz dynamicznej podmiany skórki
- Ładowania CSS tylko tego CSS, który jest potrzebny dla wyrenderowanych komponentów
- Dodawania/usuwania stylów w momencie renderowania/usuwania komponentu
Podstawy React-JSS
Do utworzenia stylów używamy funkcji createUseStyles
, która zwróci nam hooka którego używać będziemy w komponencie. createUseStyles
to tzw funkcja wyższego rzędu. Jako parametr bierze obiekt z nazwami klas jako klucze i obiektami jako stylami. Zamiast obiektu, jako styl możemy przekazać funkcję która jako parametr przyjmuje propsy komponentu:
Skórki w React-JSS
Jak każda szanująca się biblioteka CSS-in-JSS React-JSS daje nam możliwość używania skórek. Wewnątrz komponentów zawierających się w ThemeProvider
theme dostępny jest w propsach:
Styled-jsx
Używanie biblioteki styled-jsx znacząco różni się od poprzednich – pisząc w styled-jsx mamy podobne wrażenia jak podczas pisania zwykłego CSS:
Ten sposób zapisu będzie zaletą dla tych, którzy przywykli do klasycznego sposobu pisania stylów w CSS. Dodatkowo, taki zapis bardzo ułatwia pisanie innych selektorów niż klasy, a takie też są nadal potrzebne.
Style dynamiczne
Ponieważ stylowanie w styled-jsx używa template string, możemy używać dynamicznych wartości z propsów/stanu:
Skórki
Styled-jsx nie oferuje bezpośrednio wsparcia dla skórek i przełączania między nimi, można jednak zasymulować to zachowanie poprzez przekazywanie theme jako propsa:
Aphrodite
Aphrodite jest biblioteką utworzoną przez twórców Khan Academy, pierwotnie była używana wewnętrznie a potem została upubliczniona. Jej rozmiar to zaledwie 20 kilobajtów przed / 6 kilobajtów po skompresowaniu przez gzip.
Po zainstalowaniu poleceniem npm install --save aphrodite
style tworzymy jako obiekty przekazywane do Stylesheet.create(...)
, gdzie klucze to nazwy klas a wartości to wartości stylów:
Aphrodite dostacza możliwość rozszerzania funkcjonalności biblioteki poprzez dopisywanie rozszerzeń – nie wymaga to zmian w konfiguracji projektu itp.
Porównanie popularności bibliotek CSS-in-JS
Do porównania popularności bibliotek użyjemy strony npm-stats, udostępniającą dane dotyczące pobrań biblioteki w danym dniu. Jako dzień sprawdzenia statystyk przyjmiemy 21 lutego 2020 roku.
Porównanie dla paczek styled-components, emotion, jss, styled-jsx, aphrodite
Najpierw porównanie dla paczek bazowych, pamiętając o tym że Emotion dostarcza również paczkę @emotion/core a JSS paczkę React-JSS:

Wyraźnie widać że styled-components (prawie 57 tysięcy pobrać) i JSS (prawie 49,5 tysiąca pobrań) mają dość wyraźną przewagę nad resztą stawki – kolejne Emotion ma dwa razy słabszy wynik – niewiele ponad 24 tysiące pobrań.
Porównanie dla paczek styled-components, @emotion/core, react-jss, styled-jsx, aphrodite

Przy takim układzie wynik Emotion wygląda nieporównywalnie lepiej.
Podsumowanie
Przez spory okres czasu, gdy nie interesowałem się tematem CSS-in-JS, myślałem że styled-components to jedyna opcja. Okazało się, że bibliotek jest wiele – tak jak wiele jest podejść. Wg mnie najlepiej wygląda Emotion – najczytelniejsza składnia i duża popularność – ale zdania mogą być różne. Pod adresem https://www.cssinjsplayground.com/ można sprawdzić jeszcze dodatkowe biblioteki CSS-in-JS.