Как сделать модальное окно jquery

Обновлено: 12.05.2024

На работе перед началом создания нового проекта (веб сайт) я решил попробовать перейти с клиентской части библиотеки Microsoft AJAX на jQuery. Оснований для этого было несколько, но не об этом сейчас речь.

Дошло дело до всплывающих модальных окон и надо было найти соответствующий плагин. Сначала я попробовал jqModal, но наткнулся на баг в IE7 (мой bug report). После чего я решил использовать jQuery UI dialog, т.к. мне понравилась сама библиотека jQuery UI. Забегая вперёд отмечу, что ThickBox имеет аналогичную проблему той, которую я сейчас опишу.

Собственно, создал контрол, который должен был обеспечивать появление этой формы при клике на любые ссылки с классом «lbPopupLink»:

(не забывайте, что тут я javascript код прописываю прямо на странице, что, в принципе, не есть хорошо, т.к. если я контрол поставлю на странице дважды, то получиться дублирующий javascript код — в этом случае лучше использовать ClientScriptManager.RegisterClientScriptBlock; но т.к. данный контрол я точно собирался использовать только один раз на страницу и в целях упрощения статьи я оставлю всё как есть)

// Global variables
var __passwordCloneValues;

//
// Function that will close jQuery UI dialog, clone it back to aspnet form and perform submit.
// Should be applied to the dialog.
//
// Arguments:
// butOkId — id of the submit button
//
$.fn.extend( dialogCloseAndSubmit: function (butOkId)
if (!Page_IsValid)
return false ;

__passwordCloneValues = new Array();
$( ":password" , $( this )).each( function ()
__passwordCloneValues.push($( this ).val());
>);
__passwordCloneValues = __passwordCloneValues.reverse();

var dlg = $( this ).clone();
$( this ).dialog( «destroy» ).remove();

return true ;
>
>);
* This source code was highlighted with Source Code Highlighter .

И вот чем нужно дополнить наш javascript блок из начала статьи, чтобы использовать эту функцию:


Вот, что получилось:

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

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

Я хочу сохранить все файлы окна и стили внутри плагина, поэтому нам останется только подключить плагин в документе. Как правило, с помощью других плагинов нужно создавать панель самостоятельно, а JQuery-плагин просто выводит ее. Я хочу сделать плагин, который создает модальное окно и задает его стили.

HTML-код очень прост. Мы хотим, чтобы плагин запускался при возникновении события клика по ссылке, так что нам нужно создать ссылку и добавить класс, чтобы мы позже могли ссылаться на него:

Сейчас у нас нет никакого CSS , и мы можем переходить непосредственно к созданию плагина простого модального окна JQuery .

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

Создайте новый файл JavaScript , назовите его jquery.paulund_modal_box.js и сохраните в той же папке, в которой находится веб-страница:

Приведенная выше базовая структура будет создавать плагин paulund_modal_box , и при возникновении события клика по элементу будет выводить JQuery модальное окно по центру. Я также добавил ряд параметров по умолчанию, которые мы можем использовать, чтобы построить панель.

Теперь нам нужно по клику отображать модальное окно. Так как мы не используем на странице ни HTML , ни CSS нам нужно выполнить ряд задач:

  1. Заблокировать остальную часть экрана, чтобы мы могли видеть только модальное окно;
  2. Создать HTML-разметку модального окна;
  3. Задать стили двух новых элементов;
  4. Вывести модальное окно.

Нам нужно добавить к событию клика следующие функции:

Теперь у нас есть вызов нужных функций, которые мы хотим использовать, давайте добавим их функционал.

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

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

Мы используем div , который будет охватывать весь экран, в него мы добавим модальное окно.

Создайте функцию add_block_page() , которая создает div и добавляет его в тег body в HTML :

Мы хотим, чтобы это окно занимало весь экран и блокировало его, поэтому давайте добавим функцию, которая будет определять стили:

Теперь экран заблокирован, и мы можем добавить в div простое модальное окно JQuery .

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

Чтобы создать модальное окно, мы используем функцию add_popup_box() :

Этот код создает div , который содержит название, описание и ссылку для закрытия модального окна JQuery . Затем он добавляет модальное окно к блокирующему div и перехватывает событие клика для закрытия панели, чтобы убрать модальное окно.

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

Вот и все, теперь наш JQuery-плагин завершен.

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

На тот случай, если вы пропустили предыдущие шаги, ниже приводится код готового плагина модального окна JQuery :

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

Мы создали плагин, но как его использовать? Вернитесь к HTML и подключите JQuery и плагин в теге head :

Теперь плагин подключен к странице, чтобы мы могли назначить его для ссылок и вызывать модальное окно JQuery UI по клику.

Создайте тег script перед закрытием body и добавьте в него следующий код:

Когда вы нажимаете на ссылку, будет открываться модальное окно, реализованное с помощью созданного плагина. Если вы создадите несколько ссылок с классом .paulund_modal , то каждый раз после нажатия на эти ссылки будет выводиться модальное окно.

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

В начале статьи я говорил о параметрах по умолчанию, которые используются для построения модального окна JQuery . Вот, как вы можете изменить параметры по своему усмотрению:

В этой статье вы узнаете, как создать всплывающее окно при входе на сайт с формой входа/регистрации с помощью HTML , CSS 3 и j Query . Для реализации popup окна требуется HTML , CSS и jQuery ( Javascript ). Я расскажу, как создать простую версию, а затем мы посмотрим, как ее можно улучшить.

Начало

Сначала нужно сбросить CSS браузера и импортировать дополнительные шрифты. Я собираюсь использовать Open Sans и Varela Round , которые доступны в Google Font .

Импорт шрифтов Google

Сброс CSS и стилей сайта по умолчанию

Стили разделов body и HTML можно изменить по своему усмотрению, это мало повлияет на создаваемую форму входа и popup окно jQuery .

Затем нужно подключить на странице jQuery . Я использую ссылку на jQuery , но можно использовать локальную версию.

Ссылка на jQuery v1.10

Создание CSS-наложения

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

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

Поскольку его стили разделяются на две основные части, я собираюсь объяснить их по отдельности.

Сначала рассмотрим установку позиции и добавление цвета

Разберем этот код:

  • background-color: rgba(0,0,0,.25) - использование RGBA позволяет указать цвет и альфа-значение, альфа - это непрозрачность цвета;
  • bottom: 0 - позиционирует элемент внизу страницы;
  • left: 0 - позиционирует элемент по левому краю страницы;
  • position: fixed - при прокрутке страницы позиция элемента не изменяется;
  • top: 0 - позиционирует элемент вверху страницы;
  • width: 100% - элемент заполняет всю ширину страницы.

Вторая часть включает flexbox CSS3 , что значительно упрощает позиционирование элементов внутри контейнера. Давайте посмотрим:

Перед тем, как перейти к popup окну для сайта, пояснение Flexbox :

  • display: flex - определяет гибкий контейнер, либо inline-flex , либо block ( flex ) ;
  • justify-content: center - выравнивает содержимое по центру.

Примечание : на момент написания этой статьи flexbox не полностью поддерживался во всех основных браузерах. Если хотите охватить максимальное количество браузеров, необходимо использовать префиксы:

Стили панели входа на HTML и CSS

Теперь у нас есть контейнер, и нужно разместить в нем создаваемую форму входа. Общей чертой подобных форм с popup окном jQuery является полупрозрачная граница. Мы используем элемент контейнера для достижения этого эффекта, но можно использовать границу, чтобы получить то же самое:

Большинство CSS-свойств очевидны. С помощью значения rgba мы еще раз установили цвет фона, что дает красивый непрозрачный эффект. border-radius задает закругленные углы контейнера формы входа.

Свойство, которое требует пояснений, это align-self , поскольку оно довольно новое. Это связано с flexbox . align-self определяет горизонтальное выравнивание элемента, и мы задали выравнивание точно по центру.

Далее переходим к области содержимого. До сих пор мы имели дело только с полупрозрачными фонами, так что пришло время использовать что-то сплошное:

Мы используем сплошной белый фон, поэтому вместо rgba применили только rgb . Отступ в 24 пикселя можете изменить по своему усмотрению.

Важной частью этого правила является определение position . Это необходимо при использовании абсолютно позиционированных элементов внутри контейнера - это будет кнопка закрытия.

Теперь нужно оформить внутри панели входа заголовок ( h3 ):

Чтобы выделить заголовок, я использую черный округлый шрифт с размером 1.8 em . Использование 1.8 em задает размер шрифта относительно шрифта документа. Это называется эластичностью шрифта.

Создание кнопки закрытия

Перед тем, как сделать popup окно, нужно создать кнопку закрытия формы входа. Это делается следующим образом:

Вот объяснение кода:

  • background-color - мы используем приятный светло-серый фон;
  • border-radius - поскольку мы создаем круг, нам нужно, чтобы радиус закругления углов границы составлял 50% от высоты;
  • position: absolute - абсолютное позиционирование кнопки / ссылки, но так как для контейнера установлено относительное позиционирование, позиции всех элементов устанавливаются относительно него;
  • top - расстояние от верхней части формы входа - rem - относительная зависимость, которая связана с размерами шрифта;
  • transition - задает анимацию для всех свойств, используются значения 400ms ease ;
  • right - расстояние от правого края экрана до формы входа.

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

Создание формы входа

Скоро перейдем к HTML popup окну. А пока CSS-код формы входа:

Сначала мы определили стили для меток формы. Благодаря этому пользователь может нажать текст и перейти к соответствующему полю формы. Элемент label работает непосредственно с id данных.

Перед тем, как сделать popup окно HTML , мы создаем элементы ввода данных формы. Я указал inset box-shadow , чтобы задать для них красивую внутреннюю тень.

Использование селектора :focus позволяет указать, как будет выглядеть элемент ввода данных, когда пользователь установил в нем курсор. Необходимо наглядно показать, что элемент в данный момент выбран.

В конце мы задаем стили с помощью селектора CSS :invalid . Когда пользователь вводит данные, которые не соответствуют заданному шаблону, элемент ввода будет отображаться с помощью этих стилей.

Стили кнопки входа

Стили кнопки не содержат ничего нового:

Для кнопки мы задали приятный синий фон с полупрозрачной темной рамкой. Этот прием позволяет не менять цвет границы, когда мы изменяем цвет фона. Мы также установили для кнопки стандартную CSS-анимацию перехода при смене цвета фона.

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

HTML-код формы входа

До сих пор все пояснения касались стилей CSS . Теперь пришло время вкратце рассмотреть разметку. В том числе и HTML popup окна.

В форме используются элементы HTML 5 , поэтому убедитесь, что doctype задан верно:

Если хотите обеспечить полную совместимость со старыми версиями браузеров и поддержку HTML 5 , включите приведенную ниже ссылку на Javascript в разделе head документа:

Полный HTML-код формы входа:

Важно отметить, что мы используем для окна наложения атрибут style="display: none;" . Это важно, когда речь идет о Javascript / jQuery .

При использовании этого метода для всего сайта необходимо разместить код внутри элемента body .

jQuery / Javascript

Нужно обернуть функции jQuery в функцию, которая загружается после того, как документ готов. Это предотвращает замедление:

Чтобы создать эффект растворения, мы используем метод jQuery fadeToggle . Он позволяет значительно проще анимировать элементы.

Мы используем fadeToggle при нажатии ссылки входа в систему. Для этого нам потребуется событие jQuery click :

Приведенный выше код запускает функцию encased при нажатии элемента с идентификатором loginLink . Чтобы указать ей, что делать, когда элемент нажат, нужно сделать следующее:

Использование jQuery-функции preventDefault() позволяет остановить связь с перенаправлением пользователя. Это обеспечивает функционал для разработчиков, которые могут ссылаться на страницу входа:

С помощью этой простой функции мы продублируем функционал для закрытия окна.

Нам не нужно использовать здесь функцию preventDefault() , потому что кнопкой закрытия окна не предоставляется внешняя ссылка.

В JS popup окне сделаем так, чтобы пользователь мог нажать клавишу ESC для закрытия окна:

Важно отметить, что эта функция используется в теле if . Оператор проверяет, нажал ли пользователь клавишу ESC ( код клавиши 27 ).

Поскольку мы не хотим, чтобы пользователь открывал окно с помощью клавиши ESC , нужно проверить, отображается ли окно наложения или нет.

Вот все весь код jQuery :

AJAX и HTML 5

Что, если вы захотите сделать эту форму еще лучше? Можно включить в нее форму регистрации. Вот как это можно сделать без дублирования кода с помощью запроса JQuery AJAX GET :

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

Мы хотим, чтобы ссылки не делали ничего другого. Используем для этого preventDefault() . Затем нужно узнать, какую страницу нужно извлечь. Это указано в HTML-атрибуте data-action .

Всем привет, сегодня я вам покажу как сделать модальное окно без использования плагинов и библиотек(только jQuery).Мы сделаем кнопку при нажатии на которую будет появляться окно, в которое вы можете разместить любую необходимую информацию. Для создания модального окна нам понадобится начальные знания HTML, CSS, jQuery.

Для начала необходимо создать 3 файла с расширениями .html , .css , .js . Назовем их index.html , style.css , script.js .

Редактирование файла index.html

Здесь мы прописываем стандартный базовый шаблон. Внутри тега head подключаем 2 остальных файла( style.css , script.js ). С помощью тега link подключаем style.css, c помощью script — script.js . Так как наш скрипт написан с использованием библиотеки jQuery, мы прописываем код подключения файла данной библиотеки перед файлом script.js .

Внутри тега body прописываем код модального окна. Структура кода позволяет создавать несколько модальных окон, которые будут вызываться по уникальному id .

Здесь в div мы указываем id модального окна, на которое мы будем ссылаться. Класс необходим для указания стилей в файле style.css . Внутри тега тега span указываем символ по нажатию на который будет закрываться модальное окно (так же окно может закрываться при нажатии вне области модального окна). Все что вы хотите добавить в модальное окно, должно быть размещено после тега span с классом modal_close .

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

Редактирование файла style.css.

В файле style.css прописываем стили для нашего модального окна.

Редактирование файла script.js

Здесь скрипт, который необходимо просто вставить в файл.

Как подключить модальное окно на нужный блок?

Вначале для проверки мы добавим в наше окно форму.

Здесь все очень просто, необходимо создать ссылку по нажатию на которую нас перебросит на блок модального окна. Для этого прописываем тег a , указываем у него в качестве значения атрибута href идентификатор модального окна.

Вёрстка таких окон сначала кажется простой задачей. Модальные окна можно сделать даже без помощи JS только лишь с помощью CSS, но на практике они оказываются неудобными, и из-за маленьких недочетов модальные окна раздражают посетителей сайта.

В итоге было задумано сделать собственное простое решение.


Вообще говоря, есть несколько готовых скриптов, JavaScript библиотек, реализующих функционал модальных окон, например:

  • Arctic Modal,
  • jquery-modal,
  • iziModal,
  • Micromodal.js,
  • tingle.js,
  • Bootstrap Modal (из библиотеки Bootstrap) и др.

(в статье не рассматриваем решения на базе Frontend-фреймворков)

Несколькими из них я пользовался сам, но почти у всех находил какие-то недостатки. Некоторые из них требуют подключения библиотеки jQuery, которая есть не на всех проектах. Для разработки своего решения, нужно сначала определиться с требованиями.

Что мы ждём от модальных окон? Отвечая на этот вопрос, я основывался на докладе «Знакомьтесь, модальное окно» Анны Селезнёвой, а так-же на относительно старой статье NikoX «arcticModal — jQuery-плагин для модальных окон».

Итак, чтобы нам хотелось видеть?

Дисклеймер: Прежде чем мы рассмотрим подробности, сразу дам ссылку на готовый код получившейся библиотеки (HystModal) на GitHub, а также ссылку на демо+документацию.

Начнём с разметки.

1. Разметка HTML и CSS

1.1. Каркас модальных окон

Как открыть окно быстро? Самое простое решение: разместить всю разметку модального окна сразу в HTML странице. Затем скрывать/показывать это окно при помощи переключения классов CSS.

Набросаем такую разметку HTML (я назвал этот скрипт «hystmodal»):

Сделаем так, чтобы .hystmodal растягивался на всё окно браузера и закрывал собой содержимое страницы. Чтобы этого добиться, установим фиксированное позиционирование в CSS и приравняем свойства top, bottom, left и right к нулю.

В этом коде сделаны ещё две вещи:

  1. Так как мы хотим центрировать окно внутри страницы, превращаем .hystmodal в flex-контейнер с выравниваем его потомков по центру по вертикали и горизонтали.
  2. Окно может быть больше высоты экрана браузера, поэтому мы устанавливаем overflow-y: auto , чтобы при переполнении возникала полоса прокрутки. Также, для сенсорных экранов (в основном для Safari) нам стоит установить свойство -webkit-overflow-scrolling: touch , чтобы сенсорная прокрутка работала именно на этом блоке а не на странице.

Теперь установим стили для самого окна.

Кажется возникли сложности.

Проблема №1. Если высота окна больше высоты окна браузера, то контент окна будет обрезан сверху.


Это возникает из-за свойства justify-content: center . Оно позволяет нам удобно выровнять потомков по основной оси (по вертикали), но если потомок становится больше родителя то часть его становится недоступной даже при прокручиваемом контейнере. Подробнее можно посмотреть на stackoverflow. Решение – установить justify-content: flex-start , а потомку установить margin:auto . Это выровняет его по центру.

Проблема №2. В ie-11 если высота окна больше высоты окна браузера, то фон окна обрезается.

Решение: мы можем установить flex-shrink:0 потомку – тогда обрезки не происходит.

Проблема №3. В браузерах кроме Chrome нет отступа от нижней границы окна (т.е. padding-bottom не сработал).

Сложно сказать баг это браузеров или наоборот соответствует спецификации, но решения два:

  • установить псевдоэлемент ::after после потомка и дать ему высоту вместо padding
  • обернуть элемент в дополнительный блок и дать отступы уже ему.

Воспользуемся вторым методом. Добавим обертку .hystmodal__wrap . Так мы заодно обойдём и проблему №1, а вместо padding у родителя установим margin-top и margin-top у самого .hystmodal__window .

Наш итоговый html:

В код также добавлены некоторые aria и role атрибуты для обеспечения доступности.

Обновленный код CSS для обертки и окна.

1.2 Скрываем окно

Сейчас наше окно всегда видно. Когда говорят о скрытии элементов, первое что приходит на ум это переключать свойство display со значения none до нашего значения flex.

Но этот подход нас не устроит, ведь свойство display не анимируется. Все переходы дочерних элементов, указанные в свойстве transition, работать не будут.

Нам поможет другое свойство visibility:hidden . Оно скроет окно визуально, хотя и зарезервирует под него место. А так как все будущие окна на странице имеют фиксированное
позиционирование – они будут полностью скрыты и не повлияют на остальную страницу. Кроме того, на элементы с visibility:hidden нельзя установить фокус с клавиатуры, а от скрин-ридеров мы уже скрыли окна с помощью атрибута aria-hidden="true" .

Добавим также классы для открытого окна:

1.3 Оформление подложки

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

Просто разместим элемент .hystmodal__shadow прямо перед закрывающим . В будущем, сделаем так, чтобы этот элемент создавался автоматически из js при инициализации библиотеки.

1.4 Отключение прокрутки страницы

Когда модальное окна открывается, мы хотим, чтобы страница под ним не прокручивалась.
Самый простой способ этого добиться — повесить overflow:hidden для body или html, когда окно открывается. Однако с этим есть проблема:

Проблема №4. В браузере Safari на iOS страница будет прокручиваться, даже если на тег html или body повешен overflow:hidden .
Решается двумя способами, либо блокированием событий прокрутки (touchmove, touchend или touchsart) из js вида:

Однако при этом блокируется и прокрутка самого модального окна, а также все прокручиваемые блоки внутри окна, если они будут. Требуется дополнительные проверки селекторов из js, что приводит к усложнению кода, поэтому рассмотрим другой вариант.

ps: можно конечно применить библиотеку scroll-lock, в которую заложено это решение, но в статье было решено воспользоваться другим вариантом.

Другое решение – основано частично на CSS. Пусть когда окно открывается, на элемент будет добавляться класс .hystmodal__opened :

Благодаря position:fixed , окно не будет прокручиваться даже в safari, однако здесь тоже не всё гладко:

Проблема №5. При открытии/закрытии окна страница прокручивается в начало.
Действительно, это происходит из-за изменения свойства position, текущая прокрутка окна сбрасывается.

Для решения, нам нужно написать следующий JS (упрощенно):

При открытии:

При закрытии:

Отлично, приступим к JavaScript коду.

2. Код JavaScript

2.2 Каркас библиотеки

Нам нужна совместимость со старыми браузерами включая IE11 поэтому нам нужно выбрать из 2 вариантов кодинга:

  • Разрабатывать на старом стандарте ES5, и использовать только те фичи, которые поддерживают все браузеры.
  • Применить современный синтаксис ES6, но подключить транспайлер Babel, который автоматически преобразует код для всех браузеров и встроит необходимые полифилы.
    Было принято решение использовать второй вариант, с прицелом на будущее.
    Приступим.

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

Итак, мы описали класс HystModal . Чтобы всё работало, нужно всего лишь подключить наш скрипт и создать экземпляр класса:

Проблема №6: если в браузере есть фиксированный скроллбар (который влияет на ширину страницы), то при открытии/закрытии окна происходит сдвиг контента, когда полоса прокрутки то появляется то пропадает.

Действительно – скроллбар пропадает и контент страницы перераспределяется. Чтобы решить эту проблему, можно добавить отступ справа к тегу html, равный ширине скроллбара когда он пропадает.

Однако ширина скроллбара может быть разной в разных браузерах и операционных системах. Кроме того, скроллбара может не быть на коротких страницах или он может быть плавающим (например, в Chrome на Android). Поэтому ширину нужно вычислять динамически из скрипта.

Дополним метод _bodyScrollControl()

Почему код метода close() упрощён? Дело в том, что просто убирая классы CSS у элементов, мы не можем анимировать закрытие окна.

Проблема №7. При закрытии окна, свойство visibility:hidden применяется сразу и не даёт возможности анимировать закрытие окна.

Причина этого известна: свойство visibility:hidden не анимируется. Конечно, можно обойтись без анимации, но, если она нужна, сделаем следующее.

  • Создадим дополнительный CSS-класс .hystmodal—moved почти такой-же как и .hystmodal--active
  • Затем при закрытии сначала добавим этот класс к окну и повесим обработчик события «transitionend» на модальном окне. Затем удалим класс `.hystmodal—active , таким образом вызывая css-переход. Как только переход завершится, сработает обработчик события «transitionend», в котором сделаем всё остальное и удалим сам обработчик события.

Ниже: новая версия методов закрытия окна:

Вы заметили, что мы создали ещё один метод _closeAfterTransition() и перенесли основную логику закрытия туда. Это нужно, чтобы удалить обработчик события transitionend после закрытия окна, ведь в метод removeEventListener необходимо передать именно ту функцию, которую мы привязывали.

Кроме того, если анимация не будет нужна, можно просто вызвать this._closeAfterTransition() не вешая его на событие.

Как мы помним, внутри addEventListener, this будет указывать на селектор где происходит событие, а не на наш экземпляр класса, поэтому в конструкторе нужно добавить ещё одну строчку для жёсткой привязки метода к this.

2.2 Закрытие окна по клику на оверлей

Нам нужно обработать ещё одно событие – закрытие окна по клику на элемент подложки .hystmodal__wrap . Мы можем повесить обработчик клика на документ для делегирования события как при открытии и проверить что событие произошло на .hystmodal__wrap примерно так:

Это будет работать, но есть один малозаметный недостаток.

Проблема №8. Если кнопку мыши нажать внутри окна, а отпустить за его пределами (над подложкой), окно закрывается.

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

Окно закрывается потому что по спецификации, если нажатие и отпускание мыши были на разных элементах, то событие click сработает на самом ближайшем общем для них элементе, а у нас это как раз .hystmodal__wrap .

Мы могли бы решить это изменением html, добавляя ещё один div сразу после .hystmodal__window и размещая его визуально под окном. Но нам бы не хотелось добавлять лишний пустой div ещё сильнее усложняя разметку.

Мы можем разбить наш addEventListener на два отдельных обработчика: для событий mousedown и mouseup и будем проверять чтобы оба события происходили именно на .hystmodal__wrap . Добавим новые обработчики событий в наш метод eventsFeeler()

2.3 Управление фокусом

У нас заготовлено два метода для управления фокусом: focusContol() для переноса фокуса внутрь окна и обратно при его закрытии, а также focusCatcher(event) для блокирования ухода фокуса из окна.

Решения для фокуса были реализованы аналогично js-библиотеке «Micromodal» (Indrashish Ghosh). А именно:

1. В служебный массив сохраним все css селекторы на которых может быть установлен фокус (свойство помещаем в init()):

2. В методе focusContol() находим первый такой селектор в окне и устанавливаем на него фокус, если окно открывается. Если же окно закрывается – то переводим фокус на this.starter :

3. В методе focusCatcher() находим в окне и превращаем в массив коллекцию всех элементов на которых может быть фокус. И проверяем, если фокус должен был выйти на пределы окна, то вместо этого устанавливаем фокус снова на первый или последний элемент (ведь фокус можно переключать как по Tab так и по Shift+Tab в обратную сторону).

Результирующий код метода focusCatcher:

По сути мы реализовали все необходимое для успешного создания модальных окон, осталось ещё несколько дел:

Проблема №9. В IE11 не работают методы Element.closest() и Object.assign() .

Для поддержки Element.closest, воспользуемся полифилами для closest и matches от MDN.

Можно их вставить просто так, но так как у нас проект всё равно собирается webpack, то удобно воспользоваться пакетом element-closest-polyfill который просто вставляет этот код.

Для поддержки Object.assign , можно воспользоваться уже babel-плагином @babel/plugin-transform-object-assign

3. Заключение и ссылки

Повторяя начало статьи, всё изложенное выше, я оформил в маленькую библиотеку hystModal под MIT-лицензией. Вышло 3 кБ кода при загрузке с gzip. Ещё написал для неё подробную документацию на русском и английском языке.

Что вошло ещё в библиотеку hystModal, чего не было в статье:

  • Настройки (вкл/выкл управление фокусом, варианты закрытия, ожидание анимации закрытия)
  • Коллбеки (функции вызывающиеся перед открытием окна и после его закрытия (в них передаётся объект модального окна))
  • Добавлен запрет на какие-либо действия пока анимация закрытия окна не завершится, а также ожидание анимации закрытия текущего окна перед открытием нового (если окно открывается из другого окна).
  • Оформление кнопки-крестика закрытия в CSS
  • Минификация CSS и JS плагинами Webpack.

Если вам будет интересна эта библиотека, буду рад звёздочке в GitHub, или напишите в Issues о найденных багах. (Особенно большие проблемы, наверное, в грамматике английской версии документации, так как мои знания языка пока на начальном уровне. Связаться со мной также можно в Instagram

Читайте также: