Как создать простое модальное окно на jQuery

Чтобы создать модальное окно на jQuery, соберите плагин из разметки, CSS и обработчиков событий. Готовый пример откроет панель по кнопке, затемнит страницу, заблокирует прокрутку и вернет фокус после закрытия. Вы также добавите закрытие по крестику, затемнению и клавише Esc.

Что мы хотим создать

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

Модальное окно с сообщением поверх затемненной страницы

Закрыть окно можно тремя способами: нажать кнопку с символом ×, кликнуть по затемнению или нажать Esc. Фокус перейдет внутрь окна при открытии и вернется на кнопку после закрытия.

Подготовьте четыре файла: index.html, jquery.js, modal.css и jquery.paulund_modal_box.js. Полная сборка jQuery нужна для методов анимации. Официальную документацию по библиотеке и ее методам смотрите в jQuery API.

HTML-разметка страницы

Создайте файл index.html и добавьте кнопку вызова. Элемент button не меняет адрес страницы и не требует отмены перехода по href.

<!doctype html>
<html lang="ru">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Пример модального окна</title>
  <link rel="stylesheet" href="modal.css">
</head>
<body>
  <main>
    <h1>Информация о доставке</h1>
    <button type="button" class="paulund_modal">
      Открыть сообщение
    </button>
  </main>
</body>
</html>

Откройте сохраненный файл в браузере: на странице появятся заголовок и кнопка.

Создание jQuery-плагина модального окна

Создайте файл jquery.paulund_modal_box.js. Метод в $.fn подключает плагин к объектам jQuery, а $.extend() объединяет параметры вызова со значениями по умолчанию.

Добавьте каркас с вызовом e.preventDefault(), чтобы плагин работал и со ссылкой href="#" без перехода.

(function ($) {
  $.fn.paulund_modal_box = function (prop) {
    var options = $.extend({
      height: 250,
      width: 500,
      title: 'Информация',
      description: 'Заказ готов к отправке.'
    }, prop);

    return this.off('click.paulundModal')
      .on('click.paulundModal', function (e) {
        e.preventDefault();
        // Здесь появится создание окна.
      });
  };
})(jQuery);

Возврат результата .on() сохраняет цепочку методов jQuery. Пространство имен paulundModal позволяет заменить обработчик при повторной инициализации.

Добавление блокировки страницы

Добавьте в modal.css класс затемнения. Фиксированное позиционирование привязывает слой к окну браузера, а inset: 0 растягивает его до всех границ.

.paulund_block_page {
  position: fixed;
  inset: 0;
  z-index: 1000;
  display: flex;
  align-items: center;
  justify-content: center;
  box-sizing: border-box;
  padding: 16px;
  background: rgba(0, 0, 0, 0.6);
}

body.paulund_modal_open {
  overflow: hidden;
}

Flexbox центрирует панель, а отступ 16 px отделяет ее от краев экрана.

При открытии плагин сохранит исходное значение body.style.overflow и установит hidden. После закрытия скрипт вернет сохраненное значение, поэтому страница продолжит прокручиваться.

Создание модального окна

Добавьте в modal.css стили панели, заголовка, текста и кнопки закрытия. Размеры задаются параметрами плагина, а CSS ограничивает панель доступной областью экрана.

.paulund_modal_box {
  position: relative;
  box-sizing: border-box;
  max-width: 100%;
  max-height: 100%;
  overflow: auto;
  padding: 24px;
  border: 1px solid #ddd;
  border-radius: 10px;
  background: #fff;
  color: #222;
  box-shadow: 0 2px 7px #292929;
}

.paulund_modal_title {
  margin: 0 40px 16px 0;
  font-size: 24px;
}

.paulund_modal_description {
  margin: 0;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

.paulund_modal_close {
  position: absolute;
  top: 8px;
  right: 8px;
  width: 36px;
  height: 36px;
  border: 0;
  border-radius: 4px;
  background: #eee;
  color: #222;
  font-size: 28px;
  line-height: 1;
  cursor: pointer;
}

.paulund_modal_close:focus-visible {
  outline: 2px solid #005fcc;
  outline-offset: 2px;
}

Кнопка содержит символ ×, поэтому отдельное изображение для закрытия не требуется. Атрибут aria-label сообщает скринридеру назначение кнопки. Панель получит role="dialog", aria-modal="true" и связь с заголовком через aria-labelledby.

Добавляйте заголовок и описание методом .text(), который отображает пользовательские данные обычным текстом.

Не передавайте непроверенные пользовательские данные в .html(). Вставка строки как HTML может создать риск XSS.

Готовый jQuery-плагин

Замените каркас в файле jquery.paulund_modal_box.js этим кодом. Стили остаются в отдельном файле, а плагин допускает одно открытое окно одновременно.

(function ($) {
  var active = false;
  var counter = 0;

  $.fn.paulund_modal_box = function (prop) {
    var options = $.extend({
      height: 250,
      width: 500,
      title: 'Информация',
      description: 'Заказ готов к отправке.'
    }, prop);

    return this.off('click.paulundModal')
      .on('click.paulundModal', function (e) {
        e.preventDefault();
        if (active) return;
        active = true;

        var opener = this;
        var closing = false;
        var body = document.body;
        var oldOverflow = body.style.overflow;
        var background = [];
        var titleId = 'paulund-modal-title-' + (++counter);
        var duration = window.matchMedia(
          '(prefers-reduced-motion: reduce)'
        ).matches ? 0 : 120;

        var $overlay = $('<div>', {
          'class': 'paulund_block_page'
        });
        var $dialog = $('<div>', {
          'class': 'paulund_modal_box',
          role: 'dialog',
          'aria-modal': 'true',
          'aria-labelledby': titleId,
          tabindex: '-1'
        }).css({
          width: options.width,
          height: options.height
        });
        var $close = $('<button>', {
          'class': 'paulund_modal_close',
          type: 'button',
          'aria-label': 'Закрыть окно'
        }).text('×');
        var $title = $('<h2>', {
          'class': 'paulund_modal_title',
          id: titleId
        }).text(options.title);
        var $description = $('<p>', {
          'class': 'paulund_modal_description'
        }).text(options.description);

        $dialog.append($close, $title, $description);
        $overlay.append($dialog).appendTo(body);

        Array.from(body.children).forEach(function (element) {
          if (element === $overlay[0]) return;
          background.push({
            element: element,
            inert: element.inert
          });
          element.inert = true;
        });
        body.style.overflow = 'hidden';

        function closeModal() {
          if (closing) return;
          closing = true;

          $overlay.stop(true).fadeOut(duration, function () {
            $(document).off('.paulundModalOpen');
            $overlay.remove();
            background.forEach(function (item) {
              item.element.inert = item.inert;
            });
            body.style.overflow = oldOverflow;
            active = false;
            if (opener.isConnected) opener.focus();
          });
        }

        $close.on('click.paulundModalClose', closeModal);
        $overlay.on('click.paulundModalOverlay', function (event) {
          if (event.target === $overlay[0]) closeModal();
        });

        $(document).on('keydown.paulundModalOpen', function (event) {
          if (event.key === 'Escape') {
            event.preventDefault();
            closeModal();
          }
          if (event.key === 'Tab') {
            event.preventDefault();
            $close[0].focus();
          }
        });

        $(document).on('focusin.paulundModalOpen', function (event) {
          if (!$dialog[0].contains(event.target)) {
            $close[0].focus();
          }
        });

        $overlay.hide().fadeIn(duration);
        $close[0].focus();
      });
  };
})(jQuery);

Обработчик закрытия привязан к новой кнопке $close. Проверка event.target закрывает окно только при клике по самому затемнению.

Метод .fadeOut() запускает исчезновение, а колбэк удаляет оверлей после завершения анимации. Флаг closing не дает повторно запустить закрытие.

Плагин удерживает фокус на единственном интерактивном элементе панели – кнопке закрытия.

Для формы или нескольких кнопок список элементов фокуса нужно расширить.

Использование jQuery-плагина

Скачайте полную сборку jQuery на официальной странице jquery.com/download и сохраните файл рядом с index.html под именем jquery.js. Можно использовать уже подключенную на сайте копию, если она содержит методы анимации.

Добавьте скрипты перед закрывающим тегом </body>. Сначала загрузите библиотеку, затем плагин и после него вызов инициализации.

<script src="jquery.js"></script>
<script src="jquery.paulund_modal_box.js"></script>
<script>
  $(function () {
    $('.paulund_modal').paulund_modal_box();
  });
</script>

Нажмите «Открыть сообщение». Панель появится по центру, фон потемнеет, прокрутка страницы остановится, а фокус перейдет на крестик.

  1. Нажмите кнопку закрытия. Панель исчезнет, а фокус вернется на кнопку вызова.
  2. Откройте окно снова и нажмите Esc. Скрипт закроет панель тем же способом.
  3. Кликните по затемнению. Окно закроется, а клик внутри белой панели его не закроет.
  4. Нажмите Tab или Shift+Tab. Фокус останется внутри открытого окна.
  5. Уменьшите окно браузера. Панель сохранит отступ 16 px от краев экрана.

Ошибка jQuery is not defined означает, что библиотека не загрузилась.

Ошибка paulund_modal_box is not a function указывает на неправильный порядок подключения файлов.

Чтобы убрать компонент, удалите вызов инициализации и подключение плагина. Затем удалите modal.css, если этот файл больше не используют другие элементы страницы.

Использование параметров

Плагин принимает четыре параметра: title, description, height и width. Заголовок и описание задаются строками, размеры – положительными числами в пикселях.

ПараметрЗначение по умолчаниюЧто меняет
titleИнформацияЗаголовок панели
descriptionЗаказ готов к отправке.Текст сообщения
height250Высоту панели в пикселях
width500Ширину панели в пикселях

Замените вызов инициализации в index.html этим примером. Панель получит ширину 600 px и высоту 320 px, если экран позволяет такой размер.

<script>
  $(function () {
    $('.paulund_modal').paulund_modal_box({
      title: 'Доставка заказа',
      description: 'Курьер свяжется с вами перед выездом. Подготовьте номер заказа.',
      height: 320,
      width: 600
    });
  });
</script>

Свойство white-space: pre-wrap сохраняет переносы строк в описании, а HTML-разметка в параметрах отображается обычным текстом.

Для разных сообщений назначьте кнопкам разные классы и вызовите плагин отдельно для каждой группы. Например, одна кнопка может показывать условия доставки, а другая – информацию об оплате.

Когда использовать встроенный dialog

Для нового проекта рассмотрите встроенный элемент <dialog> и его метод showModal(). Браузер создает модальное состояние, обрабатывает Esc и управляет фокусом.

Псевдоэлемент ::backdrop оформляет затемнение.

Чтобы закрывать окно по фону, обработайте клик и сравните event.target с самим элементом dialog, как в примере с оверлеем.

Проверьте окно клавиатурой до публикации страницы. Esc должен закрывать панель, а фокус возвращаться на кнопку вызова.

Комментарии

Оставьте свой комментарий
Пока никто не оставил комментариев