PX vs REM vs EM: kompletny przewodnik po jednostkach CSS
Oto krótka odpowiedź na pytanie px vs rem vs em, jeszcze przed jakimkolwiek wyjaśnieniem. Używaj rem do niemal całego wymiarowania — rozmiarów czcionek, paddingu, marginesów, odstępów, border-radius i punktów przełamania (breakpointów) — bo skaluje się wraz z ustawieniem rozmiaru czcionki w przeglądarce czytelnika. Używaj px do tych nielicznych rzeczy, które nigdy nie powinny się skalować, jak obramowanie o szerokości 1px czy precyzyjne przesunięcie cienia. Używaj em do rzadkiego, lokalnego przypadku, gdy wartość ma rosnąć wraz z rozmiarem czcionki samego elementu — na przykład padding przycisku, który podąża za jego tekstem.
Ta reguła obejmuje 90% decyzji. Pozostałe 10% to miejsce, gdzie kryją się kłopoty: matematyka kumulacji em, która za pierwszym razem zaskakuje każdego, błąd w media query psujący układy przy powiększeniu oraz przypadki, w których px jest faktycznie bardziej dostępnym wyborem. Dalej znajdziesz wszystkie trzy z gotowym do uruchomienia CSS, a na końcu ściągę według właściwości, którą warto mieć otwartą podczas pisania stylów.
Co px, rem i em naprawdę oznaczają
Trzy jednostki mają trzy różne punkty odniesienia, i na tym polega cała różnica.
px to jednostka absolutna. Jeden px to jeden piksel CSS i zachowuje ten rozmiar bez względu na otoczenie. border: 1px solid to jeden piksel, kropka. Haczyk w tym, że „absolutny” oznacza też, że jednostka ignoruje preferencje użytkownika — o tym, dlaczego to ma znaczenie, będzie później.
rem jest względny wobec rozmiaru czcionki elementu głównego (root). Elementem głównym jest <html>, a przeglądarki domyślnie ustawiają jego rozmiar czcionki na 16px. Zatem 1rem równa się 16px w standardowej konfiguracji, wszędzie na stronie, niezależnie od zagnieżdżenia. Cała zaleta sprowadza się do tej spójności: masz jedną wartość kotwiczną i nie musisz pilnować niespodzianek.
em jest względny wobec rozmiaru czcionki bieżącego elementu (lub jego rodzica, dla właściwości innych niż font-size). Ponieważ ten punkt odniesienia zmienia się wraz z zagnieżdżaniem elementów, wartości em przesuwają się zależnie od kontekstu. Ten sam 1.5em może w jednym miejscu dawać 24px, a w innym 30px.
Kotwica, którą warto zapamiętać, to 16px = 1rem. Jeśli masz zapamiętać tylko jedno, zapamiętaj właśnie to. Gdy musisz przeliczyć konkretną wartość, konwerter px na rem wykonuje dzielenie względem dowolnej bazy, którą wybierzesz.
px vs rem vs em w skrócie
| Jednostka | Względem czego | Skaluje się z czcionką użytkownika? | Typowe zastosowanie | Zachowanie przy zagnieżdżeniu |
|---|---|---|---|---|
px | Niczego (absolutna) | Nie | Obramowania, przesunięcia cieni, włoskowate linie | Zawsze ten sam rozmiar |
rem | Rozmiar czcionki głównego <html> | Tak | Rozmiar czcionki, odstępy, breakpointy | Zawsze ten sam rozmiar |
em | Rozmiar czcionki bieżącego elementu | Tak | Wartości lokalne związane z komponentem | Kumuluje się — może dryfować |
Dwie kolumny rozstrzygające większość sporów to „skaluje się z czcionką użytkownika” oraz „zachowanie przy zagnieżdżeniu”. rem wygrywa w obu: respektuje preferencję czytelnika i pozostaje przewidywalny. em dzieli pierwszą zaletę, ale rezygnuje z drugiej.
Jak oblicza się każdą jednostkę
To zwykła arytmetyka. Kłopot sprawia zwykle jedno: przez jaką liczbę dzielić albo mnożyć.
rem korzysta z rozmiaru czcionki elementu głównego:
rem = px ÷ root-font-size
Przy domyślnym roocie 16px, 24px ÷ 16 = 1.5rem. Aby wrócić, pomnóż: 1.5rem × 16 = 24px. Każdy rem na stronie używa tej samej 16 (lub czegokolwiek, co ustawisz jako root), i dokładnie dlatego rem jest przewidywalny.
em korzysta z rozmiaru czcionki samego bieżącego elementu:
em = px ÷ current-element-font-size
Jeśli font-size elementu wynosi 20px, to 1em na tym elemencie to 20px, 0.5em to 10px, a padding 1.5em to 30px. Zmień rozmiar czcionki elementu, a każda przypisana do niego wartość em zmieni się razem z nim. To lokalne sprzężenie jest sensem em, ale bywa też jego pułapką.
Pułapka kumulacji em
Wiele poradników pomija ten fragment. Gdy zagnieżdżasz elementy, które wszystkie używają em do rozmiaru czcionki, wartości mnożą się w dół drzewa. Każdy poziom dziedziczy obliczony rozmiar czcionki rodzica i nakłada na to swój własny współczynnik em.
.menu { font-size: 1.2em; } /* rodzic ma 16px → 19.2px */
.menu .item { font-size: 1.2em; } /* rodzic ma 19.2px → 23.04px */
.menu .item .sub { font-size: 1.2em; } /* rodzic ma 23.04px → 27.648px */
Każdy poziom to „120% swojego rodzica”, co brzmi niegroźnie. Ale ponieważ rodzic już urósł, trzeci poziom to 1.2 × 1.2 × 1.2 = 1.728em względem oryginalnych 16px — około 27.6px, a nie 19.2px, które mógłbyś odczytać z reguły w izolacji. Zagnieźdź listę w liście wewnątrz komponentu, a tekst rozrasta się w sposób trudny do prześledzenia.
rem całkowicie to omija. 1.2rem to 19.2px, czy siedzi na samej górze dokumentu, czy dwanaście poziomów głębiej, bo zawsze mierzy względem roota, nigdy względem rodzica. Gdy wartość daje rozmiar, którego się nie spodziewałeś, pierwsze pytanie brzmi: czy to em (względny wobec rodzica, kumuluje się) czy rem (względny wobec roota, stabilny). Jeśli debugujesz zabłąkany rem i chcesz szybko zobaczyć jego rozmiar w pikselach, konwerter rem na px przelicza go natychmiast.
Kiedy używać rem
Po rem sięgaj domyślnie. To właściwa jednostka do rozmiarów czcionek, paddingu, marginesów, odstępów, border-radius i breakpointów w media query — wszystkiego, co powinno się skalować, gdy czytelnik dostosowuje rozmiar tekstu.
To ostatnie zdanie to argument za dostępnością i nie jest on hipotetyczny. Ankiety WebAIM wśród użytkowników czytników ekranu i osób słabowidzących konsekwentnie pokazują, że duża część użytkowników zmienia domyślny rozmiar czcionki przeglądarki lub systemu, wielu z nich znacznie powyżej standardowych 16px. Układ wymiarowany w rem honoruje tę zmianę: podbij domyślny rozmiar do 20px, a każda wartość oparta na rem rośnie proporcjonalnie. Układ wymiarowany w px całkowicie to ignoruje: tekst pozostaje zablokowany na zaszytym rozmiarze, niezależnie od tego, jak bardzo czytelnik potrzebuje go większego.
:root {
font-size: 16px; /* 1rem = 16px */
}
h1 { font-size: 2rem; } /* 32px, skaluje się z preferencją użytkownika */
p { font-size: 1rem; } /* 16px */
.card { padding: 1.5rem; } /* 24px */
.card { border-radius: 0.5rem; } /* 8px */
Ponieważ każda wartość jest tutaj zakotwiczona w tym samym roocie, pojedyncza zmiana rozmiaru czcionki roota przeskalowuje cały interfejs proporcjonalnie. To również utrzymuje spójność design systemu: odstępy i typografia poruszają się razem, zamiast się rozjeżdżać.
Sztuczka z 62.5%
Istnieje popularny skrót, który czyni arytmetykę rem trywialną. Ustaw rozmiar czcionki roota na 62.5%, czyli 62.5% × 16px = 10px:
html {
font-size: 62.5%; /* teraz 1rem = 10px */
}
body {
font-size: 1.6rem; /* przywróć czytelny tekst 16px */
}
h1 { font-size: 2.4rem; } /* 24px */
p { font-size: 1.6rem; } /* 16px */
Przy roocie 10px rachunek pamięciowy sprowadza się do „podziel wartość w pikselach przez 10”: 24px → 2.4rem, 12px → 1.2rem. Jedyny haczyk to przywrócenie czytelnego rozmiaru tekstu za pomocą body { font-size: 1.6rem }, bo surowa baza 10px daje domyślny tekst o wiele za mały. Użycie 62.5% jako procentu, a nie 10px, zachowuje względność, więc czytelnik, który przeskaluje domyślne ustawienia przeglądarki, nadal otrzymuje proporcjonalny wzrost. Jeśli przyjmiesz tę bazę, ustaw rozmiar czcionki roota w konwerterze na 10, aby pasował do twojego arkusza stylów.
Kiedy używać em
Używaj em, gdy chcesz, by wartość skalowała się wraz z własnym rozmiarem czcionki elementu, a nie roota. Klasycznym przypadkiem jest przycisk:
.btn {
font-size: 1rem; /* wymiarowany względem roota */
padding: 0.75em 1.5em; /* padding podąża za tekstem przycisku */
}
.btn--large {
font-size: 1.25rem; /* jedna zmiana zmienia rozmiar wszystkiego */
}
Ponieważ padding jest w em, modyfikator .btn--large zmienia rozmiar tekstu i jego paddingu razem, z jednej deklaracji, więc przycisk pozostaje proporcjonalny przy dowolnym rozmiarze. Ta sama logika dotyczy ikony wymiarowanej w em, by pasowała do linii tekstu, w której się znajduje, albo letter-spacingu, który ma rosnąć wraz z czcionką.
Strategia, która sprawdza się w praktyce, to rem dla globalnego szkieletu, em dla lokalnych proporcji. Ustaw rozmiar czcionki w rem, by odpowiadał roocie i preferencji użytkownika; ustaw tę garstkę wartości, które mają podążać za tym elementem, w em. Tylko trzymaj em z dala od czegokolwiek, co głęboko się zagnieżdża, bo inaczej wcześniejsza pułapka kumulacji znów się wkrada.
Kiedy używać px
Niektóre wartości naprawdę nie powinny się skalować i px jest dla nich właściwy: włoskowate obramowanie 1px, precyzyjne przesunięcie box-shadow, pierścień fokusa 2px. To detale renderowania, nie treść. Obramowanie, które „skaluje się” do 1.25px, gdy użytkownik powiększa tekst, nic nie zyskuje i może wyrenderować się jako rozmyta linia. px utrzymuje je ostrym.
.divider { border-bottom: 1px solid; } /* powinno pozostać 1px */
.card { box-shadow: 0 2px 4px rgba(0,0,0,0.1); } /* stałe przesunięcie */
.input:focus { outline: 2px solid; } /* ostry pierścień fokusa */
Zaskakujący niuans — kiedy px jest bardziej dostępny
Większość porad „zawsze używaj rem” pomija jeden niuans. Dostępny wybór to nie „rem wszędzie”, tylko „skaluj to, co powinno się skalować, i ustal na stałe to, co nie powinno”.
Obramowanie 1px to stały detal. Wymuszenie go w rem, by rosło, gdy użytkownik powiększa tekst, nie poprawia czytelności, a jedynie rozmywa włoskowatą linię. Dla tych właściwości px jest bardziej dostępnym wyborem właśnie dlatego, że pozostaje na miejscu.
Błąd, który ludzie faktycznie popełniają, jest odwrotny: użycie px do rzeczy, które powinny reagować, jak rozmiary czcionek i breakpointy. To tutaj px szkodzi dostępności. Reguła nie dotyczy więc jednostki, lecz właściwości. Zapytaj, czy wartość jest treścią, z którą czytelnik wchodzi w interakcję (skaluj ją — rem), czy stałym detalem renderowania (przypnij ją — px). Jednostka wynika z odpowiedzi.
Pułapka media query
Ta psuje prawdziwe układy i prawie żaden przewodnik przed nią nie ostrzega. Punkty przełamania w media query napisane w px nie reagują na powiększenie rozmiaru czcionki przeglądarki tak, jak byś tego oczekiwał.
Wyobraź sobie breakpoint przy width: 600px, gdzie zwija się pasek boczny. Użytkownik o ograniczonym wzroku ustawia domyślny rozmiar przeglądarki na 24px, by czytać komfortowo. Twoja treść potrzebuje teraz więcej miejsca w poziomie — większy tekst chce się wcześniej przełamać. Ale breakpoint w px nie wie, że tekst urósł; nadal przełącza się dokładnie przy 600px szerokości viewportu, więc układ zmienia się w niewłaściwym momencie, a treść robi się ściśnięta lub się nakłada.
Porównaj oba podejścia:
/* breakpoint px — ignoruje preferencję rozmiaru czcionki użytkownika */
@media (min-width: 600px) {
.sidebar { display: block; }
}
/* breakpoint em/rem — reaguje na rozmiar czcionki użytkownika */
@media (min-width: 37.5em) {
.sidebar { display: block; }
}
37.5em to 600px przy domyślnych 16px (600 ÷ 16 = 37.5). Różnica jest behawioralna: gdy użytkownik podwoi domyślny rozmiar czcionki, breakpoint em efektywnie też się podwaja, więc układ przełącza się przy szerokości viewportu proporcjonalnej do tekstu, czyli dokładnie wtedy, gdy treść tego potrzebuje. Breakpoint px pozostaje zamrożony.
Jeden niuans warto znać: w warunkach media query zarówno em, jak i rem rozwiązują się względem domyślnego rozmiaru czcionki przeglądarki, a nie żadnego nadpisania na html, więc zachowują się tam identycznie. Każda z tych jednostek naprawia błąd; px go powoduje.
Tabela decyzyjna według właściwości
Gdy masz wątpliwości, ta tabela je rozstrzyga. To najszybszy sposób na podjęcie decyzji bez ponownego wyprowadzania logiki za każdym razem.
| Właściwość | Zalecana jednostka | Dlaczego |
|---|---|---|
font-size | rem | Skaluje się z preferencją rozmiaru czcionki użytkownika |
padding / margin | rem | Odstępy skalują się razem z tekstem |
border | px | Włoskowate linie powinny pozostać ostre i stałe |
przesunięcie box-shadow | px | Precyzyjny detal renderowania, nie treść |
border-radius | rem | Utrzymuje zaokrąglenie narożników proporcjonalne do skali |
| media query | em / rem | Breakpointy muszą reagować na powiększenie czcionki |
width / max-width | rem (często ch dla tekstu) | Skalowalne szerokości układu; ch ogranicza długość wiersza |
line-height | bez jednostki | Bezjednostkowy mnożnik dziedziczy się poprawnie |
Wiersz line-height zasługuje na uwagę, bo to częsty błąd. Zawsze pisz line-height: 1.5, bez jednostki. Wartość bez jednostki to mnożnik, który każdy element oblicza względem własnego rozmiaru czcionki, więc zagnieżdżone elementy pozostają czytelne. Napisz zamiast tego line-height: 1.5em lub 24px, a obliczona długość zostanie odziedziczona, co oznacza, że dziecko z większą czcionką zachowuje wysokość wiersza rodzica i jego tekst zaczyna się zlewać. Brak jednostki omija cały problem.
Przeliczanie między px a rem
Arytmetyka jest na tyle prosta, by zrobić ją w głowie, gdy tylko utrzymasz kotwicę: 16px = 1rem. Podziel przez 16, by przejść na rem, pomnóż przez 16, by wrócić do px.
| px | rem (baza 16px) |
|---|---|
| 8px | 0.5rem |
| 12px | 0.75rem |
| 16px | 1rem |
| 24px | 1.5rem |
| 32px | 2rem |
Jeśli używasz sztuczki z 62.5%, baza staje się 10px, a rachunek jest jeszcze prostszy — wystarczy podzielić lub pomnożyć przez 10, więc 24px = 2.4rem. Jedyna zasada to zawsze przeliczać względem bazy, którą faktycznie ustawia twój arkusz stylów.
Do wszystkiego innego — nietypowych wartości, niestandardowego roota czy masowej konwersji eksportu z Figmy — pomiń liczenie w głowie i użyj konwertera px na rem lub konwertera rem na px. Oba pozwalają ustawić dowolny rozmiar czcionki roota i przeliczać w obu kierunkach w czasie rzeczywistym. A jeśli porządkujesz potem arkusz stylów pełen mieszanych jednostek, formater CSS znormalizuje za ciebie odstępy i wcięcia.
Częste błędy
Kilka wzorców powoduje większość kłopotów związanych z jednostkami:
Ustawianie rozmiaru czcionki roota w px. Napisanie html { font-size: 16px } (zamiast pozostawienia domyślnej wartości lub użycia 100% / procentu) całkowicie nadpisuje preferencję rozmiaru czcionki przeglądarki użytkownika. Wartości rem nadal liczą się względem niej, ale czytelnik nie może już przeskalować całej strony. Zostaw root w domyślnej wartości albo użyj procentu.
Mieszanie px i rem bez systemu. Niektóre rozmiary czcionek w px, niektóre w rem, odstępy podzielone między oba: w efekcie układ skaluje się nierównomiernie, gdy użytkownik dostosowuje tekst. Wybierz rem jako domyślną jednostkę, a px zarezerwuj dla świadomych wyjątków z tabeli decyzyjnej.
Używanie em do globalnych odstępów. Em na szeroko zagnieżdżonych kontenerach przywraca pułapkę kumulacji, więc padding głęboko w drzewie daje coś, czego nikt nie zamierzał. Trzymaj globalne odstępy w rem; em zachowaj dla lokalnych wartości w obrębie komponentu.
Nadawanie line-height jednostki. Jak opisano wyżej, line-height: 24px lub 1.5em zostaje odziedziczone jako obliczona długość i psuje się na elementach o różnych rozmiarach czcionek. Zawsze używaj bezjednostkowego mnożnika.
FAQ
Czy rem jest lepszy od px?
W przypadku większości wymiarowania tak: rem jest lepszy od px, bo skaluje się z preferencją rozmiaru czcionki przeglądarki użytkownika, którą px ignoruje. Ale „lepszy” zależy od właściwości: px jest właściwym wyborem dla stałych detali, jak obramowania 1px i przesunięcia cieni, które mają pozostać ostre. Używaj rem do wymiarowania treści, px do detali renderowania.
Ile to 1rem w pikselach?
1rem równa się rozmiarowi czcionki roota w pikselach, czyli domyślnie 16px w praktycznie wszystkich przeglądarkach. Zatem 1rem = 16px, 1.5rem = 24px, a 2rem = 32px w standardowej konfiguracji. Jeśli arkusz stylów nadpisuje html { font-size } — na przykład na 10px sztuczką z 62.5% — wtedy 1rem równa się tej wartości.
Powinienem używać rem czy em do font-size?
Używaj rem do font-size w niemal każdym przypadku. Rem mierzy względem roota, więc pozostaje przewidywalny bez względu na to, jak głęboko element jest zagnieżdżony. Em mierzy względem rozmiaru czcionki rodzica, co kumuluje się w dół drzewa i sprawia, że zagnieżdżony tekst nieoczekiwanie się rozrasta. Em zarezerwuj dla lokalnych wartości związanych z pojedynczym komponentem.
Kiedy używać px zamiast rem?
Używaj px do wartości, które nie powinny się skalować z rozmiarem czcionki użytkownika: obramowań 1px, precyzyjnych przesunięć box-shadow, pierścieni fokusa i innych stałych detali renderowania. To ostre detale projektowe, a nie treść, więc przypięcie ich w px jest bardziej dostępnym wyborem. Wszystko związane z treścią nadal powinno używać rem.
Dlaczego media query psują się, gdy używam px?
Punkty przełamania w media query w px nie reagują na powiększenie rozmiaru czcionki przeglądarki. Gdy użytkownik powiększa domyślną czcionkę, jego treść potrzebuje więcej miejsca, ale breakpoint px nadal przełącza się przy tej samej szerokości viewportu, więc układ zmienia się w niewłaściwym momencie. Używaj breakpointów em lub rem, które skalują się z rozmiarem czcionki użytkownika.
Czym jest sztuczka z czcionką 62.5%?
Sztuczka z 62.5% ustawia html { font-size: 62.5% }, czyniąc rozmiar czcionki roota równym 10px (62.5% z 16). Przy bazie 10px matematyka rem staje się „podziel przez 10”: 24px = 2.4rem, 12px = 1.2rem. Programiści ustawiają następnie body { font-size: 1.6rem }, by przywrócić czytelny tekst 16px.
Czy można mieszać px, rem i em?
Tak, mieszanie px, rem i em jest prawidłowe, gdy każda jednostka podąża za właściwością, do której pasuje: rem do typografii i odstępów, px do stałych detali, em do lokalnych wartości w obrębie komponentu. Kłopoty sprawia mieszanie ich bez systemu — na przykład niektóre rozmiary czcionek w px, a niektóre w rem. Wybierz rem jako domyślną jednostkę, a px i em traktuj jako świadome wyjątki.
Jakiej jednostki używać do paddingu i marginesu?
Używaj rem do paddingu i marginesu, by odstępy skalowały się razem z tekstem, gdy użytkownik dostosowuje rozmiar czcionki. To utrzymuje układ proporcjonalnym i dostępnym. Em zarezerwuj dla paddingu, który ma podążać za własnym rozmiarem czcionki elementu, jak przycisk, którego padding rośnie wraz z tekstem, i unikaj em na głęboko zagnieżdżonych kontenerach, gdzie się kumuluje.