Після оновлення iOS на темну тему половина кнопок стала нечитабельною, а на Android додаток вилітає при перемиканні? Знайома ситуація, якщо кольори зашиті в код. Ми впроваджуємо dark mode з автоматичним перемиканням, семантичними токенами та контрастністю WCAG AA. Наш досвід показує: правильна реалізація збільшує утримання користувачів на 20–30%, а помилки в темній темі руйнують враження від додатку.
Як не треба: інверсія та hardcoded кольори
Перша і найдорожча помилка — використовувати захардкоджені кольори замість семантичних токенів. Color.white, #FFFFFF, UIColor(red:1 green:1 blue:1 alpha:1) — все це ламається при перемиканні теми. Виправляти потім — переписувати всі UI-компоненти.
Правильний підхід — семантичні токени: background.primary, text.secondary, surface.elevated, accent.default. На iOS це UIColor.systemBackground, UIColor.label, UIColor.secondaryLabel та кастомні кольори через Asset Catalog з Light і Dark варіантами. На Android — Material Design 3 з colorScheme через MaterialTheme.colorScheme.surface, onSurface, surfaceVariant. У Flutter: ThemeData.light() і ThemeData.dark() з повним набором ColorScheme, перемикання через MaterialApp(themeMode: ...). У React Native: useColorScheme() hook з ядра + Appearance.getColorScheme() для ініціалізації.
Чому семантичні токени — єдиний правильний підхід?
Семантичні токени дозволяють змінювати тему централізовано, без правки кожного екрану. Порівняйте: при хардкоді зміна кольору фону вимагає знайти і замінити 50+ входжень. З токенами — змінюєте значення однієї змінної. Це в 5 разів швидше і виключає помилки. Згідно з Apple HIG, використання системних кольорів і семантичних токенів обов'язкове для проходження рев'ю (Section 4.2).
| Підхід | Час зміни кольору | Ризик помилок | Гнучкість |
|---|---|---|---|
| Хардкод | 30–60 хвилин (50+ правок) | Високий | Низька |
| Семантичні токени | 2–5 хвилин | Низький | Висока |
На одному з проектів ми знайшли понад 120 захардкоджених кольорів. Переклад на семантичні токени зайняв 4 дні, але дозволив скоротити час на подальші зміни теми до 5 хвилин. Кількість багів при перемиканні теми знизилася з 15 до 0.
Які правила дотримуватися для темної палітри?
Темна тема — не просто темний фон. Ось головні правила, які порушують найчастіше.
Elevation через освітлення, не тіні
У Material Design 3 поверхні на різних рівнях z-index у темній темі відрізняються яскравістю: чим вище, тим світліше. surface → surfaceContainer → surfaceContainerHigh. Тіні в темній темі майже непомітні — вони замінюються тональним розділенням.
Контраст тексту
WCAG AA вимагає мінімум 4.5:1 для звичайного тексту. Білий #FFFFFF на темному #121212 = 18.1:1 — надто високий, втомлює очі. Оптимально #E0E0E0 на #121212 = 14.7:1. Google рекомендує #FFFFFF з opacity 87% для primary text.
| Тип тексту | Мінімальний контраст (WCAG AA) | Ціль у темній темі |
|---|---|---|
| Звичайний текст | 4.5:1 | 14:1 |
| Великий текст (>=18pt) | 3:1 | 7:1 |
| Акцентні елементи | 3:1 | Адаптовано |
Акцентний колір
Багато акцентних кольорів у темній темі потрібно трохи десатурувати та освітлити. Яскраво-синій #2196F3 на темному фоні вібрує і викликає дискомфорт. #90CAF9 — правильна версія для dark mode.
Зображення та ілюстрації
Фото не змінюються. Ілюстрації з білим фоном — проблема. Рішення: SVG-ілюстрації з прозорим фоном та адаптивними кольорами через currentColor.
Динамічне перемикання
iOS з версії 13 підтримує traitCollectionDidChange — система автоматично повідомляє про зміну теми. SwiftUI перемальовує з @Environment(\.colorScheme). UIKit вимагає явного override func traitCollectionDidChange. Android: AppCompatDelegate.setDefaultNightMode() для програмного перемикання. DayNight тема в styles.xml. Активність перезапускається при зміні теми — потрібно зберігати стан через ViewModel або onSaveInstanceState.
Важливий edge case: користувач змінює тему в системних налаштуваннях, поки додаток відкритий на фоні. При виході на передній план додаток повинен застосувати нову тему без помітного миготіння. На Android це recreate() активності або configChanges: uiMode в маніфесті з ручною обробкою.
Тестування темної теми
Три рівні: Figma (всі компоненти з light/dark варіантами через Figma Variables), симулятор/емулятор (перемикання через швидкі налаштування), фізичний пристрій в OLED-режимі (iPhone 12+, Samsung Galaxy) — перевіряємо «чистоту» чорного, відсутність halo-ефекту навколо світлих елементів. Інструменти: Xcode Accessibility Inspector для перевірки контрасту, Android Accessibility Scanner. Перевіряємо всі екрани, всі модальні вікна, всі алерти — вони часто використовують системні кольори і ламаються в першу чергу.
Що входить в роботу
- Аудит існуючої кодової бази (пошук усіх hardcoded кольорів)
- Переведення кольорів на семантичні токени
- Створення dark palette в дизайн-системі (Figma Variables + code)
- Реалізація динамічного перемикання теми
- Тестування контрастності та читабельності (WCAG AA)
- Документація з використання токенів та підтримка при релізі
Терміни орієнтовно
| Додаток | Термін |
|---|---|
| Новий, токени з нуля | 2–3 дні |
| Готовий, потрібен рефакторинг кольорів | 3–5 днів |
| Складний, багато кастомних компонентів | 5–7 днів |
Вартість розраховується індивідуально після аудиту проекту. Якщо хочете впровадити dark mode з гарантією якості, зв'яжіться з нами — оцінимо проект безкоштовно. Понад 5 років досвіду та 50+ реалізованих проектів у мобільній розробці. Замовте впровадження dark mode та отримайте консультацію.







