Używamy cookies, żeby zwiększyć Twoje doświadczenia na stronie
CodeWorlds
Powrót do kolekcji
Przewodnik11 min czytania

Tailwind CSS 4, konfiguracja w CSS

Tailwind 4 porzucił plik konfiguracyjny w JavaScripcie na rzecz CSS. Nowy silnik, wymagania przeglądarek, migracja z trójki i pułapki przy przejściu.

Tailwind CSS 4, czyli koniec pliku konfiguracyjnego

Tailwind zmienił sposób pisania stylów w aplikacjach internetowych, zastępując nazwane klasy zestawem drobnych klas narzędziowych składanych bezpośrednio w kodzie strony. Wersja czwarta zmieniła sposób pracy z samym narzędziem, i to bardziej, niż sugeruje numer.

Największą zmianą jest zniknięcie pliku konfiguracyjnego w JavaScripcie. Kolory, odstępy, czcionki i wszystko inne opisujesz teraz wprost w arkuszu stylów, jako zmienne CSS. Plik w JavaScripcie nadal działa, o ile go wskażesz, ale przestał być domyślną drogą.

Druga zmiana dotyczy silnika, napisanego od nowa w języku Rust. Pełne budowanie jest kilkukrotnie szybsze, a przebudowa przyrostowa przy zapisie pliku praktycznie natychmiastowa.

Konfiguracja w arkuszu stylów

Zamiast eksportować obiekt z ustawieniami, opisujesz je w CSS, w bloku przeznaczonym na motyw.

Code
CSS
@import "tailwindcss";

@theme {
  --color-marka: #0f766e;
  --color-marka-jasny: #14b8a6;
  --font-naglowek: "Inter Variable", sans-serif;
  --spacing-sekcja: 6rem;
}

Z tych wartości powstają klasy narzędziowe, więc kolor zdefiniowany w ten sposób jest dostępny wszędzie tam, gdzie spodziewasz się koloru.

Zaleta jest większa, niż wygląda, i wykracza poza wygodę. Wartości są zwykłymi zmiennymi CSS, więc widać je w narzędziach deweloperskich, można je odczytać z JavaScriptu i można je nadpisać w konkretnym miejscu bez przebudowy projektu.

To rozwiązuje problem, który przy poprzednim podejściu wymagał obejścia. Motyw ciemny, motyw dla konkretnego klienta albo wariant kolorystyczny jednej sekcji sprowadza się do nadpisania zmiennych w wybranym zakresie, zamiast do generowania osobnych zestawów klas.

Poza motywem dostępne są jeszcze trzy elementy: definiowanie własnych klas narzędziowych, definiowanie własnych wariantów oraz wskazanie wtyczek. Wszystko w tym samym pliku, obok reszty stylów.

Code
CSS
@utility karta-cien {
  box-shadow: 0 1px 2px rgb(0 0 0 / 0.06), 0 8px 24px rgb(0 0 0 / 0.08);
}

@custom-variant ciemny (&:where(.ciemny, .ciemny *));

@plugin "@tailwindcss/typography";

Własny wariant jest tu elementem najczęściej pomijanym, a rozwiązuje konkretny problem: pozwala opisać stan albo zakres raz i używać go jak każdego wbudowanego przedrostka, zamiast powtarzać ten sam selektor w kilkunastu miejscach.

Nazwa dyrektywy bywa tu myląca i warto ją zapamiętać dokładnie. Wariant definiuje się przez @custom-variant, natomiast sama dyrektywa @variant robi co innego: nakłada istniejący wariant na reguły wewnątrz zwykłego bloku CSS. Krótsza nazwa pochodzi z wersji przedpremierowych czwórki, więc poradniki pisane w tamtym okresie podają zapis, który dziś nie zadziała.

Wymagania przeglądarek

To jest najważniejsze zastrzeżenie przy tej wersji i rzecz, którą trzeba sprawdzić przed rozpoczęciem migracji, a nie po niej.

Wersja czwarta wymaga nowszych przeglądarek: Safari od wersji szesnastej z czwartką, Chrome od wersji sto jedenastej i Firefox od wersji sto dwudziestej ósmej. Starsze po prostu nie wyświetlą stylów poprawnie.

Powód jest techniczny i wart zrozumienia, bo przesądza sprawę. Narzędzie opiera się na mechanizmach CSS, których nie da się zastąpić: rejestrowaniu własnych właściwości oraz mieszaniu kolorów. To nie są rzeczy, dla których istnieje wypełniacz dla starszych przeglądarek, więc nie ma tu obejścia.

Wniosek praktyczny jest prosty i niewygodny. Jeśli Twoja aplikacja musi działać na starszych przeglądarkach, wersja czwarta odpada i zostajesz przy trójce. To nie jest kwestia wygody, tylko technicznej niemożliwości.

Warto sprawdzić to w danych o rzeczywistym ruchu, a nie w założeniach. Jeśli masz w projekcie plik z listą obsługiwanych przeglądarek, jedno polecenie odpowiada na pytanie wprost.

Code
Bash
npx browserslist "> 0.5% in PL, last 2 versions, not dead"

Przy aplikacji dla klientów zewnętrznych, zwłaszcza w sektorze publicznym albo w krajach z wolniejszą wymianą urządzeń, udział starszych przeglądarek bywa wyższy, niż podpowiada intuicja. Jeśli na wyjściu pojawi się Safari sprzed szesnastki albo Chrome sprzed sto jedenastki, decyzja jest podjęta i nie ma sensu jej podważać obejściami.

Migracja z wersji trzeciej

Producent dostarcza narzędzie automatyzujące przejście i warto od niego zacząć, bo obsługuje większość mechanicznej pracy.

Code
Bash
git switch -c migracja-tailwind
npx @tailwindcss/upgrade
git diff --stat

Osobna gałąź przed uruchomieniem nie jest przesadną ostrożnością. Narzędzie zmienia pliki szablonów w całym repozytorium, a przegląd tysiąca zmienionych linii jest znacznie łatwiejszy, gdy da się je porównać z punktem wyjścia i cofnąć jednym poleceniem.

Zamienia zależności, przenosi konfigurację z pliku JavaScript do arkusza stylów i poprawia nazwy klas w szablonach. Wymaga nowszej wersji środowiska uruchomieniowego, co warto sprawdzić przed uruchomieniem.

Kilka rzeczy pozostaje do zrobienia ręcznie i to one zajmują czas.

Pierwsza to zmienione nazwy klas. Osobne klasy do przezroczystości zniknęły na rzecz zapisu łączącego kolor z przezroczystością. Zmieniły się też nazwy części klas związanych z układem elastycznym. Narzędzie poprawia to w szablonach, natomiast nie zajrzy do nazw budowanych dynamicznie w kodzie.

Druga to własne klasy narzędziowe zdefiniowane w warstwie przeznaczonej na narzędzia. W nowej wersji przestają reagować na warianty, więc klasa działa, dopóki nie spróbujesz użyć jej z przedrostkiem najechania kursorem. Rozwiązaniem jest przeniesienie ich do przeznaczonej do tego dyrektywy.

Trzecia to kolejność stylów. Nowa wersja korzysta z warstw kaskady, a style spoza warstw mają nad nimi pierwszeństwo. To znaczy, że arkusz dołączony obok, na przykład od biblioteki komponentów, może zacząć nadpisywać rzeczy, które wcześniej nadpisywał Tailwind.

Praktyczna rada: migruj na osobnej gałęzi i przejrzyj wygląd wizualnie, a nie tylko sprawdź, czy projekt się buduje. Zmiany w kolejności stylów nie zgłaszają błędów, tylko przesuwają rzeczy o kilka pikseli w miejscach, których nikt nie planował.

Instalacja i narzędzia budowania

Sposób podłączenia zmienił się razem z wersją i warto znać właściwą drogę dla swojego projektu, bo starsze poradniki opisują nieaktualną.

Przy narzędziach budujących nowej generacji dostępna jest dedykowana wtyczka, wyraźnie szybsza od podejścia przez warstwę przetwarzania stylów. To jest zalecana droga przy projektach na Vite i wszystkim, co na nim stoi.

Przy Next.js i innych frameworkach korzystających z warstwy przetwarzania stylów podłączenie odbywa się przez osobny pakiet wtyczki. Warto zwrócić uwagę na jedną rzecz: w wersji czwartej wtyczka została wydzielona do własnego pakietu, więc konfiguracja skopiowana ze starszego poradnika po prostu nie zadziała.

Zniknęła też potrzeba wskazywania, gdzie szukać klas. Poprzednia wersja wymagała wyliczenia ścieżek do plików szablonów, a obecna wykrywa je sama, pomijając to, co jest wykluczone z kontroli wersji. To usuwa całą kategorię problemów z klasami, które nie powstawały, bo ktoś zapomniał dopisać katalog.

Import jest teraz pojedynczą linią zamiast trzech osobnych dyrektyw. Drobiazg, natomiast łatwo go przeoczyć przy migracji, a stare dyrektywy przestały być rozpoznawane i nie zgłaszają tego wprost.

Warstwy kaskady i współistnienie z innym CSS

Ta część bywa źródłem problemów przy projektach, w których Tailwind nie jest jedynym źródłem stylów.

Nowa wersja umieszcza swoje style w warstwach kaskady, co porządkuje kolejność wewnątrz narzędzia i wprowadza jedną konsekwencję wartą zapamiętania. Style spoza jakiejkolwiek warstwy mają pierwszeństwo nad tymi wewnątrz warstw, niezależnie od kolejności w dokumencie i niezależnie od szczegółowości selektora.

W praktyce oznacza to, że arkusz od biblioteki komponentów, dołączony obok, zaczyna wygrywać z klasami narzędziowymi. Objaw jest mylący: klasa jest w kodzie strony, widać ją w narzędziach deweloperskich, a mimo to nie działa.

Rozwiązania są dwa. Pierwsze to owinięcie cudzego arkusza we własną warstwę przy imporcie, co sprowadza go do tego samego mechanizmu porządkowania. Drugie to wskazanie kolejności warstw jawnie, na początku arkusza, żeby nie zależała od kolejności importów.

Przy pracy z gotowymi zestawami komponentów, na przykład opisanym w tekście o Mantine, warto to rozstrzygnąć na początku projektu. Później oznacza to przeszukiwanie stylów w poszukiwaniu miejsc, w których coś nadpisuje coś innego bez widocznego powodu.

Tailwind kontra alternatywy

RozwiązanieMocna stronaSłabośćKiedy wybrać
TailwindSzybkie pisanie, spójność, brak martwych stylówNieczytelny kod strony, wymagania przeglądarekProjekt budowany z komponentów
Moduły stylówZwykły CSS, pełna kontrola, brak zależnościNazywanie klas, więcej plikówZespół preferujący klasyczne podejście
Style w komponencieStyle blisko logiki, dynamiczne wartościKoszt w czasie wykonania, mniejsza popularnośćSilnie dynamiczne stylowanie
Gotowy zestaw komponentówWygląd w komplecie, mniej decyzjiTrudniej odejść od narzuconego styluPanel administracyjny, aplikacja wewnętrzna

Pierwszy wiersz wygrywa przy projekcie składanym z komponentów, bo tam nieczytelność kodu strony przestaje mieć znaczenie: klasy siedzą w jednym miejscu, w definicji komponentu, a nie rozsypane po całym projekcie.

Przegrywa przy stronach pisanych bezpośrednio w kodzie strony, bez warstwy komponentów. Trzydzieści klas na jednym elemencie jest wtedy realnym problemem przy każdej późniejszej zmianie, a nie wyłącznie szczegółem estetycznym.

Warto pamiętać, że pierwszy wiersz często występuje razem z ostatnim. Zestawy takie jak shadcn/ui czy daisyUI są zbudowane na tej warstwie, więc wybór jednego nie wyklucza drugiego.

Praktyka codziennej pracy

Kilka rzeczy, które przy dłuższej pracy odróżniają projekt czytelny od plątaniny klas.

Powtarzalne zestawy klas wynoś do komponentów, a nie do własnych klas skrótowych. Komponent niesie ze sobą strukturę i zachowanie, a klasa skrótowa jedynie wygląd, więc pierwsze rozwiązanie skaluje się lepiej i nie tworzy własnego, równoległego systemu nazw.

Gdy projekt nie stoi na Reakcie, gotowe zestawy sterowane atrybutami oszczędzają sporo pracy. Preline UI daje komponenty Tailwinda działające bez żadnego frameworka, więc wpina się tak samo w Astro, szablon serwerowy i zwykły plik HTML. Sprawdź tylko licencję, bo część takich zestawów rozdziela wersję darmową i komercyjną.

Warunkowe klasy składaj narzędziem do tego przeznaczonym, a nie łączeniem ciągów znaków. Ręczne sklejanie prowadzi do sytuacji, w której dwie sprzeczne klasy trafiają na ten sam element, a wygrywa ta, która akurat jest później w wygenerowanym arkuszu.

Nie buduj nazw klas dynamicznie z fragmentów. Narzędzie skanuje kod w poszukiwaniu pełnych nazw, więc nazwa sklejona z prefiksu i zmiennej nie zostanie wykryta i klasa nie powstanie. To jest najczęstsza przyczyna stylu, który działa lokalnie i znika po zbudowaniu.

Wartości spoza skali zapisuj w nawiasach kwadratowych oszczędnie. Kilka takich miejsc jest w porządku, kilkadziesiąt oznacza, że skala jest źle dobrana i warto poprawić motyw zamiast obchodzić go za każdym razem.

Kolejność klas warto ujednolicić automatycznie, wtyczką do narzędzia formatującego. To usuwa całą kategorię dyskusji przy przeglądzie kodu i sprawia, że różnice w repozytorium pokazują faktyczne zmiany, a nie przestawione klasy.

Warto też korzystać z wtyczki podpowiadającej klasy w edytorze. Poza uzupełnianiem nazw pokazuje ona, jaki styl kryje się za daną klasą, co przy nauce skraca drogę do zrozumienia skali odstępów bardziej niż czytanie dokumentacji. Przy zespole mieszanym doświadczeniem to jedna z niewielu rzeczy, które faktycznie przyspieszają wdrożenie nowej osoby.

Ostatnia rzecz dotyczy motywu ciemnego. Warto zdecydować na początku, czy przełącza się on według ustawienia systemu, czy według wyboru użytkownika zapisanego w aplikacji. Zmiana tej decyzji później oznacza przejrzenie wszystkich miejsc, w których użyto wariantu ciemnego, bo oba mechanizmy wymagają innego zapisu.

Typowe błędy

Pierwszy to migracja na wersję czwartą bez sprawdzenia wymagań przeglądarek. Starsze przeglądarki nie wyświetlą stylów, a wypełniacza nie ma.

Drugi to nazwy klas budowane dynamicznie z fragmentów. Narzędzie ich nie wykryje, więc klasa nie powstanie, a problem wyjdzie dopiero po zbudowaniu.

Trzeci to własne klasy narzędziowe w dawnej warstwie po migracji. Przestają reagować na warianty, co objawia się działającą klasą i niedziałającym stanem najechania.

Czwarty to sprawdzenie po migracji wyłącznie tego, czy projekt się buduje. Zmiany w kolejności stylów nie zgłaszają błędów, tylko przesuwają rzeczy wizualnie.

Piąty to tworzenie własnych klas skrótowych zamiast komponentów. Powstaje wtedy równoległy system nazw, czyli dokładnie to, od czego to narzędzie miało uwolnić.

Szósty to nadużywanie wartości spoza skali. Kilkadziesiąt takich miejsc oznacza, że motyw jest źle dobrany i warto go poprawić zamiast obchodzić przy każdym elemencie.

Siódmy to dołączanie cudzych arkuszy obok, bez wskazania warstwy. Style spoza warstw wygrywają z klasami narzędziowymi, a objawem jest klasa widoczna w kodzie strony i niedziałająca bez widocznego powodu.

FAQ

Co zmieniła wersja czwarta?

Przede wszystkim miejsce konfiguracji: kolory, odstępy i czcionki opisujesz teraz w arkuszu stylów jako zmienne CSS, a nie w pliku JavaScript. Silnik został napisany od nowa, przez co budowanie jest wyraźnie szybsze, a przebudowa przy zapisie pliku niemal natychmiastowa.

Czy plik konfiguracyjny w JavaScripcie nadal działa?

Tak, o ile wskażesz go jawnie w arkuszu stylów. Przestał być jednak domyślną drogą, a nowe możliwości opisuje się w CSS, więc przy nowym projekcie warto zacząć od razu od nowego podejścia.

Czy mogę zmigrować, mając użytkowników na starszych przeglądarkach?

Nie. Wersja czwarta wymaga nowszych wersji przeglądarek i opiera się na mechanizmach, których nie da się zastąpić wypełniaczem. Przy wymogu obsługi starszych urządzeń zostajesz przy wersji trzeciej.

Dlaczego moja klasa nie działa po zbudowaniu?

Najczęściej dlatego, że jej nazwa powstaje dynamicznie z fragmentów. Narzędzie skanuje kod w poszukiwaniu pełnych nazw, więc nazwa sklejona ze zmiennej nie zostanie wykryta. Rozwiązaniem jest zapisanie pełnych nazw w kodzie i wybieranie między nimi.

Czy Tailwind nadaje się do dużych projektów?

Tak, pod warunkiem pracy z komponentami. Klasy zebrane w definicjach komponentów pozostają czytelne, a rozsypane bezpośrednio po kodzie strony przestają. To jest główne kryterium, a nie wielkość projektu sama w sobie.

Dokumentacja stoi na stronie projektu, a przejście z poprzedniej wersji opisuje przewodnik migracji.