Чому ваш сайт виглядає порожнім на 2K-моніторі
3 хв читанняCSSадаптивTailwind
Макет намальовано на 1440, а екрани бувають 2560 і 3440. Розповідаємо, як зробити, щоб сайт масштабувався цілком, а не тільки розтягував поля - і чому це не ламає доступність.
Відкрийте будь-який сучасний лендінг на моніторі 2560px. Найімовірніше ви побачите те саме, що й на ноутбуці, тільки з величезними порожніми полями обабіч. Контейнер уперся в свою максимальну ширину і зупинився, а екран - ні.
Це не помилка верстальника. Так працює стандартний підхід: фіксовані брейкпоінти й контейнер із межею. Питання в іншому - чи це те, що ви хотіли показати клієнту, який купив дорогий монітор.
Що робить більшість - і чому цього замало
Найпоширеніша відповідь - додати ще один брейкпоінт і на ньому збільшити кілька заголовків. Проблема в тому, що збільшуються саме «кілька». Решта лишається: відступи, іконки, рамки, висоти карток. Виходить сторінка, де заголовок уже великий, а кнопка під ним - ні.
Інший підхід: одна одиниця замість брейкпоінтів
Якщо макет намальовано на ширині 1440, то будь-який розмір у ньому - це частка від 1440. Замість того щоб перераховувати їх руками на кожному брейкпоінті, можна оголосити одну змінну, яка означає «один піксель макета 1440», і виражати через неї геть усе.
:root {
--u: max(1px, 0.06944vw);
}Далі розмір задається не пікселями, а множенням: 16px тексту стає calc(16 * var(--u)), відступ 24px - calc(24 * var(--u)). На 1440 усе точно як у макеті. На 2560 усе разом більше в 1.78 раза: і текст, і відступи, і іконки, і радіуси.
У Tailwind це робиться в одному місці - у темі. Переписавши шкалу відступів, розмірів шрифтів і максимальних ширин через цю одиницю, ви отримуєте пропорційність у кожному вже написаному класі, не торкаючись компонентів.
Головне заперечення: а як же доступність
Стандартна претензія до розмірів у vw така: користувач не зможе збільшити текст, а WCAG 1.4.4 вимагає можливості збільшити до 200%. І це справедливо для чистого vw.
Саме тут працює max(1px, ...). Коли людина натискає Ctrl+, браузер зменшує CSS-вьюпорт: 1440 при 200% стає 720. Це нижче за 1440, тож одиниця впирається у свій поріг і стає рівно 1px - текст повертається до базового розміру і далі відображається зі збільшенням. Тобто зум працює точно так само, як на сайті з фіксованими пікселями.
Той самий поріг вирішує ще одну задачу: нижче 1440 нічого не зменшується. Одиниця там дорівнює пікселю, і сайт поводиться як звичайний адаптивний макет із вашими брейкпоінтами. Масштабування вмикається тільки вгору.
Де це ламається
Чесно про підводні камені, бо їх кілька і всі вони знаходяться однаково - вимірюванням, а не читанням коду.
- Довільні значення в обхід теми. Клас на кшталт text-[11px] написаний прямо в компоненті теми не знає і лишиться 11px назавжди. Такі місця треба знайти всі до одного.
- Атрибути SVG. Іконка з width="14" height="14" не масштабується, бо це атрибут, а не CSS. Розмір треба задавати класом.
- Вкладені системи координат. Якщо блок уже масштабується трансформом, то одиниця всередині нього помножиться вдруге - і вміст роз'їдеться відносно рамки.
- Класи Tailwind, яких немає у шкалі. Написавши py-18 при відсутньому кроці 18, ви отримаєте не помилку, а мовчазну відсутність відступу.
Як перевірити, що вийшло
Не на око. Відкрийте сторінку на 1440 і на 2560, зніміть обчислений font-size тих самих елементів і поділіть одне на одне. Має вийти 1.78 у всіх - у заголовка, у навігації, у тексту абзацу. Якщо десь 1.00, ви знайшли пропущене місце.
Пропорційність - це властивість, яку або має вся сторінка, або не має жодна її частина. Половина відмасштабованих елементів виглядає гірше, ніж нуль.