Этап 4: Модальное окно
Free PreviewПоиск и фильтрация работают. Теперь добавим модальное окно — при клике на карточку пользователь видит полную информацию о месте.
Требования
HTML-структура модального окна
- Добавьте в
index.htmlодин элемент модального окна. Он должен существовать в DOM с самого начала, но быть скрыт. - Структура внутри: крупное изображение, бейдж категории, название, адрес, рейтинг, полное описание, кнопка закрытия.
- За пределами внутреннего блока — полупрозрачный backdrop, клик по которому закрывает модалку.
Рекомендуемая HTML-структура. Внешний элемент — сам backdrop (полупрозрачный оверлей на весь экран). Внутри него — блок с контентом. Это удобно: клик вне блока с контентом будет кликом по backdrop:
<div class="modal" id="modal"> <div class="modal__content"> <button class="modal__close" id="modalClose">×</button> <img class="modal__image" id="modalImage" src="" alt=""> <div class="modal__body"> <span class="modal__category" id="modalCategory"></span> <h2 class="modal__title" id="modalTitle"></h2> <p class="modal__address" id="modalAddress"></p> <div class="modal__rating" id="modalRating"></div> <p class="modal__description" id="modalDescription"></p> </div> </div> </div>htmlCSS для модалки:
position: fixed; inset: 0— фиксирует оверлей на весь экран. Скрытое состояние удобнее всего реализовать черезopacity: 0; pointer-events: none, а видимое — через классmodal--openсopacity: 1; pointer-events: auto. Это позволяет анимировать черезtransition: opacity.
Открытие и закрытие
- Клик по карточке открывает модалку с данными именно этой достопримечательности.
- Используйте делегирование: один обработчик на контейнере сетки, а не по обработчику на каждой карточке.
- Кнопка закрытия (×) закрывает модалку.
- Клик по backdrop закрывает модалку. Клик по содержимому модалки — нет.
- Нажатие
Escapeзакрывает модалку. - Пока модалка открыта, страница под ней не прокручивается (
document.bodyполучает нужный стиль). - После закрытия прокрутка восстанавливается.
Как найти нужный объект при делегировании. Карточка имеет
data-id. При клике найдите ближайшую карточку черезclosest, возьмите id и найдите объект вstate.attractions:grid.addEventListener('click', (e) => { const card = e.target.closest('.card'); if (!card) return; const id = Number(card.dataset.id); const attraction = state.attractions.find(a => a.id === id); openModal(attraction); });js
Как отличить клик по backdrop от клика по контенту. Слушайте клик на самом модальном оверлее и проверяйте
e.target:modal.addEventListener('click', (e) => { if (e.target === modal) closeModal(); // кликнули именно по backdrop, не по содержимому });js
Блокировка прокрутки. Стандартный приём — добавить
overflow: hiddenнаbody:function openModal(attraction) { document.body.style.overflow = 'hidden'; modal.classList.add('modal--open'); // заполнить поля... } function closeModal() { document.body.style.overflow = ''; modal.classList.remove('modal--open'); }js
Анимация
- Открытие и закрытие должны быть анимированы: плавное появление backdrop и самого окна.
- Реализуйте через CSS-классы и
transition— не через JS-анимацию.
CSS-подход к анимации. Базовое состояние — модалка невидима и некликабельна. Класс
modal--openделает её видимой. Переход прописывается в базовом состоянии:.modal { position: fixed; inset: 0; background: rgba(0, 0, 0, 0.6); opacity: 0; pointer-events: none; transition: opacity 0.25s ease; display: flex; align-items: center; justify-content: center; } .modal--open { opacity: 1; pointer-events: auto; } .modal__content { transform: translateY(20px); transition: transform 0.25s ease; } .modal--open .modal__content { transform: translateY(0); }css
Наполнение данными
- При открытии модалки заполняйте её содержимое данными из объекта достопримечательности.
- Храните ссылку на текущий открытый объект в
state— она пригодится в следующем этапе (для кнопки избранного внутри модалки).
Заполнение полей модалки. Прямое обращение по id удобнее
querySelectorвнутри функции:function fillModal(attraction) { document.getElementById('modalImage').src = attraction.image; document.getElementById('modalImage').alt = attraction.name; document.getElementById('modalTitle').textContent = attraction.name; document.getElementById('modalCategory').textContent = attraction.category; document.getElementById('modalAddress').textContent = attraction.address; document.getElementById('modalRating').textContent = `★ ${attraction.rating}`; document.getElementById('modalDescription').textContent = attraction.description; }js
Продвинутое задание — URL hash
Реализуйте навигацию через хэш URL: когда модалка открывается, добавляйте в адресную строку #attraction-1 (где 1 — id места). При закрытии убирайте хэш. При загрузке страницы проверяйте хэш и если он есть — автоматически открывайте нужную модалку.
Это позволяет делиться прямой ссылкой на конкретное место. Изучите:
window.location.hash- событие
hashchange - MDN: Location.hash
Ожидаемый результат
- клик по карточке открывает модалку с данными этой достопримечательности
- в модалке есть изображение, категория, название, адрес, рейтинг, описание
- модалка закрывается по кнопке ×, клику по backdrop и клавише Escape
- пока модалка открыта, страница не прокручивается
- открытие и закрытие анимированы
- клик внутри модалки не закрывает её