Всем привет! Я в веб-разработке не так давно. Сейчас я пишу свой сайт, который будет выступать в качестве моего портфолио и, возможно, даже целого проекта. При добавлении модального окна для авторизации на свой сайт, я подумал, а что будет, если публиковать подобные модульные вещи, чтобы любой человек мог их скопировать и не думать о них, а использовать в разработке. То есть создать готовый модуль для встраивания. Мне, как разработчику было бы удобно использовать готовое решение, тем более написанное мною, да и делиться опытом - дело приятное :)
Для тех, кому надо сразу код и вид окна.
![](https://habrastorage.org/getpro/habr/upload_files/ef2/2cc/97c/ef22cc97c074a9a274ce00e9f9b692ce.png)
NB
сам сайт скрыт для сохранения интеллектуальной собственности :)
А теперь пошаговое создание:
<div class="modalBackground">
<div class="modalActive">
<div class="modalClose">
<img src="modalCross.svg" />
</div>
<div class="modalWindow"></div>
</div>
</div>
Здесь представлена несложная разметка для модального окна.
Перед разъяснением элементов и их стилей, мы укажем скрытие ползунка прокрутки для body, которое нам будет мешать:
/* убираем нижний ползунок прокрутки */
body {
overflow-x: hidden;
}
Давайте поясню, что есть что:
modalBackground - это фон, расположенный за модальным окном. Через него мы будем видеть наш сайт { background: rgba(0, 0, 0, 0.8); }, в то время как основной фокус будет на модальном окне. Для корректного расположения, чтобы наш фон покрывал весь сайт - мы делаем его с положением { position: fixed } и размерами на весь экран { width: 100%; height : 100%; }. А для наложения поверх других окон или элементов сайта - { z-index: 1 }. Стоит отметить, что изначально мы не можем видеть наше окно { display: none }. Для отображения возможности нажатия на фон - делаем указатель через { cursor: pointer; }
/* фон нашего модального окна */
.modalBackground {
display: none;
background: rgba(0, 0, 0, 0.8);
position: fixed;
width: 100%;
height: 100%;
cursor: pointer;
/* указываем z-индекс для корректного наслаивания */
z-index: 1;
}
modalActive - непосредственно наше модальное окно. Его размеры { width: 350px; height : 495px; } я подбирал исходя из удобства верстки для маленьких экранов, так что размеры можно указать свои. Мы позиционируем наше модальное окно по центру { position: absolute; top: calc(50% - 250px); left: calc(50% - 175px); }. Делаем рамки закругления в 10 пикселей { border-radius: 10px }. Курсор для удобства делаем стандартным { cursor: default }. Свойства background-color и padding в данном случае ни на что не влияют, они используются для фона нашего окошечка внутри и для внутренних отступов нашего окошечка соответственно. Поэтому их можно ставить на свой вкус и цвет :)
/* позиционирование самого модального окна */
.modalActive {
position: absolute;
width: 350px;
height: 495px;
top: calc(50% - 250px);
left: calc(50% - 175px);
border-radius: 10px;
background-color: rgb(255, 255, 255);
cursor: default;
padding: 40px 20px;
}
modalClose - это наш крестик. Я использовал два варианта выхода из модального окна, кому как удобнее - через нажатие на фон, либо через нажатие на крестик (этот вариант предпочтительнее для мобильных устройств из-за маленького экрана, по сравнению с монитором ноутбука/компьютера/планшета). Для крестика соответственно используется тег modalCross с указанием в img пути к картинке-крестика. Свойство font-family используется для выбора семейства шрифта, здесь оно не играет роли (на ваш вкус и цвет).
/* кнопочка закрытия модального окна */
.modalClose {
font-family: var(--font-regular);
position: absolute;
right: 5px;
top: 5px;
width: 30px;
height: 30px;
cursor: pointer;
}
/* сама картинка кнопочки закрытия */
.modalClose img {
margin: 3px;
width: 24px;
height: 24px;
}
modalWindow - внутри него располагается содержимое нашего окна, для удобной верстки внутреннего содержимого устанавливаем относительное позиционирование относительно нашего модального окна { position: relative }. Какое оно будет - зависит только от вас :)
/* делаем позиционирование внутренних элементов относительно модального окна */
.modalWindow {
position: relative;
}
Теперь приступим к части оживления нашего окна с помощью жабаскрипта JS !
Прежде всего нам надо получить все элементы, с которыми нам предстоит работать:
// устанавливаем триггер для модального окна (название можно изменить)
const modalTrigger = document.getElementsByClassName("trigger")[0];
// получаем ширину отображенного содержимого и толщину ползунка прокрутки
const windowInnerWidth = document.documentElement.clientWidth;
const scrollbarWidth = parseInt(window.innerWidth) - parseInt(document.documentElement.clientWidth);
// привязываем необходимые элементы
const bodyElementHTML = document.getElementsByTagName("body")[0];
const modalBackground = document.getElementsByClassName("modalBackground")[0];
const modalClose = document.getElementsByClassName("modalClose")[0];
const modalActive = document.getElementsByClassName("modalActive")[0];
Стоит отметить, что при использовании метода getElementsByClassName мы будем получать массив всех элементов. Поэтому для корректного обращения к конкретному элементу - мы указываем индекс получаемого элемента. А так как наши массивы состоят из одного элемента - индекс во всех случаях равен [0].
Переменная modalTrigger - содержит наш триггер, при нажатии на который у нас будет появляться наше модальное окно.
Если наш сайт длинный и у нас появляется ползунок прокрутки - мы получаем его длину и записываем в scrollbarWidth. Давайте тут поподробнее. Мы изначально получаем ширину видимой части сайта через свойство clientWidth. Ширина ползунка прокрутки - разность между шириной окна внутри и шириной отображаемого содержимого (то, что под ползунком - не является отображаемым содержимым). Для корректности мы преобразовываем полученные значения через функции parseInt.
Далее мы привязываем необходимые элементы к переменным в соответствии с названием их классов, для тега body мы используем метод getElementsByTagName с указанием индекса получаемого элемента, то есть [0]. Смысл такой же, как и при getElementsByClassName. Я заметил простую вещь - если читаешь название методов, то понимаешь что они тебе дают :). В нашем случаем мы получаем множество элементов (окончание s в слове Elements), поэтому мы и работаем с массивом. А в методе getElementById мы получаем один элемент (о чем свидетельствует отсутствие окончания s в слове Element).
После инициализации рабочих переменных - мы корректируем положение body при появлении ползунка прокрутки, то есть наш ползунок будет накладываться поверх нашего сайта, а не сдвигать его, как это обычно бывает (можете проверить сами):
// функция для корректировки положения body при появлении ползунка прокрутки
function bodyMargin() {
bodyElementHTML.style.marginRight = "-" + scrollbarWidth + "px";
}
// при длинной странице - корректируем сразу
bodyMargin();
Механизм корректировки прост: в случае появления ползунка прокрутки - мы делаем отступ body через свойство margin-right на отрицательную величину ширины ползунка прокрутки. При первой загрузки страницы мы вызываем эту функцию, чтобы наше содержимое сразу же позиционировалось корректно, несмотря на наличие ползунка прокрутки. Вообще, позиционирование с учетом ползунка прокрутки - дело каждого, мне не хотелось бы, чтобы мой сайт скакал влево вправо :)
Создадим обработчик события нажатия на наш триггер:
// событие нажатия на триггер открытия модального окна
modalTrigger.addEventListener("click", function () {
// делаем модальное окно видимым
modalBackground.style.display = "block";
// если размер экрана больше 1366 пикселей (т.е. на мониторе может появиться ползунок)
if (windowInnerWidth >= 1366) {
bodyMargin();
}
// позиционируем наше окно по середине, где 175 - половина ширины модального окна
modalActive.style.left = "calc(50% - " + (175 - scrollbarWidth / 2) + "px)";
});
И в завершение создадим обработчик закрытия нашего окна при нажатии на крестик или на область за модальным окном:
// нажатие на крестик закрытия модального окна
modalClose.addEventListener("click", function () {
modalBackground.style.display = "none";
if (windowInnerWidth >= 1366) {
bodyMargin();
}
});
// закрытие модального окна на зону вне окна, т.е. на фон
modalBackground.addEventListener("click", function (event) {
if (event.target === modalBackground) {
modalBackground.style.display = "none";
if (windowInnerWidth >= 1366) {
bodyMargin();
}
}
});
Вот и всё модальное окно. Если у Вас есть какие-нибудь замечания, похвала, критика, советы, любой фидбек - буду рад прочитать и внести корректировки! Всех обнял-приподнял :)