Модуль I · тема 4 · урок 1 з 2 · наскрізний проєкт STARTUP LAUNCH · 120 хвилин
У тебе вже є сервер, бриф і числа. Сьогодні ти задаси сторінці власні кольори, шрифт і знак. І запишеш їх у файл, який читає браузер.
Набір таких рішень — кольори, шрифт, знак, відступи — і зветься айдентикою продукту. Це те, за чим твою сторінку впізнають серед сотні чужих.
Робити це будемо не в графічному редакторі, а в коді. Кольори стануть
файлом brand.css, логотип — файлом assets/logo.svg.
Обидва лягають у ~/www/ й доживають до Demo Day.
Дизайн тут — не «зроби гарно». Це відстані в пікселях, лінії вирівнювання, розміри шрифтів і коефіцієнти контрасту.
Майже все це — числа. А числа можна порахувати й перевірити машиною. Тому айдентику здають як код, а не як картинку.
--brand-accent, ти міняєш бренд одним рядком. Щойно
#3b82f6 розповзся по сімнадцяти файлах — бренду більше немає,
є сімнадцять різних синіх.brand.css зі своїми кольорами
й чистити logo.svg від сміття редактора.Слова «контраст», «шрифтова пара» і WCAG поки нічого не означають — розберемо їх по черзі.
| Етап | Хв | Що робимо |
|---|---|---|
| Розігрів: слайд-жах | 10 | називаємо проблеми своїми словами, без термінів |
| Чотири принципи | 20 | близькість, вирівнювання, контраст, повторення — «до і після» |
| Ієрархія і типографіка | 20 | три рівні уваги, шрифтова пара, шкала, довжина рядка |
| Колір і контраст за WCAG | 20 | відносна яскравість, поріг 4,5:1, конструктор палітри |
| Ревізія макета за 60 секунд | 10 | чотири повзунки, індекс читабельності, вихід у brand.css |
| Практика: логотип | 20 | малюємо й чистимо SVG локально, viewBox і currentColor |
Практика: brand.css | 15 | токени у :root, <link> в index.html і brief.html |
| Автоперевірка й підсумок | 5 | check11 4, четвертий сегмент ракети |
brand.css і assets/logo.svg. Наскрізний критерій
no_media діє й сьогодні.Близькість · вирівнювання · контраст · повторення
Коли макет «якийсь не такий», причина майже завжди в одному з чотирьох місць.
Ці чотири принципи описала Робін Вільямс у книжці «The Non-Designer’s Design Book». Вони працюють однаково для плаката, слайда й вебсторінки.
Чому так надовго. Принципи описують не моду, а те, як око збирає зображення докупи. Око за пів століття не змінилося.
| Принцип | Правило | Як виглядає порушення |
|---|---|---|
| Близькість | Що поруч — те пов’язане. Відстань між групами більша, ніж усередині групи | Підпис однаково далеко від «свого» і від чужого блоку; читач сам вирішує, що до чого |
| Вирівнювання | Кожен елемент стоїть на спільній лінії з іншим. Ліній має бути мало | Дев’ять елементів — дев’ять різних відступів зліва; сторінка «плаває» |
| Контраст | Якщо елементи різні — вони мають бути різними явно, а не трохи | Заголовок 17 px, текст 16 px: незрозуміло, це заголовок чи збій |
| Повторення | Один спосіб робити одне й те саме на всій сторінці | Три картки — три різні рамки, три радіуси, три відтінки синього |
На твоєму лендингу три заголовки, під кожним по абзацу. Однокласник каже:
«Незрозуміло, який опис до якого заголовка». У CSS у тебе
h3{margin:14px 0} і p{margin:14px 0}.
Що виправить це найшвидше?
Ти зробив три картки послуг. Перша — з рамкою й радіусом 2 px. Друга — залита сірим, без рамки. Третя — з жовтою рамкою й гострими кутами. Виглядає «різноманітно». Що насправді читає відвідувач?
Перше, друге, третє — і жодного «однаково важливого»
На екрані людина спершу не читає, а сканує. За першу секунду око вихоплює один-два об’єкти. Які саме — вирішуєш ти.
Керуєш ти чотирма речами. Розміром літер. Вагою — це товщина накреслення, від тонкого до жирного. Кольором. І простором навколо.
Найсильніший із чотирьох — простір. Елемент, навколо якого порожньо, читається першим. Навіть коли він менший за сусідів.
Тому в макеті спершу розганяють відстані. І тільки потім беруться за розмір шрифту.
На головному екрані твого лендингу назва продукту, слоган і кнопка «Спробувати» — усі трьома різними кольорами і всі великі. Учитель питає: «Що тут головне?» Ти відповідаєш «усе». Який найдешевший спосіб виправити це, не переверстуючи сторінку?
Дев’яносто відсотків твого лендингу — це текст
Шрифтів у продукті потрібно два: один для заголовків, другий для тексту. Можна й один — це не помилка, а дисципліна.
Три і більше — це вже не пара, а набір. Читач бачить не характер, а безлад.
Пара має контрастувати, а не бути схожою. Два майже однакові шрифти — те саме, що заголовок 17 px над текстом 16 px. Різниця є, а сенсу в ній немає.
Системний шрифт уже стоїть на пристрої користувача. Завантажувати його не треба, і це дає три виграші.
Перший: на один запит до сервера менше. Другий: сторінка легшає на 30–100 КБ за кожне накреслення.
Третій помітний найбільше. Веб-шрифт вантажиться не миттєво: спершу текст малюється запасним шрифтом, а потім перескакує на справжній. Літери «стрибають» просто перед очима.
З телефона по мобільному інтернету цей стрибок видно щоразу.
:root{
--font-head: "Segoe UI", system-ui, -apple-system, "Noto Sans", sans-serif;
--font-body: system-ui, -apple-system, "Segoe UI", "Noto Sans", sans-serif;
}
/* стек читається зліва направо: перший шрифт, який є в системі,
той і бере. Останнім завжди стоїть загальна родина — sans-serif */
Якщо береш шрифт із вебу — бери два накреслення, не шість. І перевір, чи є в ньому кирилиця.
Шрифт без кирилиці браузер мовчки замінить системним. Твоя айдентика протримається до першого українського слова.
Розміри не вигадують окремо для кожного заголовка. Береш базовий розмір 16 px і множиш на 1,25. Виходить 20. Множиш 20 — виходить 25. Далі 31, далі 39.
Такий ряд і зветься розмірною шкалою. Кожен розмір у макеті ти береш із неї, а не з голови.
Навіщо. Шкала не дає з’явитися рядку «21 px, бо 20 замалувато». У макеті лишається шість розмірів замість двадцяти.
Комфортний рядок — 60–75 символів разом із пробілами. Довший рядок змушує око шукати початок наступного, і читач збивається. А закороткий рве фразу на шматки.
У CSS це один рядок: max-width: 66ch. Одиниця
ch — це ширина нуля в поточному шрифті. Побільшав шрифт —
обмеження поїхало за ним само.
Міжрядковий інтервал для основного тексту — приблизно 1,5. Це не смак, а вимога.
Є список правил, за якими перевіряють, чи зручно читати сайт людині зі слабким зором або з телефона на сонці. Його склали ті, хто домовляється про стандарти вебу. Великі сайти на цей список рівняються, а державні зобов’язані його виконувати.
Зветься список WCAG — Web Content Accessibility Guidelines, тобто «правила доступності вебвмісту». Правила в ньому пронумеровані.
Правило 1.4.12 якраз і просить, щоб текст лишався читабельним при інтервалі 1,5. Далі на сторінці трапляться ще номери — це той самий список.
Для великих заголовків інтервал навпаки зменшують до 1,1–1,2. Інакше рядки заголовка розповзаються.
Планувальник збирає дедлайни з усіх предметів в один список і нагадує про них за день. Ти не заводиш завдання руками: розклад підтягується з класного журналу, а домашка — з чату класу. Кожен дедлайн можна відкласти один раз, і планувальник запам’ятає, скільки разів ти це робив із кожного предмета.
Рядок закороткий — близько 32 символів, фраза рветьсяПланувальник збирає дедлайни з усіх предметів в один список і нагадує про них за день. Ти не заводиш завдання руками: розклад підтягується з класного журналу, а домашка — з чату класу.
Так треба — max-width: 66ch, міжрядковий 1,6Планувальник збирає дедлайни з усіх предметів в один список і нагадує про них за день. Ти не заводиш завдання руками: розклад підтягується з класного журналу, а домашка — з чату класу. Кожен дедлайн можна відкласти один раз, і планувальник запам’ятає, скільки разів ти це робив із кожного предмета.
Ти виставив body{max-width:100%}, і на моніторі 27 дюймів
абзаци тягнуться через увесь екран. Учитель каже: «Читати неможливо».
Що з переліченого — найкоротше правильне виправлення?
Основний, акцент, нейтралі, статусні — і коефіцієнт контрасту, який усе вирішує
Палітра продукту — це не «кольори, які мені подобаються». Це ролі. Кожен колір відповідає рівно за одну.
Яскравих кольорів у палітрі всього два: фірмовий і акцентний. Решта — сірі різної світлості: фон, поверхня картки, лінії, текст.
Візьмеш третій яскравий — і око перестане розуміти, куди дивитися
першим. Тому автоперевірка рахує різні кольори в brand.css.
Більше восьми вона не пропустить.
| Роль | Скільки | За що відповідає |
|---|---|---|
| Основний (brand primary) | 1 | колір, за яким продукт упізнають: знак, головна кнопка, активний стан |
| Акцент (accent) | 1 | рідкісний і сильний: одна дія, яку ти хочеш, щоб натиснули |
| Нейтралі | 4–5 | фон, поверхня картки, лінії, основний текст, приглушений текст |
| Статусні | 0–2 | помилка й успіх; на лендингу часто не потрібні взагалі |
brand.css на цих місцях стоятимуть твої кольори.
Пропорція «90 % нейтралей, 10 % фірмових» — робочий орієнтир, а не закон.Контраст у вебі — не «на око світліше чи темніше». Це число, яке рахують за формулою. Формулу задає WCAG, і кроків у ній три.
Крок 1 — прибрати гаму. Кожен канал R, G, B ділять на 255. Далі отримане число «розпрямляють».
Робиться це так. Якщо значення ≤ 0,03928 — ділять на 12,92.
Якщо більше — беруть ((c + 0,055) / 1,055) у степені 2,4.
Навіщо крок. Монітор світиться нерівномірно: подвоєне число в коді не дає вдвічі яскравішої точки. Без розпрямляння числа брехали б.
Крок 2 — відносна яскравість.
L = 0,2126·R + 0,7152·G + 0,0722·B.
Коефіцієнти різні не випадково. Око бачить зелений набагато яскравіше за синій — приблизно вдесятеро. Формула просто повторює цю особливість ока.
Крок 3 — відношення.
(Lсвітлішого + 0,05) / (Lтемнішого + 0,05).
Мінімум — 1:1 (два однакові кольори), максимум — 21:1 (чорний на білому).
#CCCCCC, #9A9A9A, #767676,
#595959, #222222 на білому #FFFFFF.
#767676 — найсвітліший сірий, який ще проходить 4,5:1 на білому.Приблизно кожен дванадцятий чоловік і кожна двохсота жінка розрізняють кольори інакше, ніж ти. Найпоширеніша форма — червоно-зелена. Для такого користувача твій «зелений = вільно, червоний = зайнято» — це дві однакові плями. Те саме буває й без жодних особливостей зору: чорно-біла роздруківка, дешевий проєктор, екран на сонці.
Вимога WCAG 1.4.1 звучить просто: колір не має бути єдиним способом передати інформацію. Колір лишається — до нього додають другий сигнал: значок, підпис, форму, штрихування, підкреслення.
| Тільки кольором | Колір + другий сигнал |
|---|---|
| Червоне поле форми | Червоне поле + значок і текст «вкажи пошту» |
| Зелена й червона точки в статусі | Точки + підписи «вільно» / «зайнято» |
| Посилання відрізняється лише кольором | Посилання підкреслене |
| Дві лінії на діаграмі різного кольору | Різний колір + суцільна і пунктирна |
Твій сірий текст на білому виглядає стильно на твоєму ноутбуці, а з проєктора в класі його не видно. Яке число це передбачає — і чому воно показує проблему ще до того, як ти дійшов до кабінету?
У формі відгуків на твоєму сайті незаповнене поле підсвічується червоною рамкою — і більше нічим. Тестує однокласник, який не розрізняє червоний і зелений. Що він побачить і що треба додати?
Обери один колір — сторінка добудує решту, порахує кожну пару і згенерує brand.css
Нижче — не «підбірка гарних кольорів». Сторінка бере твій основний колір і виводить із нього решту палітри.
Далі для кожної пари вона проходить ті самі три кроки: розпрямляє гаму, рахує яскравість, ділить одне на друге.
Числа, які ти бачиш, справжні. Те саме порахує check11 4
на сервері.
| Пара | Де це видно | Поріг | Контраст |
|---|
Рядок «лінія → фон» — довідковий: суто декоративний
роздільник порога не має. Але щойно ти обводиш тією самою лінією поле
вводу чи кнопку, вона стає межею елемента керування — і тоді за WCAG
1.4.11 їй потрібно 3:1. У такому місці бери не --brand-line,
а --brand-muted: він уже проходить 4,5:1.
Скопіюй, збережи як brand.css у кодуванні
UTF-8 і поклади в ~/www/. Значення можна й потрібно правити
руками — конструктор дає робочу основу, а не вирок.
Конструктор показує: текст на фоні — 12,4:1, а біла підпис на твоїй основній кнопці — 2,1:1. Ти кажеш: «Головне ж 12,4, перевірка пройде». Що з цим не так на практиці?
Чотири повзунки — чотири принципи. Той самий макет, інші числа
Ліворуч — навмисно поганий екран продукту. Поганий він не тому, що «негарний».
У ньому одночасно порушені всі чотири принципи. Крути повзунки й дивись, як міняється кожен складник індексу. Мета — 90 і вище.
дедлайни, домашка й нагадування в одному місці
Індекс — середнє арифметичне чотирьох складників, по 25 % кожен. Складник «контраст» рахується з реального коефіцієнта WCAG між кольором заголовка й фоном макета. Три інші складники — оцінка, придумана автором сторінки для цієї вправи: у стандартах таких чисел немає.
Це той самий файл, що й у конструкторі вище: обидва
інструменти працюють з однією палітрою й пишуть в один
brand.css. Ревізія додає до нього ритм —
--gap-group і --radius. Зміни основний колір —
і макет ревізії перефарбується разом із файлом.
Ти витягнув індекс до 92, але зробив це так: відступ між групами 46 px, вирівнювання 100 %, контраст 100 %, повторення 100 %. На екрані телефона половина блоків поїхала за межу першого екрана. Що показує ця ситуація про сам індекс?
Дизайн-токен — це той самий майстер-слайд, тільки в коді
Уяви: ти написав color:#3b82f6 у чотирьох файлах
і сімнадцяти правилах. Через тиждень вирішив, що синій занадто
«банківський».
Тепер треба знайти всі сімнадцять місць. І не переплутати
з #3b81f6 — його ти одного разу набрав із помилкою.
Одне місце легко пропустити. Через місяць у продукті буде три різні сині, і жоден не буде «кольором бренду».
CSS-змінна прибирає цю проблему повністю. Значення живе в одному місці, у решті коду стоїть ім’я ролі:
:root{
--brand-primary: #3b82f6;
}
.btn { background: var(--brand-primary); }
a { color: var(--brand-primary); }
.logo svg { color: var(--brand-primary); }
/* міняєш бренд — правиш один рядок, а не сімнадцять */
Токен --blue живе до того дня, коли бренд стане зеленим.
У коді залишиться рядок --blue: #16a34a. Ім’я вже бреше.
А --brand-primary переживе будь-яку зміну кольору.
Воно називає призначення, а не відтінок.
Те саме з відступами: --gap-group краще за
--gap-24.
| Погане ім’я | Добре ім’я | Чому |
|---|---|---|
--blue | --brand-primary | колір зміниться, роль — ні |
--gray-3 | --brand-muted | з номера не видно, де це застосовувати |
--big | --fs-h1 | «великий» відносно чого? |
--px24 | --gap-group | значення прив’язане до імені й не міняється |
Головна вигода токенів видно саме тут. Темна тема не переписує жодного правила оформлення.
Вона лише підставляє інші значення в ті самі змінні. Усе, що написане
через var(--brand-…), перефарбовується саме собою.
:root{
--brand-bg: #f7f8fa;
--brand-text: #14181d;
}
/* 1) якщо в системі увімкнено темну тему */
@media (prefers-color-scheme: dark){
:root:not([data-theme="light"]){
--brand-bg: #0d1116;
--brand-text: #e6ebf0;
}
}
/* 2) якщо користувач сам натиснув перемикач */
:root[data-theme="dark"]{
--brand-bg: #0d1116;
--brand-text: #e6ebf0;
}
Два блоки потрібні тому, що станів три: «як у системі», «світла примусово», «темна примусово».
Сторінка, яку ти зараз читаєш, зроблена так само. Відкрий її на телефоні з темною темою й порівняй.
#0d1116, а текст —
#e6ebf0, і жоден із них не є ані чистим чорним, ані чистим
білим. Конструктор вище рахує темну пару окремо — саме тому в таблиці
є рядок «темна тема».На уроці 6 ти зробиш deck.html на токенах бренду. Перед
Demo Day ти вирішуєш змінити основний колір. У першому варіанті кольори
в деку прописані літералами #3b82f6, у другому — через
var(--brand-primary) з підключеного brand.css.
У чому різниця за часом і чому це питання не про красу?
viewBox, currentColor і чому вектор тут не обговорюється
Відкрий logo.svg звичайним блокнотом. Ти побачиш текст:
тут коло, тут прямокутник, тут лінія від точки до точки.
SVG — не картинка, а список інструкцій «що намалювати». Тому знак правиться в редакторі коду, лягає в Git і важить кілька сотень байтів.
| Питання | Растр (PNG, JPG) | Вектор (SVG) |
|---|---|---|
| Що зберігається | сітка пікселів | інструкції: фігури й координати |
| Банер 3×2 метри | розсипається на квадрати | та сама чіткість |
| Вага знака | десятки–сотні КБ | частки кілобайта |
| Змінити колір | перемалювати й перезалити | один рядок CSS |
| Темна тема | потрібен другий файл | currentColor — той самий файл |
| Пошук і читання | непрозорий бінарник | звичайний текст, індексується |
viewBox, збільшена втричі,
щоб було видно координати. Права — той самий знак у дев’яти рядках
тексту. Файл із цим кодом важить близько 340 байтів.viewBox="0 0 64 64" каже: усередині файлу малюнок має
розмір 64 на 64. У цих одиницях і записані всі координати.
width і height кажуть інше: покажи це
на екрані ось такого розміру.
Тому та сама розмітка малює і фавікон 16 px, і знак на банері. Міняється лише друге число.
Без viewBox малюнок прив’язується до пікселів і не
тягнеться. Це найчастіша причина скарги «SVG чомусь не росте на всю
ширину».
fill="currentColor" означає «візьми колір із CSS-властивості
color того місця, куди мене вставили». Один файл — і в шапці
знак фірмовий, у підвалі приглушений, у темній темі світлий:
/* працює тільки для інлайнового SVG — вставленого прямо в HTML. Той самий файл через <img src="logo.svg"> кольору ззовні не бачить */ .site-head .logo { color: var(--brand-primary); } .site-foot .logo { color: var(--brand-muted); } .btn .logo { color: var(--brand-bg); }
Редактор — Inkscape, Figma, Illustrator — експортує SVG зі своїм сміттям. Це його службові записи: чужі атрибути, порожні групи, номер на кожній точці.
Інколи всередину потрапляє навіть ціла растрова картинка. Ось що прибрати.
<metadata>, <defs> без вмісту, коментарі редактора;inkscape:, sodipodi:, data-name;id на кожній фігурі — вони потрібні редакторові, не тобі;currentColor;<g> з єдиною дитиною — вони нічого не роблять;<image> — це вставлений растр, і такий «SVG» перевірку не пройде.Числа у виводі ілюстративні: у твоєму файлі буде свій розмір
і свій viewBox. Важливі тут лише два факти — нуль у першому
рядку і наявність viewBox у другому.
logo.svg і brand.css у UTF-8.
У Windows PowerShell 5.1 ключ -Encoding utf8 додає на початок
файлу BOM — три невидимі байти. Для XML це зайвий клопіт, тож надійніше
зберігати без BOM:
[IO.File]::WriteAllText($p,$t,(New-Object Text.UTF8Encoding $false))
або просто «UTF-8 without BOM» у налаштуваннях редактора. У Git Bash,
macOS і Linux звичайне перенаправлення > BOM не додає.Твій logo.svg важить 180 КБ і в редакторі коду починається
з рядка <image width="512" height="512"
xlink:href="data:image/png;base64,iVBORw0KGgo…. Автоперевірка його
відхиляє. Що сталося і що робити?
Ти вставив логотип як <img src="assets/logo.svg">
і прописав у CSS .logo{color:var(--brand-primary)}. Знак
лишається чорним у будь-якій темі. Чому і як це виправити?
brand.css і assets/logo.svgВиконуй по черзі. Галочки зберігаються — сторінку можна закрити.
brand.css → ~/www/ і logo.svg →
~/www/assets/. Обидва — легкий текст.check11 4 (перша частина)Сервер розбере твій brand.css, порахує контраст
за тією самою формулою WCAG і подивиться на logo.svg як на
XML. Спроби не обмежені.
Демонстраційний режим: результат згенеровано для показу.
На сервері ця кнопка запускає check11 4 від імені учня
і читає ~/.progress/11-4.json. Друга половина
check11 4 закриється на уроці 6 разом із
pitch.html, deck.html і og.png.
contrast_45 блокує оцінку, бо весь урок був саме про це число:
палітра, у якій основний текст не читається, — це не «інший смак»,
а несправна сторінка. no_media діє наскрізно весь модуль:
у ~/www/ і ~/upload/ не має бути
.mp4 .mov .avi .mkv .webm .mp3 .wav .flac і файлів понад 2 МБ.
На уроці 14 check11 8 прожене ці перевірки повторно.logo.svg;Це те, що бачить учитель, коли виставляє оцінку.
| Складник | Вага | Результат |
|---|
brand.css окремим
блоком-коментарем. Конструктор палітри вже видає цей блок — але
числа звір сам і, якщо треба, поправ.index.html, у DevTools постав фільтр
filter: grayscale(1) на body і перевір, чи
лишається зрозумілим, де що. Якщо ні — знайди місце, де сенс тримався
лише на кольорі, і додай другий сигнал.~/notes/brand.md три речення: який колір
основний і чому саме він для твого продукту, яка шрифтова пара і чому,
який коефіцієнт контрасту в пари «текст — фон». Це чернетка слайда
«айдентика» для Demo Day.pitch.html з якорями й автозмістом, HTML-презентація
deck.html на восьми слайдах і прев’ю посилання в месенджері.
Дек будується на твоїх токенах: кольори в ньому мають бути
var(--brand-…), а не літералами. Сьогоднішній
brand.css — це те, з чого він буде зроблений.Пороги контрасту, формула яскравості й вимоги до розмітки — зі стандартів, а не з чийогось смаку. Перевіряти дозволено й корисно.
ch — ширина символу «0» у поточному шрифті —
w3.org · CSS Values 4, §5.1.1:root, читання через
var(), успадкування й перевизначення —
w3.org · CSS Custom Properties for Cascading Variables,
MDN · Using CSS custom propertiesprefers-color-scheme — як браузер повідомляє про темну
тему системи —
MDN · prefers-color-schemeviewBox: своя система координат SVG і її відмінність
від width/height —
w3.org · SVG 2, §8.3 viewBoxcurrentColor — значення, що бере колір із властивості
color —
w3.org · CSS Color 4,
MDN · currentcolorrole="img" і
<title> —
w3.org · SVG Accessibility API Mappings,
MDN · SVG titlesystem-ui —
w3.org · CSS Fonts 4, system-uiКоефіцієнти на «драбині контрасту» пораховані автором
сторінки за формулою WCAG для конкретних сірих на білому
#FFFFFF — їх можна перевірити будь-яким калькулятором
контрасту. «Індекс читабельності» в ревізії макета — вигадана автором
сторінки навчальна оцінка: у стандартах такого показника немає,
справжнє в ньому лише складник контрасту. Розмірна шкала 1,25 —
загальновживана практика, а не вимога. Повний список джерел із
поясненнями — у файлі urok-05-джерела.md поруч
із цією сторінкою.