Довжина рядка, масштаби відступів, темні поверхні, тіні та кільця фокусу в CSS
Дізнайтеся основи CSS, які лежать в основі витончених інтерфейсів: довжина рядків, заснована на значенні ch, шкала відстаней 4px, багатошарові темні поверхні, багатошарові тіні та кільця для позначення активного елемента.
Веб-додаток може мати стильний градієнт, скляні картки та плавні анімації, проте вже через кілька секунд використання здається незавершеним. Нічого не зламано, проте візуальний ритм нагадує прототип на вихідні, а не продукт рівня Linear, Stripe чи Vercel. Причиною зазвичай є не палітра кольорів чи брак художнього таланту. Це здебільшого кілька конкретних рішень у CSS щодо довжини рядків, відстаней між елементами, контрасту, висоти та станів фокусу, і ця стаття показує, як правильно їх налаштувати.
Обмежте довжину рядка за допомогою одиниць ch
Текст, який заповнює всю ширину монітора 1440px, є одним із найочевидніших ознак неопрацьованого фронтенду. Дуже довгі рядки важко читати: як тільки кількість символів у рядку перевищує приблизно 80, погляд змушений повертатися до лівого краю, і часто при цьому потрапляє не на той рядок. На довгій сторінці постійне пошукання правильного місця є виснажливим.
Зазвичай це виглядає так: контейнер повної ширини без жодних обмежень для абзацу:
{/* BAD: Unbounded text stretches across the whole viewport */}
<div className="w-full p-8">
<h1 className="text-3xl font-bold">API Documentation</h1>
<p className="text-slate-300 mt-4 text-base">
Our platform enables developers to authenticate and stream webhook events in real-time... (stretches 1200px wide)
</p>
</div>
Рішення: регулювати розмір блоків тексту за кількістю символів
CSS має одиницю вимірювання, створену саме для цієї проблеми. ch дорівнює ширині символа „0“ у шрифті, тож використання цієї одиниці дозволяє контролювати кількість символів у рядку незалежно від розміру шрифту. Зручне читання зазвичай передбачає від 45 до 75 символів у рядку. Клас для прозового тексту може поєднувати обмеження за рахунок ch, достатню висоту рядка та трохи зменшений міжбуквенний інтервал:
/* Clean readable prose container */
.prose-container {
max-width: 68ch; /* Optimal line length regardless of font size */
line-height: 1.65;
letter-spacing: -0.01em;
}
У Tailwind утиліта max-w-prose забезпечує подібне обмеження (65ch), а mx-auto центрує колонку:
{/* Enterprise Grade: Beautiful, focused reading experience */}
<div className="max-w-prose mx-auto px-6 py-12">
<h1 className="text-3xl font-bold tracking-tight text-white">
API Documentation
</h1>
<p className="mt-4 text-slate-300 text-base leading-relaxed">
Our platform enables developers to authenticate and stream webhook events in real-time...
</p>
</div>
Якщо тримати документацію, пости у блогу та описовий текст у межах приблизно 65–70ch, ці сторінки відразу виглядають збалансованими та привабливими. Застосовуйте це до блоків тексту, а не до всієї структури сайту.
Використовуйте міжрядковий інтервал у масштабі 4px/8px
Проаналізуйте класи-вспомогу в кодбазі, яка здається недосконалою, і ви часто знайдете такі значення:
- відступи для картки —
p-[18px] - маржа для модального вікна —
mt-5(20px) - відступи для кнопки —
px-3.5 py-[7px] - розстояння між елементами розділу —
gap-7(28px)
Кожне з цих значень було обрано тому, що воно виглядало нормально на певному екрані у певний момент, але разом вони руйнують просторовий ритм. Люди сприймають послідовні інтервали навіть без усвідомлення цього, і коли значення відступів не мають між собою жодного зв’язку, лейаут виглядає хаотичним та розривчастим.
Шкала значень, яку варто застосувати
Усталені системи дизайну обмежують використання відступів кратно 4 або 8 пікселям та надають кожному кроку певну назву та призначення. Практична шкала виглядає так:
space-1(4px): мікро-відстань, наприклад, проміжок між іконкою та її позначеннямspace-2(8px): компактний відступ для бейджів та малих тегівspace-3(12px): внутрішній відступ полів формиspace-4(16px): стандартний відступ для карток та кнопокspace-6(24px): проміжки між карткамиspace-8(32px): розділення між розділамиspace-12(48px): розділення між основними блоками панелі керування
Усе, що виходить за межі цієї шкали, наприклад margin-top: 19px, слід вважати дефектом, а не вибором стилю. За замовчуванням у Tailwind вже використовуються кроки по 4px, тому на практиці слід уникати довільних значень у дужках.
Уникайте суто чорного фону у темному режимі
Типовою першою спробою створення темного інтерфейсу SaaS є використання повністю чорного фону з повністю білим текстом:
/* The Harsh Dark Mode Trap */
body {
background-color: #000000;
color: #ffffff;
}
Білий колір на чорному створює максимальний можливий коефіцієнт контрасту 21:1. Це легко відповідає мінімальним вимогам доступності, але при такому екстремальному контрасті яскравий текст може здаватися розмитим або сяючим на тлі (ефект гало), що багатьом читачам, особливо тим, хто має астигматизм, здається виснажливим, особливо на екранах OLED та з високим контрастом.
Більшою проблемою є глибина. Поверхні, які знаходяться ближче до спостерігача або до джерела світла, природно виглядають трохи яскравішими. Якщо базовий шар вже має кольори #000000, не залишається можливості відрізнити картку, меню зі списком або модальне вікно, оскільки чорний колір не може стати ще темнішим під ними.
Створення ієрархії шарів
Замість цього використовуйте глибокі, злегка забарвлені темні відтінки, поступово збільшуючи світлість у міру підйому елементів вгору. Перша частина набору токенів визначає чотири рівні поверхні — від основної площини сторінки до накладок, таких як модальні вікна та підказки:
:root {
/* Slate / Charcoal Depth Stack */
--bg-canvas: #090d16; /* Deepest background */
--bg-surface: #0f172a; /* Cards, tables, sidebar */
--bg-elevated: #1e293b; /* Dropdowns, popovers, active tabs */
--bg-overlay: #334155; /* Modals, tooltips */
Решта того ж блоку :root додає два рівні прозорості для країв та три рівні тексту — від заголовків до позначок часу та неактивних іконок. Зверніть увагу, що в наведеному фрагменті декларації --border-active та --text-primary розташовані на одному рядку; це допустимо в CSS, але краще переформатувати цей код. Крім того, #f8fafc — це майже білий колір, а не білий з прозорістю 95%:
--border-subtle: rgba(255, 255, 255, 0.08);
--border-active: rgba(255, 255, 255, 0.16); --text-primary: #f8fafc; /* 95% opacity white for headings */
--text-secondary: #94a3b8; /* Muted slate for body text */
--text-tertiary: #64748b; /* Inactive icons, timestamps */
}
При застосуванні до маркапу: основна площина знаходиться внизу, карточка використовує колір поверхні з тонким краєм, а заголовки та основний текст використовують токени первинного та вторинного тексту:
{/* Clean, layered elevation */}
<div className="bg-[var(--bg-canvas)] min-h-screen p-8">
<div className="bg-[var(--bg-surface)] border border-[var(--border-subtle)] rounded-xl p-6 shadow-sm">
<h2 className="text-[var(--text-primary)] font-semibold">
Workspace Overview
</h2>
<p className="text-[var(--text-secondary)] text-sm mt-1">
Manage team roles and API keys.
</p>
</div>
</div>
Тепер ієрархія формується лише на основі світлості, без необхідності використання темних тіней.
Замініть одну темну тінь кількома світлими
Інтерфейси для початківців зазвичай використовують одну темну, розмиту тінь:
/* BAD: One thick, dark, muddy shadow */
.card-bad {
box-shadow: 0 10px 20px rgba(0, 0, 0, 0.5);
}
Результат нагадує застарілий ефект редагування фотографій. Реальні об’єкти не створюють однорідного розмиття. Фізична тінь складається з двох компонентів:
- тісна тінь з високим контрастом прямо біля об’єкта, яка утворюється під дією основного джерела світла
- широка, м’яка тінь, яка поступово зникає в оточенні; її називають амбієнтною оклюзією
Використовуйте тіні з низькими значеннями альфа
box-shadow приймає список, розділений комами, тож ви можете накласти дві чи три тіні, кожна з невеликим значенням альфа. Тут тінь завтовшки 1px створює основу для елемента, середнє розмиття додає глибину, а широка, дуже м’яка тінь поширює ефект:
/* Polished Enterprise Shadow */
.card-elevation-high {
box-shadow:
0 1px 2px rgba(0, 0, 0, 0.06), /* Crisp grounding line */
0 8px 16px rgba(0, 0, 0, 0.08), /* Middle ambient blur */
0 24px 48px rgba(0, 0, 0, 0.12); /* Soft dispersed glow */
}
На темних фонах тіні важко розгледіти, тому їм потрібна вища прозорість, а тонка світла рамка значною мірою допомагає відокремити елемент. Значення негативного розповсюдження запобігають тому, щоб темна тінь виходила за межі елемента:
/* In dark mode, pair subtle shadow with a crisp top border */
.card-dark-elevation {
box-shadow:
0 20px 25px -5px rgba(0, 0, 0, 0.5),
0 8px 10px -6px rgba(0, 0, 0, 0.5);
border: 1px solid rgba(255, 255, 255, 0.08);
}
Замість накладення вирізаного з паперу елемента на чорний фон, він здається завислим прямо над полотном.
Ніколи не видаляйте контури фокусу без заміни
Одна рядка завдає більше шкоди, ніж будь-яка інша у стилісних таблицях фронтенду:
/* DO NOT DO THIS */
*:focus {
outline: none;
}
Команди додають його тому, що стандартний кільце фокусу браузера конфліктує з елементами з власним стилем. Його видалення без запропонування альтернативи ускладнює користувачам клавіатури визначення того, який елемент знаходиться у фокусі, що робить інтерфейс для них практично непридатним та порушує вимоги доступності.
Використовуйте замість цього :focus-visible
Сучасні браузери підтримують :focus-visible, який активується лише тоді, коли браузер вирішує, що потрібен індикатор фокусу, зазвичай під час навігації за допомогою клавіатури, а не після клацання мишею. Це дозволяє прибрати індикатор для користувачів миші, зберігши його для користувачів клавіатури. Перший крок — це видалення стандартного обрамлення з кнопок:
/* Remove ugly mouse clicks, preserve crystal-clear keyboard rings */
button:focus {
outline: none;
}
Другий крок — це визначення чіткого власного індикатора фокусу для клавіатури:
button:focus-visible {
outline: 2px solid #6366f1; /* Crisp indigo ring */
outline-offset: 2px;
border-radius: 6px;
}
Є два важливі моменти, які варто знати. По-перше, безпечнішою формою першого правила є button:focus:not(:focus-visible), яка видаляє обрамлення лише тоді, коли не потрібен видимий індикатор, тож браузери без підтримки :focus-visible зберігають своє стандартне обрамлення. По-друге, параметр border-radius у правилі фокусу змінює форму кнопки під час її активації; якщо у кнопки вже круглі кути, цю строку можна пропустити, оскільки сучасні браузери малюють обрамлення, яке відповідає радіусу елемента.
У Tailwind ту саму ідею реалізовано за допомогою варіантів focus-visible:, які додають обрамлення, зсув та колір зсуву, що підбирається до темного фону:
<button className="px-4 py-2 bg-indigo-600 hover:bg-indigo-500 rounded-lg text-white font-medium focus:outline-none focus-visible:ring-2 focus-visible:ring-indigo-400 focus-visible:ring-offset-2 focus-visible:ring-offset-slate-900 transition-all">
Save Changes
</button>
Поведінка outline-none у Tailwind змінилася між основними версіями (новіші релізи додають outline-hidden), тож перевірте свою версію. У будь-якому разі користувачі миші отримують чистий інтерфейс керування, а користувачі клавіатури завжди бачать, де знаходиться фокус.
Чек-лист для доробки перед злиттям
Пройдіться по цих перевірках перед тим, як випустити зміни фронтенду:
- Ширина тексту: чи обмежені блоки тексту приблизно до 50–75ch?
- Відступи: чи всі внутрішні та зовнішні відступи формуються за суворою шкалою 4px/8px?
- Шари темного режиму: чи поверхні створені з комбінації відтінків вугілля чи сланцю, а не з прямого
#000000? - Тіні: чи тіні є м’якими, багатошаровими та розсіяними, а не просто однією темною розмитістю?
Підсумок
Якість реалізації залежить скоріше від послідовних обмежень, ніж від художньої інтуїції: довжина рядків, заснована на ch, фіксована шкала відступів, світлість як показник глибини у темних темах, тіні, що імітують справжнє світло, та кільця фокусу, які залишаються видимими. Кожне з цих правил є простим та легким для перевірки, тож його можна застосовувати за допомогою спеціальних токенів, правил перевірки коду та чек-листів, замість того щоб покладатися на смак у кожному pull request.
Пов’язана література
- Десять прихованих проблем компонентів React, які уповільнюють сучасні додатки — Дізнайтеся про десять поширених помилок у компонентах React — від проблем із семантичним HTML до відсутності мемоїзації — та про способи їх усунення, які допоможуть зберегти швидкість, доступність та відсутність помилок у додатках у 2026 році.
- Що насправді робить розробників фронтенду цінними в епоху ШІ — Пояснюється, чому розуміння ситуації, здатність до оцінки та системне мислення зараз мають більше значення, ніж володіння фреймворками, оскільки ШІ бере на себе рутинну роботу з кодування фронтенду.