Skip to content

Wszystko o WordPressie, tworzeniu stron — i nie tylko

⚡ Krytyczny CSS: co to jest, jak wygenerować i przyspieszyć ładowanie strony

⚡ Krytyczny CSS: co to jest, jak wygenerować i przyspieszyć ładowanie strony

Strona ładuje się 3 sekundy i odwiedzający odchodzi. Otwiera Pan Google PageSpeed Insights, a tam czerwona diagnoza: „Usuń CSS blokujący renderowanie". Brzmi znajomo? Według danych HTTP Archive za 2025 rok, mediana strony pobiera 7 zewnętrznych arkuszy stylów, a średnia waga CSS przekroczyła 120 KB. Każdy plik w <head> to szlaban między użytkownikiem a treścią.

Problemem nie jest „ciężki" CSS. Przeglądarka nie pokaże ani jednego piksela, dopóki nie załaduje i nie przetworzy WSZYSTKICH stylów. Nawet tych, które odpowiadają za stopkę na 4000. pikselu. Rozwiązaniem jest Critical CSS: technika, która wycina z pełnego zestawu stylów tylko to, co jest potrzebne dla widocznego obszaru ekranu, i osadza to bezpośrednio w <head>. Reszta CSS ładuje się asynchronicznie i nikogo nie wstrzymuje.

Wdrożyliśmy critical CSS we wszystkich projektach na techblogu i zebraliśmy działający proces: od ręcznej generacji w 30 sekund do pełnej automatyzacji przez Gulpa i wtyczki WordPress. Poniżej znajduje się przewodnik krok po kroku, bez lania wody.

💡 Szybki przegląd:

  • Zrozumieć mechanikę blokowania renderowania i dlaczego przeglądarka czeka na CSS, nawet gdy HTML jest już gotowy
  • Wybrać narzędzie do zadania: darmowy generator online w 10 sekund, Penthouse dla projektów npm lub połączenie WP Rocket / Autoptimize dla WordPressa
  • Skonfigurować workflow Gulpa do automatycznej regeneracji critical CSS przy każdym wdrożeniu
  • Ominąć typowe pułapki: FOUC, treść JS, problemy z media queries

Czym jest krytyczny CSS i dlaczego przeglądarka zwalnia

Przeglądarka buduje dwie struktury: DOM z HTML i CSSOM ze stylów. Dopóki CSSOM nie jest gotowy, renderowanie jest wstrzymane. To właśnie jest blokujący CSS, strona pozostaje pusta, dopóki nie załadują się wszystkie arkusze stylów z <head>.

Google PageSpeed Insights diagnozuje problem wprost:

Pana strona ma 3 blokujące zasoby CSS. Powoduje to opóźnienie w wyświetlaniu. Żaden element z górnej części strony nie może zostać wyrenderowany, dopóki nie załadują się następujące zasoby.

Termin „above the fold" pochodzi z gazet. W sieci jest to widoczny obszar przed przewinięciem: ~600 px na desktopie, ~900 px na laptopie, ~400 px na smartfonie. Większość deweloperów przyjmuje bezpieczne 1300 px szerokości i 900 px wysokości.

Krytyczny CSS to minimalny zestaw stylów do renderowania właśnie tego obszaru. Siatka, nawigacja, czcionki, górny blok. Reszta jest odkładana i ładuje się asynchronicznie: strona pojawia się natychmiast, a doskłada się w miarę doczytywania.

Liczby są odczuwalne. Według danych Google, osadzenie krytycznego CSS skraca First Contentful Paint o 0,5-1,2 sekundy na urządzeniach mobilnych. Dla e-commerce ma to bezpośredni wpływ na konwersję: badanie Portent wykazało, że strona z FCP poniżej 1 sekundy konwertuje 3 razy lepiej niż strona z FCP wynoszącym 3 sekundy.

Narzędzia do generacji: od darmowego online po komercyjne API

Wygenerowanie krytycznego CSS ręcznie jest niemożliwe, potrzebne jest narzędzie, które wyrenderuje stronę w przeglądarce bezgłowej i wyciągnie tylko użyte style. Oto trzy działające opcje.

Narzędzie

Typ

Koszt

Automatyzacja

Dla kogo

Critical Path CSS Generator

Online

Darmowy

Nie

Pojedyncze strony, start

Penthouse

pakiet npm

Darmowy

Tak, przez Gulpa/skrypty

Deweloperzy, przetwarzanie wsadowe

criticalcss.com

SaaS

Od $10/mies.

Tak, API + WordPress

Produkcja, duże witryny

Critical Path CSS Generator: online, w 10 sekund

Critical Path CSS Generator Jonasa Olssona to darmowe narzędzie, od którego warto zacząć. Interfejs jest elementarny: wkleja Pan URL strony, wkleja Pan PEŁNY CSS (choćby 200 KB zminifikowanego), klika przycisk i otrzymuje zestaw stylów dla above-the-fold.

Zaleta: zerowy próg wejścia. Nie są potrzebne Node.js, npm ani skrypty. Wada: praca wyłącznie ręczna. Każdą stronę przetwarza Pan osobno, a przy zmianie stylów powtarza proces od nowa. Dla witryny z 5 stronami jest to do przyjęcia, dla 50, już nie.

Twórca generatora uruchomił później komercyjny serwis criticalcss.com, ewolucję tego samego pomysłu z autoaktualizacją, walidacją zrzutami ekranu i API do przetwarzania wsadowego.

Penthouse: konsolowy generator pod Gulpa

Penthouse (ponad 2680 gwiazdek na GitHubie), pakiet npm tego samego autora. Pod spodem Puppeteer i headless-Chromium: otwiera stronę, określa used CSS dla zadanego viewportu i odrzuca resztę.

Instalacja:

1npm install --save-dev penthouse

Minimalne wywołanie ze skryptu Node:

1const penthouse = require('penthouse');
2const fs = require('fs');
3
4penthouse({
5 url: 'https://example.com',
6 cssString: fs.readFileSync('./style.css', 'utf8'),
7 width: 1300,
8 height: 900
9}).then(criticalCss => {
10 fs.writeFileSync('./critical.css', criticalCss);
11});

Szerokość 1300 i wysokość 900, wartości bezpieczne empirycznie. Zapytania mediów szersze niż krytyczny viewport są domyślnie wycinane. Jeśli trzeba je zachować, flaga keepLargerMediaQueries: true.

Ważny niuans: Penthouse uruchamia się z wyłączonym JavaScriptem. Jeśli treść above-the-fold jest generowana przez framework JS, HTML przed hydratacją jest pusty i Penthouse nie znajdzie stylów. Rozwiązanie: renderowanie po stronie serwera (SSR) lub parametr forceInclude z selektorami do wymuszonego zachowania.

WP Rocket i Autoptimize: dwie wtyczki do WordPressa

Jeśli strona działa na WordPressie, ręczne generowanie critical CSS to zbędny ból głowy. Stron jest dużo, szablony się mnożą, style się zmieniają. Dwie wtyczki zamykają zadanie w całości.

WP Rocket, wtyczka premium (59 €/rok za 1 stronę, 119 € za 3, 299 € za 50). Wbudowana opcja „Remove Unused CSS" sama generuje krytyczny CSS dla każdej strony, osadza go w <head>, a resztę CSS ładuje asynchronicznie. Dwa kliknięcia i rekomendacja „Eliminate render-blocking resources" jest spełniona. Bonus: wbudowany hub Rocket Insights oparty na GTmetrix pokazuje metryki wprost z panelu administracyjnego WordPressa.

Autoptimize, bezpłatna wtyczka z opcją „Inline and Defer CSS". Wersja podstawowa generuje JEDEN plik krytycznego CSS dla całej witryny, co w praktyce nie działa (różne strony, różny above-the-fold). Rozwiązanie: integracja z serwisem criticalcss.com (plan WordPress, od 10 $/mies.). Wtyczka automatycznie pobiera krytyczny CSS przez API, osadza go i aktualizuje przy zmianach.

Dla większości użytkowników WordPressa zestaw WP Rocket lub Autoptimize + criticalcss.com zamyka temat całkowicie. Dalej materiał dla tych, którzy piszą strony niestandardowe.

Programista przy biurku z edytorem kodu i miękkim światłem studyjnym

Ręczny workflow: generowanie, wstawianie, weryfikacja

Jeśli koduje Pan stronę bez CMS-a, proces zamyka się w czterech krokach.

Krok 1. Proszę skopiować CAŁY CSS. Proszę zebrać wszystkie style witryny w JEDEN plik. Jeśli pisze Pan w Sassie, proszę skompilować. Jeśli framework typu Bootstrap lub Tailwind, proszę włączyć jego CSS w całości. Proszę nie zgadywać, że „pewnie niepotrzebne", generator sam to rozstrzygnie.

Krok 2. Proszę wygenerować krytyczny CSS przez generator online lub Penthouse. Na wyjściu zminifikowany blok stylów odpowiadający wyłącznie za above-the-fold.

Krok 3. Proszę wstawić krytyczny CSS w <style> wewnątrz <head>. To kluczowe: style inline nie generują dodatkowych żądań HTTP i są przetwarzane przez przeglądarkę natychmiast. Rezultat wygląda mniej więcej tak:

1<!DOCTYPE html>
2<html lang="ru">
3<head>
4 <meta charset="UTF-8">
5 <meta name="viewport" content="width=device-width, initial-scale=1.0">
6 <style>@charset "UTF-8";*,*::before,*::after{box-sizing:border-box}html{font-family:sans-serif;line-height:1.15}body{margin:0;font-family:'Inter',Helvetica,Arial,sans-serif;font-size:1rem;line-height:1.5;color:#222;background:#fff}nav{display:block}.container{max-width:1200px;margin:0 auto;padding:0 20px}</style>
7 <title>Заголовок страницы</title>
8</head>

Krok 4. Proszę przenieść zewnętrzne CSS i JS z <head> na dół strony, przed zamykającym </body>. Tak, <link rel="stylesheet"> w stopce jest technicznie niepoprawny według specyfikacji, ale w praktyce działa we wszystkich przeglądarkach i rozwiązuje problem blokowania. Alternatywą jest loadCSS od Filament Group do asynchronicznego ładowania stylów bez przenoszenia do stopki.

Finał, weryfikacja przez Google PageSpeed Insights. Rekomendacja „Eliminate render-blocking resources" zniknęła? Wszystko zrobili Państwo prawidłowo.

Gulp + Penthouse: automatyzacja dla projektu bez WordPressa

Każda zmiana stylu wymaga ponownej generacji krytycznego CSS. Robienie tego ręcznie jest zabójczo nudne. Gulp automatyzuje ten proces.

Nasz produkcyjny workflow:

1// gulpfile.js
2const gulp = require('gulp');
3const penthouse = require('penthouse');
4const fs = require('fs');
5const urlList = require('./criticalcss-pagelist.json');
6
7gulp.task('criticalcss', function () {
8 urlList.urls.forEach(function (item) {
9 penthouse({
10 url: item.link,
11 css: './css/style.min.css',
12 width: 1300,
13 height: 900,
14 keepLargerMediaQueries: false,
15 renderWaitTime: 100,
16 timeout: 30000
17 }).then(function (criticalCss) {
18 fs.writeFileSync(item.output, criticalCss);
19 console.log('✓ Critical CSS сгенерирован: ' + item.link);
20 }).catch(function (err) {
21 console.error('✗ Ошибка для ' + item.link + ': ' + err.message);
22 });
23 });
24});

Plik criticalcss-pagelist.json z listą URL-i i plików wyjściowych:

1{
2 "urls": [
3 { "link": "https://example.com", "output": "./critical/home.php" },
4 { "link": "https://example.com/about", "output": "./critical/about.php" },
5 { "link": "https://example.com/contact", "output": "./critical/contact.php" }
6 ]
7}

Wynik zapisujemy do plików PHP, które opakowują CSS i są wstawiane przez include w <head> odpowiedniego szablonu. Proszę dostosować do swojego stacku: zapisywać do .css, wstawiać przez serwerowy include, jakkolwiek Państwo chcą.

Uruchomienie: gulp criticalcss i wszystkie strony są przetworzone za jednym razem. Proszę podpiąć zadanie w CI/CD podczas wdrożenia, a krytyczny CSS będzie zawsze aktualny.

Z jakimi problemami się Pan/Pani zetknie

Critical CSS to technika, która ma swoje ostre kąty. Oto, co wyłapaliśmy w praktyce.

Flash of unstyled content (FOUC). Krytyczny CSS nie pokrył jakiegoś elementu, użytkownik widzi szarpanie stylów przy pełnym załadowaniu. Przyczyna: treść została wysunięta poza viewport przez absolute lub transform i generator jej nie uwzględnił. Rozwiązanie: flaga forceInclude z selektorem problematycznego elementu.

Treść generowana przez JS. Prawie wszystkie generatory (Penthouse, narzędzie online) uruchamiają się z wyłączonym JavaScriptem. Jeśli landing zbudowano na React, Vue lub Angular, a renderowania po stronie serwera nie ma, HTML jest pusty i generator nie ma czego analizować. Jedyne niezawodne rozwiązanie: włączyć SSR na poziomie frameworka. Alternatywa, ręczne opisanie selektorów przez forceInclude, ale to jest kruche.

Zapytania medialne. Domyślnie Penthouse wycina reguły, których min-width są szersze niż zadany viewport. Jeśli nie poda Pan/Pani keepLargerMediaQueries: true, style desktopowe przepadną, na szerokim ekranie strona „rozjedzie się". Zawsze proszę sprawdzać wynik na rzeczywistych rozdzielczościach.

Cache'owanie. Wygenerował Pan/Pani krytyczny CSS, wdrożył, po tygodniu zmienił styl nagłówka, a w <head> leży stara wersja. Bez automatyzacji w CI/CD będzie Pan/Pani zapominać o ponownym generowaniu. Zadanie w Gulp podczas wdrożenia rozwiązuje problem całkowicie.

⁉️🤔 Często zadawane pytania

Czy trzeba koniecznie stosować Critical CSS na każdej stronie?

Nie, nie na każdej. Jeśli strona ma jeden plik CSS o rozmiarze 20 KB, a FCP jest już poniżej sekundy, korzyść będzie niezauważalna. Ale jeśli w <head> wiszą 3-4 arkusze stylów o łącznej wadze blisko 100 KB, critical CSS da mierzalny wzrost. Dla landingu z kilku stron wystarczy generator online na 10 minut. Dla sklepu na WordPressie, WP Rocket z kilkoma zaznaczeniami. Proszę kierować się PageSpeed Insights: jeśli rekomendacja „Eliminate render-blocking resources" jest na górze, proszę to robić.

Czy można po prostu przenieść wszystkie <link> do stopki i nie zawracać sobie głowy?

Formalnie nie, specyfikacja HTML wymaga <link rel="stylesheet"> tylko w <head>. W praktyce przeglądarki renderują stronę również z <link> w stopce, ale otrzymuje Pan/Pani błysk nieostylowanej treści (FOUC) przed załadowaniem stylów. Dla wizytówki jest to dopuszczalne, dla projektu komercyjnego, nie. Właściwa ścieżka: krytyczny CSS w <head> inline, asynchroniczne ładowanie reszty przez loadCSS lub media="print" z onload="this.media='all'". Przeniesienie do stopki to proteza, która działa kosztem wizualnego szarpania.

Co się zmieniło wraz z pojawieniem się HTTP/3 i Early Hints?

HTTP/3 i 103 Early Hints pozwalają przeglądarce rozpocząć ładowanie krytycznych zasobów przed otrzymaniem pełnej odpowiedzi serwera. Skraca to opóźnienie, ale nie znosi blokowania renderowania: style i tak muszą się załadować i zostać sparsowane. Early Hints i critical CSS działają w parze, a nie zamiast siebie: Early Hints przyspiesza dostarczanie, critical CSS, moment pierwszego renderowania. Dwie techniki wzmacniają się nawzajem.

Dlaczego Penthouse nie był aktualizowany od 4 lat, czy jest jeszcze aktualny?

Ostatnie wydanie Penthouse (v2.3.3) ukazało się w 2022 roku, ale pakiet pozostaje sprawny: pod maską Puppeteer i Chromium, które są stabilne. Krytyczna funkcjonalność, generowanie used CSS dla zadanego viewportu, nie wymaga częstych aktualizacji. Alternatywa, Critical od Addy'ego Osmaniego (12 000+ gwiazdek), który jest aktualizowany aktywniej i również integruje się z Gulp/Grunt.

Jak postępować ze stronami dynamicznymi, gdzie treść zależy od użytkownika?

Dla stron z personalizacją (konto osobiste, koszyk, dashboard) krytyczny CSS generuje się nie dla konkretnego użytkownika, a dla ogólnej struktury: nagłówek, sidebar, siatka. Treść dynamiczna trafia do części asynchronicznej. Jeśli bez stylów dla bloku użytkownika above-the-fold układ się łamie, proszę dodać odpowiednie selektory przez forceInclude. Proszę generować krytyczny CSS na podstawie ogólnej struktury strony, a spersonalizowane bloki pozostawiać w ładowaniu asynchronicznym z forceInclude dla krytycznie ważnych.

Czy warto wdrożyć Critical CSS w Pana/Pani projekcie

Jeśli strona ładuje więcej niż jeden plik CSS w <head>, critical CSS da mierzalny wzrost szybkości. Dla landingu z trzech stron wystarczy generator online na 10 minut. Dla bloga lub sklepu na WordPressie, dwa zaznaczenia w WP Rocket. Dla projektu niestandardowego, godzina na konfigurację Gulpa i Penthouse zwraca się przy pierwszym wdrożeniu.

Próg wejścia jest niższy, niż się wydaje. Proszę wziąć darmowy generator online, skopiować CSS swojej strony, wkleić i po 30 sekundach zobaczy Pan/Pani wynik. A kiedy zechce Pan/Pani automatyzacji, proszę wrócić do sekcji z workflow Gulpa: ona zamknie temat całkowicie. Przyspieszenie ładowania dwukrotnie w ciągu kilku godzin pracy to transakcja, z której trudno zrezygnować.