diff --git a/people/annabaraulina/index.md b/people/annabaraulina/index.md new file mode 100644 index 0000000000..d54eeaffa4 --- /dev/null +++ b/people/annabaraulina/index.md @@ -0,0 +1,12 @@ +--- +name: 'Анна Бараулина' +url: https://github.com/AnnaBaraulina +photo: photo.jpeg +badges: + - first-contribution-small +--- + + +Привет! Меня зовут Аня, я занимаюсь веб-разработкой и ищу интересные проекты, чтобы применить то, что уже умею, а также научиться новому! В прошлом я преподаватель философии, училась и преподавала в Москве и в Париже. Любовь к логике и работе с формализованным языком несколько лет назад навели меня на мысль попробовать изучить java-script и с тех пор этим и занимаюсь и хочу продолжать и продолжать! + +Со мной можно связаться по почте: anna.baraulina@gmail.com diff --git a/people/annabaraulina/photo.jpeg b/people/annabaraulina/photo.jpeg new file mode 100644 index 0000000000..4f218f0b3c Binary files /dev/null and b/people/annabaraulina/photo.jpeg differ diff --git a/recipes/index.md b/recipes/index.md index 74a3a1299d..ca18b8a9c8 100644 --- a/recipes/index.md +++ b/recipes/index.md @@ -8,6 +8,7 @@ groups: - dragndrop-upload - character-counter - center + - popup - container - name: 'На серверной стороне' items: diff --git a/recipes/popup/demos/popup-demo/images/cute.jpg b/recipes/popup/demos/popup-demo/images/cute.jpg new file mode 100644 index 0000000000..9b6a45c801 Binary files /dev/null and b/recipes/popup/demos/popup-demo/images/cute.jpg differ diff --git a/recipes/popup/demos/popup-demo/images/grechka.jpg b/recipes/popup/demos/popup-demo/images/grechka.jpg new file mode 100644 index 0000000000..44010762ec Binary files /dev/null and b/recipes/popup/demos/popup-demo/images/grechka.jpg differ diff --git a/recipes/popup/demos/popup-demo/images/home.jpg b/recipes/popup/demos/popup-demo/images/home.jpg new file mode 100644 index 0000000000..536416bd6b Binary files /dev/null and b/recipes/popup/demos/popup-demo/images/home.jpg differ diff --git a/recipes/popup/demos/popup-demo/images/partie.jpg b/recipes/popup/demos/popup-demo/images/partie.jpg new file mode 100644 index 0000000000..66920d1d48 Binary files /dev/null and b/recipes/popup/demos/popup-demo/images/partie.jpg differ diff --git a/recipes/popup/demos/popup-demo/index.html b/recipes/popup/demos/popup-demo/index.html new file mode 100644 index 0000000000..931b671685 --- /dev/null +++ b/recipes/popup/demos/popup-demo/index.html @@ -0,0 +1,227 @@ + + + + + Пример попапа — Попап — Дока + + + + + + + + + +
+ Мем про голодного котика + Мем про котика на дороге + Мем про кота и вечеринку + Мем про кота и гречку +
+ + +
+

Дока — самая добрая документация 🙃

+ +
+
+ + + + + diff --git a/recipes/popup/index.md b/recipes/popup/index.md new file mode 100644 index 0000000000..9bc8c94df9 --- /dev/null +++ b/recipes/popup/index.md @@ -0,0 +1,294 @@ +--- +title: "Попап" +description: "Верстаем попап на `` с использованием всех возможностей тега." +authors: + - annabaraulina +contributors: + - skorobaeus +keywords: + - popup + - модалка + - модальное окно + - dialog +related: + - html/dialog + - a11y/role-dialog + - a11y/aria-haspopup +tags: + - article +--- + +## Задача + +Создание попапа — распространённая задача для разработчика. Попапы или модальные окна привлекают внимание. Это может быть полезно как для самого пользователя, так и для заказчика. Например, попап — это удобный способ предупреждения о невозвратности действия при попытке перезагрузки страницы, а также хороший инструмент для сбора контактов пользователей. + +В статье покажем простой и понятный способ создания попапа с использование тега [``](/html/dialog/). + +## Готовое решение + +Для начала создадим HTML-разметку со всеми необходимыми элементами: + +```html + + + +
+

Дока — самая добрая документация 🙃

+ +
+
+ +``` + +Для внешнего оформления, а также правильной работы попапа, нам понадобятся следующие [CSS-правила](/css/css-rule/): + +```css +body { + min-height: 100vh; + padding: 50px; + display: grid; + justify-items: center; + align-items: center; + background-color: #18191C; + color: #FFFFFF; + font-family: "Roboto", sans-serif; +} + +dialog { + position: fixed; + height: 250px; + width: 350px; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + border: none; + padding: 0; + background-color: #FFFFFF; + color: #000000; + text-align: center; +} + +.openDialogBtn { + position: fixed; + bottom: 50px; + right: 50px; + min-width: 210px; + border: 2px solid transparent; + border-radius: 6px; + font-size: 18px; + font-weight: 300; + font-family: inherit; + transition: background-color 0.2s linear; +} + +.closeDialogBtn { + margin: 15% auto 0; + border: 2px solid transparent; + min-width: 210px; + border-radius: 6px; + padding: 9px 15px; + color: #000000; + font-size: 18px; + font-weight: 300; + font-family: inherit; + transition: background-color 0.2s linear; + display: flex; + justify-content: center; + align-items: center; + color: white; +} + +.dialog__wrapper { + padding: 1em; +} + +dialog::backdrop { + background-color: rgba(0, 0, 0, 0.5); +} + +.scroll-lock { + overflow: hidden; +} +``` + +Реализуем открытие и закрытие попапа с помощью JavaScript-методов: + +```javascript +const dialog = document.getElementById('myDialog') +const dialogOpener = document.querySelector('.openDialogBtn') +const dialogCloser = document.querySelector('.closeDialogBtn') + +function closeOnBackDropClick({ currentTarget, target }) { + const dialog = currentTarget + const isClickedOnBackDrop = target === dialog + if (isClickedOnBackDrop) { + dialog.close() + } +} + +function openModalAndLockScroll() { + dialog.showModal() + document.body.classList.add('scroll-lock') +} + +function returnScroll() { + document.body.classList.remove('scroll-lock') +} + +function close() { + dialog.close() + returnScroll() +} + +dialog.addEventListener('click', closeOnBackDropClick) +dialogOpener.addEventListener('click', openModalAndLockScroll) +dialogCloser.addEventListener('click', (event) => { + event.stopPropagation() + close() +}) +``` + + + +## Разбор решения + +### Разметка + +Сделаем `` дочерним элементом относительно [``](/html/body/). Это позволит нам в дальнейшем расположить попап по центру экрана. Текст и кнопку внутри модального окна обернём в тег с классом `dialogWrapper`. С помощью этой обёртки мы реализуем закрытия попапа по клику на тёмную область (оверлей). Атрибуты [`aria-haspopup`](/a11y/aria-haspopup/) и [`aria-controls`](/a11y/aria-controls/) сообщают вспомогательным технологиям о том, как связаны элементы. Так они повышают доступность приложения для пользователей. + +```html + + + +
+

Дока — самая добрая документация 🙃

+ +
+
+ +``` + +### Стили + +Для центрирования попапа на странице присвоим ему [`position: fixed`](/css/position/), а также зададим 50% для его расположения по осям для `top` и `left`: + +```css +dialog { + position: fixed; + height: 250px; + width: 350px; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + border: none; + padding: 0; + background-color: #FFFFFF; + color: #000000; + text-align: center; +} +``` + +Встроенной функцией тега `` является его подложка. Она появляется в момент открытия попапа и имеет название `::backdrop`. С помощью этого псевдоэлемента мы можем стилизовать задник модального окна, а также реализовать его закрытие по клику на оверлей. Первое реализуем с помощью правил CSS — добавим затемнение на экран за открытым попапом: + +```css +dialog::backdrop { + background-color: rgba(0, 0, 0, 0.5); +} +``` + +Если на странице с попапом есть скролл, его можно заблокировать с помощью свойства [`scrollbar-gutter`](/css/scrollbar-gutter/) для нашего ``. Это позволит нам полностью сконцентрировать внимание пользователя на модальном окне и запретить прокрутку контента на странице за ним. + +```css +body { + min-height: 100vh; + padding: 50px; + background-color: #18191c; + color: #ffffff; + font-family: "Roboto", sans-serif; + font-size: 18px; + scrollbar-gutter: stable; +} + +.scroll-lock { + overflow: hidden; +} +``` + +### JavaScript + +Для начала найдём все элементы, которые понадобятся нам для работы с попапом — модальное окно и кнопки для его открытия и закрытия: + +```javascript +const dialog = document.getElementById('myDialog') +const dialogOpener = document.querySelector('.openDialogBtn') +const dialogCloser = document.querySelector('.closeDialogBtn') +``` + +Напишем функции для открытия и закрытия попапа. Также поместим в них код, необходимый для блокировки скролла страницы. Не забудем вернуть скролл обратно при закрытии попапа: + +```javascript +function openModalAndLockScroll() { + dialog.showModal() + document.body.classList.add('scroll-lock') +} + +function returnScroll() { + document.body.classList.remove('scroll-lock') +} + +function close() { + dialog.close() + returnScroll() +} +``` + +Навесим соответствующие обработчики событий на наши кнопки: + +```javascript +dialogOpener.addEventListener('click', openModalAndLockScroll) +dialogCloser.addEventListener('click', (event) => { + event.stopPropagation() + close() +}) +``` + +В коде выше мы поместили [`stopPropagation()`](/js/event/) внутрь обработчика события на кнопку закрытия попапа. Это необходимо для того, чтобы реализовать закрытие модального окна по клику на оверлей. Снова не будем забывать о возвращении скролла странице: + +```javascript +function closeOnBackDropClick({ currentTarget, target }) { + const dialog = currentTarget + const isClickedOnBackDrop = target === dialog + if (isClickedOnBackDrop) { + dialog.close() + returnScroll() + } +} + +dialog.addEventListener('click', closeOnBackDropClick) +``` + +Другой функцией нашего попапа окажется его закрытие по нажатию на клавишу Esc. Это является встроенной функцией элемента `` и не требует дополнительного кода.