Домашнє завдання #12: Модалка та dropdown для твого продукту
Твій продукт з ДЗ #5 досі був статичним. Сьогодні він уперше відреагує на користувача: ти створиш два UI-компоненти, які є буквально на кожному сайті — модальне вікно та dropdown меню. Але не абстрактні, а для своєї теми: у фільмотеці модалка може показувати деталі фільму, dropdown — обирати сортування. У колекції рецептів — «переглянути рецепт» і «фільтр за складністю». Механіка однакова, зміст — твій.
Що ти вже маєш
- Стилізований лендінг свого продукту з ДЗ #6 — компоненти мають виглядати як його частина (кольори, шрифти, кнопки)
Можеш вбудувати компоненти прямо в лендінг або зробити окрему сторінку в тому ж стилі.
Файлова структура
hw-12/
├── index.html
├── style.css
├── script.js
└── screenshots/
├── desktop.png
├── mobile.png
└── interaction.png
Частина 1: Модальне вікно
Кнопка на сторінці (наприклад, «Детальніше» на картці фільму) відкриває модалку поверх сторінки. Вигляд:
┌─────────────────────────────────────────┐
│ ░░░░░░░░░░░ затемнений фон ░░░░░░░░░░░ │
│ ░░░░┌───────────────────────────┐░░░░░ │
│ ░░░░│ [✕] │░░░░░ │
│ ░░░░│ Назва фільму │░░░░░ │
│ ░░░░│ Опис, рік, рейтинг... │░░░░░ │
│ ░░░░│ │░░░░░ │
│ ░░░░└───────────────────────────┘░░░░░ │
│ ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ │
└─────────────────────────────────────────┘
Сценарії поведінки
Відкриття:
- Користувач клікає на кнопку → модалка з'являється по центру екрана, фон за нею затемнюється
- Поки модалка відкрита, сторінка під нею не прокручується (спробуй покрутити колесо миші — фон стоїть на місці)
Закриття — рівно три способи, і всі мають працювати:
- Клік на кнопку закриття (хрестик у кутку модалки)
- Клік на затемнений фон поза модалкою (клік по самій модалці її НЕ закриває!)
- Натискання клавіші
Escape
Після закриття прокрутка сторінки знову працює.
Анімація:
- Модалка з'являється плавно, а не «вистрибує»: фон поступово затемнюється, саме вікно трохи збільшується або з'їжджає згори
- Анімація зроблена через CSS (
transition+ перемикання класів), а не через JavaScript-таймери
Частина 2: Dropdown меню
Мінімум три dropdown-кнопки з випадаючими списками. Придумай їх під свою тему: «Сортувати за…», «Жанр», «Рік» — або меню навігації.
[ Сортувати ▾ ] [ Жанр ▾ ] [ Рік ▾ ]
┌─────────────┐
│ За рейтингом │
│ За роком │
│ За назвою │
└─────────────┘
Сценарії поведінки
- Клік на кнопку → під нею розкривається меню. Повторний клік — закривається
- Взаємовиключність: відкритий може бути лише один dropdown. Відкриваєш другий → перший закривається сам
- Клік будь-де поза dropdown (по фону сторінки) → усі відкриті меню закриваються
- Клавіатура: коли фокус на кнопці —
EnterабоSpaceвідкриває/закриває меню;Escapeзакриває відкрите меню - Меню з'являється з плавною анімацією (CSS)
Підказки
Рівень 1: напрямок думки
- «Показати/сховати» у CSS — це перемикання класу на елементі. JavaScript лише додає/знімає клас, а вигляд описаний у стилях
- Затемнений фон (overlay) — окремий елемент на весь екран, а модалка — його дочірній елемент. Тоді «клік по фону» і «клік по модалці» можна розрізнити
- Для взаємовиключності dropdown подумай так: «перш ніж відкрити цей — закрий усі інші»
- «Клік зовні» — це подія на всьому документі, у якій треба зрозуміти, чи стався клік усередині dropdown
Рівень 2: які інструменти використати
classList.add/remove/toggle— перемикання станів- Порівняння
e.targetз елементом overlay покаже, що клікнули саме по фону, а не по вмісту модалки e.target.closest(селектор)поверне найближчого батька за селектором абоnull— так перевіряють «клік поза dropdown»- Подія
keydownнаdocument+ перевіркаe.key - Блокування прокрутки: клас з
overflow: hiddenнаbody - Плавне зникнення:
opacity+transition+pointer-events: none(боdisplay: noneне анімується).pointer-events: noneробить схований елемент «прозорим» для кліків
Рівень 3: псевдокод
Модалка:
клік на кнопку-відкриття:
зняти клас "hidden" з overlay
додати клас "no-scroll" на body
функція closeModal:
додати "hidden" на overlay
зняти "no-scroll" з body
клік на хрестик → closeModal
клік на overlay → якщо ціль кліку — сам overlay → closeModal
keydown на документі → якщо клавіша Escape → closeModal
Dropdown:
клік на кнопку-toggle:
для кожного dropdown, крім поточного → зняти клас "open"
перемкнути "open" на поточному
клік на документі:
якщо у цілі кліку немає батька-dropdown → закрити всі
keydown → якщо Escape → закрити всі
Бонус: фокус-пастка (+15)
Зроби модалку доступною з клавіатури по-дорослому — з фокус-пасткою:
- Коли модалка відкривається, фокус переходить на перший інтерактивний елемент усередині неї
Tab(іShift+Tab) циклічно ходить лише по елементах модалки й не виходить за її межі на сторінку під нею- Після закриття фокус повертається на кнопку, яка модалку відкрила
Саме так працюють модалки у великих продуктах — спробуй натиснути Tab у будь-якому діалозі GitHub.
Як здати
- Робота — у твоєму репозиторії курсу
my-web-course, у папціhw-12/ - Мінімум 3 коміти з осмисленими повідомленнями (не "fix" і не "update") — чекер бачить git-історію
- У папці —
README.md: 2-3 речення, що зроблено і як запустити - Скріншоти в
hw-12/screenshots/:desktop.png— сторінка на ширині ~1440pxmobile.png— на ширині ~390pxinteraction.png— відкрита модалка по центру із затемненим фоном
- Надішли посилання на репозиторій (можна одразу на папку
hw-12)
Критерії оцінки
| Критерій | Тип | Бали |
|---|---|---|
| Модалка відкривається кнопкою і закривається всіма трьома способами (хрестик, клік по фону, Escape); клік по самій модалці її не закриває | [поведінка] | 25 |
| Прокрутка сторінки заблокована, поки модалка відкрита, і відновлюється після закриття | [код] | 10 |
| Поява модалки анімована через CSS transition і класи, без JS-таймерів | [поведінка] | 10 |
| На interaction.png модалка по центру, фон затемнений | [скрін] | 10 |
| Мінімум 3 dropdown, кожен відкривається/закривається кліком | [поведінка] | 10 |
| Відкритий може бути лише один dropdown одночасно | [поведінка] | 10 |
| Клік поза dropdown закриває всі відкриті меню | [поведінка] | 10 |
| Клавіатура: Enter/Space перемикає dropdown, Escape закриває | [поведінка] | 10 |
| Компоненти адаптовані під тему продукту та вписані в стиль лендінгу (desktop.png + mobile.png) | [скрін] | 5 |
| Бонус: фокус-пастка в модалці (Tab не виходить за межі, фокус повертається після закриття) | [поведінка] | +15 |
Що далі
У ДЗ #14 ти збереш головний інтерактивний проєкт блоку — каталог своєї колекції. Модалка та dropdown звідси стануть у пригоді й там, і в React-версії продукту — не видаляй код.