Запропонувати правкуПокращити цю статтюДопрацюйте відповідь до «CSS одиниці: px, rem, em». Ваші зміни проходять модерацію перед публікацією.Потрібне підтвердженняКонтентЩо ви змінюєте🇺🇸EN🇺🇦UAПереглядЗаголовок (UA)Коротка відповідь (UA)**CSS одиниці px, rem та em** відрізняються точкою відліку. `px` - абсолютний, фіксований. `em` множиться на font-size батька і накопичується при вкладенні. `rem` множиться на font-size кореневого `html` і однаковий в будь-якому місці документа. ```css html { font-size: 16px; } .text { font-size: 1.5rem; } /* 24px, завжди */ .box { font-size: 1.5em; } /* залежить від батька */ ``` **Правило:** `rem` для типографіки і відступів, `px` для рамок.Показується над повною відповіддю для швидкого нагадування.Відповідь (UA)Зображення**CSS одиниці px, rem та em** визначають точку відліку для розмірів: фіксований піксель, font-size батька або font-size кореневого елемента. ## Теорія ### TL;DR - `px` - цегла: фіксований розмір, не залежить ні від батька, ні від root - `em` відносний до font-size батьківського елемента і накопичується при вкладенні - `rem` відносний до font-size кореневого `html` і однаковий скрізь - Проблема em: три рівні по 1.2em = 1.728em (1.2³), а не 1.2em - Правило вибору: `rem` майже скрізь, `px` для рамок і тіней, `em` коли відступ має масштабуватись разом зі шрифтом компонента ### Швидкий приклад ```css html { font-size: 16px; } /* база для rem */ .parent { font-size: 2rem; } /* 32px */ .child-em { font-size: 1.5em; } /* 48px - множиться на 32px батька */ .child-rem { font-size: 1.5rem; } /* 24px - множиться тільки на 16px root */ .child-px { font-size: 20px; } /* 20px - завжди 20px */ ``` `.parent` має 2rem (32px). Його `child-em` при 1.5em дає 48px, а не 24px. `rem` ігнорує батька і бере значення прямо з кореневого елемента. ### Ключова різниця Все вирішує точка відліку. `px` її не має - завжди те саме число. `em` бере обчислений font-size батька і множить: глибоке вкладення дає накопичувальний ріст. `rem` завжди читає обчислений font-size `html`, тому 1.5rem - це 24px незалежно від того, наскільки глибоко вкладений елемент. ### Коли що використовувати - **Типографіка і відступи (більшість випадків)**: `rem` масштабується з налаштуваннями браузера і ОС - **Рамки (border), box-shadow, outline**: `px` тримає краї чіткими, масштабування тут не потрібне - **Padding або margin пропорційний шрифту компонента**: `em`, наприклад `padding: 0.75em` на кнопці, що росте і зменшується разом зі своїм текстом - **Глибоко вкладені меню або компоненти**: `rem` замість `em`, щоб уникнути накопичувальної математики - **Лінії в 1px та дрібні іконки**: тільки `px` ### Таблиця порівняння | Аспект | px | em | rem | |---|---|---|---| | Точка відліку | Фіксована (1/96 дюйма) | font-size батька | font-size кореневого `html` | | Ефект вкладення | Немає | Накопичується (1.2em x 1.2em = 1.44em) | Однакова скрізь | | Зум користувача | Фіксований | Масштабується від батька | Масштабується від root | | Доступність | Ігнорує налаштування шрифту | Слідує за батьківським ланцюгом | Враховує налаштування root | | Найкраще для | Рамки, тіні | Локальні пропорції компонента | Типографіка, відступи, макет | ### Як браузер обчислює одиниці Браузер вирішує одиниці під час cascade. Спочатку обчислюється font-size кореневого `html` (за замовчуванням 16px, якщо не перевизначено). `rem` читає це значення напряму. `em` проходить вгору по дереву стилів до батька і множить. Обидві одиниці перетворюються на абсолютні пікселі перед layout. `px` минає все це. ### Типові помилки **Використовувати em для загальних відступів** ```css /* ламається при вкладенні */ .menu { font-size: 1.2em; } .menu li { font-size: 1.2em; } /* вже 1.44em */ .menu li a { font-size: 1.2em; } /* 1.728em - не те, що задумувалось */ /* рішення */ .menu li a { font-size: 1rem; } ``` Три рівні по 1.2em дають 1.728 від базового розміру. Такі проблеми важко відстежити у великих проєктах. **Ставити px для тексту** ```css /* неправильно: налаштування шрифту користувача ігноруються */ body { font-size: 16px; } /* правильно: масштабується з налаштуваннями */ body { font-size: 1rem; } ``` WCAG вимагає, щоб текст масштабувався з налаштуваннями шрифту користувача. `px` блокує це. Це питання доступності, а не просто стиль. **Використовувати em для border** ```css /* добре */ button { border: 1px solid #333; font-size: 1rem; } /* виглядає дивно при великих шрифтах */ button { border: 0.1em solid #333; } ``` Рамки потребують фіксованого чіткого краю. `em` на border змінює її товщину разом зі шрифтом компонента, що рідко є наміром. ### Де зустрічається в реальних проєктах - Tailwind CSS: `p-4` = 1rem, класи border використовують `px` - Bootstrap 5: базовий `$spacer: 1rem`, фіксовані елементи в `px` - Material-UI (MUI): типографіка теми через `h1: { fontSize: '2rem' }` - Chakra UI: rem-based токени відступів по всій бібліотеці ### Додаткові питання **Q:** Який розмір шрифту root за замовчуванням у браузері? **A:** 16px. Але користувач може змінити це в налаштуваннях браузера. Фактичне значення можна перевірити через `getComputedStyle(document.documentElement).fontSize`. **Q:** Чи впливає viewport meta на rem? **A:** Опосередковано. `width=device-width` встановлює базу логічних пікселів на мобільних. rem все одно береться від font-size `html`, але загальний макет масштабується під viewport. **Q:** Чому box-shadow краще задавати в px? **A:** Тіні з `rem` можуть виглядати розмитими при нестандартному зумі. `px` тримає їх чіткими, бо рендеринг тіней відбувається на рівні пікселів, а не шрифтів. **Q:** У CSS-in-JS (Emotion, Styled Components) як працювати з rem при динамічному root? **A:** Читай значення root під час виконання через `getComputedStyle(document.documentElement).fontSize`, потім конвертуй px в rem програмно. Більшість утиліт для тем у цих бібліотеках роблять це автоматично. **Q:** Браузерний зум теж масштабує px. То в чому реальна різниця з доступності? **A:** Зум масштабує все, включно з `px`. Але налаштування шрифту на рівні ОС (не зум) впливають тільки на відносні одиниці. Користувач із системним шрифтом 20px отримає користь від `rem`, але не від `px`. ## Приклади ### Накопичення em ламає вкладену навігацію ```css :root { font-size: 16px; } .nav { font-size: 1.125rem; } /* 18px */ .nav > li { font-size: 1.2em; } /* 21.6px */ .nav > li > a { font-size: 1.1em; /* 23.76px - виросло ненавмисно */ padding: 0.5em; /* 11.88px - теж непередбачувано */ } /* рішення: перейти на rem для внутрішніх елементів */ .nav > li > a { font-size: 1rem; /* 16px - передбачувано */ padding: 0.5rem; /* 8px - передбачувано */ } ``` Два рівні em-вкладення підняли шрифт вище 23px. Перехід на `rem` прив'язує все до root, незалежно від батьківського ланцюга. ### Кнопка на rem, яка враховує налаштування користувача ```css :root { font-size: 16px; } .btn { font-size: 1rem; /* 16px, масштабується з root */ padding: 0.75rem 1.5rem; /* 12px вгору/вниз, 24px по боках */ border-radius: 4px; /* px - чіткі кути */ border: 1px solid #333; /* px - тонка чітка лінія */ } ``` Якщо користувач виставив базовий шрифт 20px, шрифт кнопки і padding масштабуються автоматично. Border залишається 1px - саме таку тонку чітку лінію ти і хочеш. Я бачив проєкти, де все було в `px`, а команда витрачала дні на дебагінг проблем з доступністю. Один перехід на `rem` вирішував більшість з них.Для рев’юераПримітка для модератора (необов’язково)Бачить лише модератор. Прискорює рев’ю.