Как стать автором
Обновить

Комментарии 28

if ((bodyElementHTML.style.overflowY = "hidden")) {
  ...
} else {
  ...
}

Есть подозрение, что else-ветка тут лишняя.

Или...

... условие надо на == переделать.

Прочитал Ваш комментарий, да, функция немного была некорректно составлена с лишними телодвижениями, теперь достаточно просто сделать отступ на величину ширины ползунка прокрутки. Спасибо!

Простейшая модалка:

<dialog style="padding: 0">
  <div id="modal-box" style="padding: 1rem">
    <div>Modal content</div>
    <button id="close-modal-btn">Close</button>
  </div>
</dialog>
<button id="show-modal-btn">Show modal</button>
const modal = document.querySelector('dialog')
const modalBox = document.getElementById('modal-box')
const showModalBtn = document.getElementById('show-modal-btn')
const closeModalBtn = document.getElementById('close-modal-btn')

let isModalOpen = false

showModalBtn.addEventListener('click', (e) => {
  modal.showModal()
  isModalOpen = true
  e.stopPropagation()
})

closeModalBtn.addEventListener('click', () => {
  modal.close()
  isModalOpen = false
})

document.addEventListener('click', (e) => {
  if (isModalOpen && !modalBox.contains(e.target)) {
    modal.close()
  }
})

Я ждал Ваш комментарий. Если бы была возможность — плюсанул бы Вам за использование нативных инструментов без костылей и велосипедов

Тег dialog является экспериментальным. Взять тот же mdn, к примеру firefox. Версия, где поддерживается этот тег выпущена 2022-03-08. Для safari аналогичная ситуация - 2022-03-15. Поэтому на простых костылях сделал окно для возможности использования без проблем в старых браузерах. Спасибо за комментарий в любом случае!

Проблема с плохой поддержкой dialog решается при помощи полифила. В браузере проверяется поддержка dialog и этот скрипт подключается при помощи динамического импорта, если браузер не поддерживает dialog.

Преимущества этого элемента в том, что он нативный, имеет встроенные методы и атрибуты для открытия/закрытия, семантику и доступен из коробки.

Спроектировать хорошее модальное окно не такая уж и тривиальная задача. Нужно стилиовать окно и бэкдроп, при этом предусмотреть возможность кастомизации. Нужно написать логику и API для работы, при этом предусмотреть различные сценарии использования. Нужно позаботиться о семантике и сделать его действительно модальным - роль, все нужные aria-состояния и focus trap. Нужно продумать работу с клавиатуры, перемещение по интерактивным элементам внутри, закрытие через крестик и Esc. Нужно правильно реализовать бэкдроп, чтобы контент под ним не был интерактивным и страница не прокручивалась. Также нужно учесть, что в окне может быть разный контент и не допустить переполнения. И это все ещё нужно реализовать максимально кросбраузерно.

Спасибо за развернутый и подробный комментарий! В данном примере я не старался использовать полифилы лишь по одной причине - данный тип модального окна, на мой взгляд, достаточно прост и не занимает много строчек кода, используя также самые обычные средства для реализации. Вся логика и API предоставляются для Читателя. Об этом я постарался подумать и сделал возможность позиционирования и верстки элементов внутри окна при открытии. Все остальные пожелания или изменения в работе окна, а также взаимодействие с ним - индивидуальны и зависят от задачи)

z-index всё же следует поднять, потому что на сайте могут быть обычные элементы, у которых z-index больше одного.

Да, Вы правы, величину надо регулировать в зависимости от необходимого наслоения. Я указал его равным 1 из соображений, что элемент со свойством z-index один на странице. Спасибо!

Такой крестик можно нарисовать используя CSS transform:

.modalClose {
 float:right;
 cursor:pointer;
 position:relative;
 width:20px;
 height:20px;
 display:flex;
 flex-direction:column;
 justify-content:center
}
.modalClose::before,
.modalClose::after {
 position:absolute;
 content:'';
 width:100%;
 height:2px;
 background-color:#000;
}
.modalClose::before {
 transform:rotate(45deg);
}
.modalClose::after {
 transform:rotate(-45deg)
}

В таком случае будет проще добавить, скажем, hover, а не заморачиваться со сменой цветов в SVG через filter:

.modalClose:hover::before,
.modalClose:hover::after {
 background-color:Red;
}

Спасибо за фидбек! Честно, не хотелось особо сильно заморачиваться с CSS. Поэтому и сделал расчет из удобства, чтобы вставить любую картинку, выступающую в роли "крестика"

хабр стал похож на отчетную страницу первого класса, огромное достижение - модальное окно....
ну ж если и выкладывать - то уж хотя бы c с использованием template, Shadow DOM, grid, ну и возможностью перемещения этого окна по экрану.

и за что плюсанули в карму? за приглашение от НЛО?

Спасибо за комментарий! Первая мысль, как сделать модальное окно - с использованием самых простых вещей без особого изощрения. Если есть примеры создания модального окна с этими инструментами - я буду рад их увидеть! Честно говоря не представляю как использовать теневое дерево, разве что скрыть модальное окно, чтобы его нельзя было достаточно легко отобразить через средства разработчиков. Но опять же, не совсем знаю, как эта технология устроена, ибо не использую, а читал для ознакомления.

Зачем вы так говорите? Это же модалка на ЧИСТОМ CSS и JS. Раньше модалку можно было только на React + Tailwind, а теперь вот, прогресс!

Спасибо за комментарий! Я рад, что у Вас получилось освоить построение веб-страниц сразу же начиная с использованием фреймворков. Простое модальное окно на ванильном JS и CSS ничем не хуже их аналогов с использованием соответствующих библиотек, тем более в обучении (как я и указал, что не так давно занялся веб-разработкой)

Для этого в html добавили тег dialog, со встроенными методами открытия и закрытия через js и оверлеем)

Да, он является экспериментальным. Хоть и поддержка от chrome была ещё в 2014 году, но тот же самый safari и firefox начали поддерживать его в марте 2022 года. Поэтому я и решил сделать простейшее модальное окно с использованием "палок". В любом случае - спасибо за фидбек!

Я ожидал увидеть нативный dialog , после прочтения статьи еще раз заголовок прочитал...

Нативный dialog поддерживается не так давно в полном объеме, о чем пишет mdn. Поэтому и модальное окно сделано "нативнее" нативного :). Спасибо за фидбек!

А модальность окна в чем заключается? Статья про div в виде окна, не более. Нативный dialog - не просто тег и он, как минимум, уже поддерживается. Почитайте еще про атрибут inert, технику focus trap, accessibility... И обновите свой пример, он сломан, так как modalTrigger пропущен.

Спасибо за комментарий! Модальность заключается в том, что при нажатии на modalTrigger у нас открывается окно поверх других элементов на странице. Сам же modalTrigger я отдельно вынес и указал, что его задаем сами (т.е. любой элемент на Вашей странице). Спасибо также за материал, прочитаю и ознакомлюсь!

Модальность должна ограничивать пользователя во взаимодействии с родительским окном. В вашем случае доступ с клавиатуры никак не блокируется. Только указатель (к примеру, курсор мыши) и то при условии, что всякие там z-index у родителя и его потомков не будут перекрывать ваше окно. Проблема всей статьи в том, что слой поверх слоя можно было и 10 лет назад сделать относительно просто на "чистом CSS и JS", а вот именно модальное окно уже сильно сложней, если вообще осуществимо даже сейчас (т.е. воссоздать поведение нативного dialog в полной мере).

JS там за тем, что статья называется "Модальное окно на чистом CSS и JS" :)

В любом случае - спасибо за дополнительные вариации модальных окон, там есть реально классные варианты!

Мне как новенькому в веб разработке, было очень полезно прочитать вашу статью

Спасибо! Сейчас думаю, какой материал выкладывать периодически, по мере сложности и полезности. Планирую как и по фронтенду, так и по бекенду

.modalActive {
    position: absolute;
    width: 350px;
    height: 495px;
    top: 50%;
    left: 50%;
    border-radius: 10px;
    background-color: rgb(255, 255, 255);
    cursor: default;
    padding: 40px 20px;
    transform: translate(-50%, -50%)
}

Если в дальнейшем потребуется изменение размеров модального окна у вас возникнет потребность с пересчетом top и left. Используйте для центрирование transform. Почитать подробнее про него можно здесь.

Спасибо! Да, такой способ центрирования намного удобнее и не зависит от параметров окна. Применил у себя :)

upd: при наличии ползунка прокрутки модальное окно не учитывает его величину и надо задавать дополнительный отступ, чтобы окно позиционировалось по центру. Этот способ удобен, когда мы не учитываем длину страницы по оси Y и нам неважно, будет ли сайт смещаться влево или нет. В моём случае я дополнительно смещаю сайт, чтобы он всегда был по центру, поэтому надо продумать момент с позиционированием окна тоже

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории