Pull to refresh

Модальное окно на чистом CSS и JS

Level of difficultyEasy
Reading time5 min
Views32K

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

Для тех, кому надо сразу код и вид окна.

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();
        }
    }
});

Вот и всё модальное окно. Если у Вас есть какие-нибудь замечания, похвала, критика, советы, любой фидбек - буду рад прочитать и внести корректировки! Всех обнял-приподнял :)

Tags:
Hubs:
Total votes 7: ↑4 and ↓3+3
Comments28

Articles