Модальные окна, которые мы заслужили

Начнем


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

Многие зададут вопрос: «Почему не использовать готовые решения?». Проблема в том, что этот функционал либо вообще не реализован, либо сделан очень плохо. Можно использовать самое простое и плохое решение:

.body { overflow: hidden;}

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

Анимация проблемы(Gif)


Некоторые решения на просторах npm предлагают замену скролла отступом или блоком, который стилизован под скролл (простая серая полоска), много магии, но проблему они не исправляют.

Немного подправим начальный код, и все работает:

.body { 
    position:fixed;
    overflow-y: scroll;
}

Теперь появилась другая проблема: страница прыгает вверх. Код. Решение через js простое: при открытии страницы берем значение, на которое проскроллена страница, и задаем это значение свойству top тега <body> Код.

function getBodyScrollTop() {
    return self.pageYOffset || (document.documentElement && document.documentElement.ScrollTop) || (document.body && document.body.scrollTop);
  }

openModalButton.addEventListener('click', e => {
  e.preventDefault()
  
  body.dataset.scrollY = getBodyScrollTop() // сохраним значение скролла
  body.style.top = `-${body.dataset.scrollY}px`
  
  modal.classList.add('modal--open')
  body.classList.add('body-lock')
})

closeModalButton.addEventListener('click', e => {
  e.preventDefault()
  
  modal.classList.remove('modal--open')
  body.classList.remove('body-lock')
  window.scrollTo(0, body.dataset.scrollY) // берем значение, которое сохранили
})

Иногда на сайте может встречаться страничка, у которой мало контента и нет скролла, но при открытии модального окна наш код добавляет его. Немного доработаем скролл. Готовое решение.

function existVerticalScroll() {
   return document.body.offsetHeight > window.innerHeight
}

openModalButton.addEventListener('click', e => {
  e.preventDefault()
  
  body.dataset.scrollY = getBodyScrollTop()
  
  modal.classList.add('modal--open')
  
  if(existVerticalScroll()) { // новая строка
     body.classList.add('body-lock')
     body.style.top = `-${body.dataset.scrollY}px`
   }
})

closeModalButton.addEventListener('click', e => {
  e.preventDefault()
  
  modal.classList.remove('modal--open')
  
  if(existVerticalScroll()) { // новая строка
   body.classList.remove('body-lock')
   window.scrollTo(0,body.dataset.scrollY)    
  }
})

Доступность


Если о ней не подумать, будет возможное перемещение с помощью таба вне модального окна. На gif только нажатие Tab несколько раз.

Анимация проблемы(Gif)


На просторах интернета нет простого решения этой проблемы, а писать свой костыль велосипед не очень рационально, когда есть библиотека focus-trap.js. Здесь автор более детально раскрыл тему библиотек и их проблем.

// Не забудьте подключить плагин
const modalFocusTrap = createFocusTrap(".modal"); // инициализируем плагин для модального окна

openModalButton.addEventListener('click', e => {
  e.preventDefault()
  
  body.dataset.scrollY = getBodyScrollTop()
  
  modal.classList.add('modal--open')
  modalFocusTrap.activate(); // новая строка. Активируем плагин

  if(existVerticalScroll()) {
     body.classList.add('body-lock')
     body.style.top = `-${body.dataset.scrollY}px`
   }
})

closeModalButton.addEventListener('click', e => {
  e.preventDefault()
  
  modal.classList.remove('modal--open')
  modalFocusTrap.deactivate(); // новая строка. Отключаем плагин

  if(existVerticalScroll()) {
   body.classList.remove('body-lock')
   window.scrollTo(0,body.dataset.scrollY)    
  }
})

Итоги


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

function initModal(className) {
    // код, что мы писали выше для одной модалки
}
initModal('modalName1')
initModal('modalName2')

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

Полезные материалы


Средняя зарплата в IT

110 500 ₽/мес.
Средняя зарплата по всем IT-специализациям на основании 6 970 анкет, за 2-ое пол. 2020 года Узнать свою зарплату
AdBlock похитил этот баннер, но баннеры не зубы — отрастут

Подробнее
Реклама

Комментарии 99

    +13

    Мы их не заслужили, но они нас преследуют везде.
    По большей части — навязывая нам какую-то хрень: "вы уже уходите", "мы вам перезвоним", "оставьте ваш емейл"…
    На мобильном в последнее время писк — открыть модальное окно без крестика (aka buttone close) — не закроешь — или оставляй телефон, или закрывай сайт нафиг.
    Мне уже наплевать в таком случае на скролл.
    Из-за такого использования модальные окна давно пора уже внести в bad practices и во всякие блокеры, аналогично window.open

      –6
      Мир кричит — чем меньше JS тем лучше (хватит нагружать мой комп всякой чухней, которой не факт что пользователь её воспользуется), но автор считает иначе.
      Остановил бы статью на фразе давайте таглить класс со свойствами body { overflow: hidden;} и был бы молодец, но нет.
        0
        В разных критериях и манифестах качества есть такой пункт

        не я так считаю

        Тут больше проблема в том как сдать проект заказчику. Когда он зайдет на сайт, и увидит что при открытии модального окна скачут блоки у него явно будут вопросы.
          –4
          Вам можно посочувствовать, если вам попался настолько дотошный заказчик. *Сам с такой проблемой по «скачущих» блоках при фиксации я не сталкивался. Возможно это по причине того что я использую normalize.css или ещё что.
            +3
            Normalize.css и например reset.css решают совсем другую задачу, у нас реализация поведении нативного скролла браузера
            0

            Если в зависимости от того, видна ли полоса прокрутки, или нет — скачут блоки, дело швах задолго до модальных окон.


            Решение .body { overflow: hidden;} — правильное, остальные — сразу в утиль.

              0
              Это решение не работает на iOS.
                0

                Этого не достаточно. Остаются проблемы подёргивания блоков из-за изменения ширины страницы на ширину полосы прокрутки. И проблемы с фокусом не решаются тоже. Если не понимаете о каком подёргивании идёт речь — прямо на этой странице откройте консоль и выполните следующий код:


                setInterval(function() {document.getElementsByTagName('body')[0].style.overflowY = document.getElementsByTagName('body')[0].style.overflowY === 'hidden' ? 'scroll' : 'hidden'}, 1024) 
                  0

                  Вот прямая цитата из комментария, на который вы отвечаете. Выделю жирным, для облегчения понимания.


                  Если в зависимости от того, видна ли полоса прокрутки, или нет — скачут блоки, дело швах задолго до модальных окон.
                    0

                    Вы код пробовали здесь на хабре? Как с этим швахом быть? Блоки скачут вправо-влево.

                      –1

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

                        +1

                        Это проблема проявляется в момент открытия\закрытия модального окна с применением body {overflow: hidden} (код эмулирует открытие\закрытие модала раз в секунду, сам модал при этом не показывается, но проблема overwlow видна)

                0
                Думаю вам стоит объяснить, что за такую фичу придется хорошо заплатить ). Может испугается и не будет больше просить. Или хорошо заплатит ).
                  +1
                  А может и не будет больше к вам обращаться. Сайт ведь не должен прыгать и дергаться.
                +1
                В случае с body { overflow: hidden;} появляется проблема: В разных браузерах бывают скроллы разной ширины, на телефонах так и вовсе нету полоски скролла. Ещё ухудшает ситуацию то, что ширина скролла отличается у разных версий браузера и то, что многим людям нравится ставить кастомную ширину скролла(например через about:config в ff).
                Но даже если не учитывать что скролл разный — padding-right для body на место скролла может вёрстку сайта. Просто напросто пользователь может свернуть браузер или переставить его в левую половину экрана и весь сайт обрежется пополам(так как для body стоит overflow:hidden)
                +1

                Ещё есть современное свойство overscroll-behavior
                https://developer.mozilla.org/en-US/docs/Web/CSS/overscroll-behavior

                  +1
                  К сожалению, баба яга яблоко, как обычно, против, в смысле не поддерживает.
                  Проблеме с прокруткой модалов из ещё бутстрап 3 на iOS лет уже 8 как, но воз и ныне там — программисты из Купертино лучше знают, что нужно их юзерам на абсолютно любом сайте в интернете.
                  0
                  Некоторые решения на просторах npm предлагают замену скролла отступом или блоком, который стилизован под скролл (простая серая полоска), много магии, но проблему они не исправляют.

                  у меня добавление отступа исправляет проблему, что я делаю не так? Да и магии в таком решении явно не больше чем в предложенном. Сейчас попробовал на действующем проекте после скролла страницы в инспекторе добавлять на body:


                  position: fixed;
                  overflow-y: scroll;
                  top: -100px;

                  куча разных артефактов вылазит. Колбасит элементы уже имеющие position: fixed (явно не по причине несовпадения top: -100px с проскроленным значением) и сжимает body по ширине. Со вторым не проблема, нужно ещё width: 100% на body добавлять, а вот что происходит с фиксированными элементами нужно разбираться, но добавление отступа на body проблем не создавало.

                    –3

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

                      +2

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

                        –3

                        но к сожалению в этом случае мы увидим маленькие буковки с пятью сносками о том что сайт не отвечает за последствия… вот человек который заработал на адблок думаю заработает не меньше если сделает блокировку модальных окон. ни разу не видел чтобы они использовались с пользой для пользователя

                        • НЛО прилетело и опубликовало эту надпись здесь
                            +1

                            ну да, тут с вами согласен. дело не в самих окнах конечно

                              +2

                              Вместо запроса "Вы действительно хотите удалить?" лучше сразу скрывать с глаз пользователя данные и в уведомлении ему сообщить: «в течение такого-то времени вы можете данные восстановить, после они будут удалены навсегда», — а по истечении указанного интервала фактически уничтожить данные.

                                +3
                                Это более сложная цепочка. Пользователь должен это прочитать, понять и запомнить где он это дело может восстановить и пр.
                                  +1

                                  Именно.

                                    0

                                    Если это какая-нибудь "корзина" онлайн магазина, то позицию можно не убирать из списка, а зачёркивать/делать еле видимой и поверх неё разместить сообщение "товар удалён, через N секунд он исчезнет с экрана. Восстановить товар в корзине".


                                    Если это какой-то сложный АРМ, где данные нужно убрать с экрана здесь и сейчас, то на странице историй действий оператора можно отдельно выводить доступное к восстановлению (отмене удаления) + в общем списке у того, что ещё не удалено фактически, выводить кнопку "отменить удаление". Или опция "показывать удалённые" на странице с объектами которыми оперирует пользователь.


                                    Это сложнее для "разработать", но удобнее для "использовать". Модальные окна проще "написать", но заставляют пользователей совершать лишние действия. А пользователь лишних телодвижений должен совершать только если он сделал что-то неправильно. Когда человеку необходимо удалить несколько десятков объектов, он лучше пару раз "сходит" в "корзину" восстановить ошибочно удалённые данные, чем несколько десятков раз будет нажимать на "да, я уверен, что хочу это удалить"

                                      +3
                                      Но тогда на бэкенде нужно будет реализовать «корзину», а это не всегда возможно. Среди «опасных» операций, не только удаление есть. Да и излишне усложнять систему ради достаточно редких операций очень накладно получается.
                                        0

                                        В общем случае атрибут "удалено" содержащий дату и время "удаления" объекта и периодически запускаемая задача по удалению "всего, что удалено X минут назад" решают проблему. Излишним усложнением системы это тяжело назвать.


                                        А вообще — да, надо думать и реализовывать. Собственно, это и отличает хороший продукт от основной массы. В одном сели и подумали, а в другом нафигачили как проще.

                                          0
                                          Ок. А как быть с кнопкой, например «перезагрузить виртуальную машину» и пр?
                                          Да и если удаление достаточно редкая операция, в БД нам придется делать отдельный флаг и везде собственно его проверять.
                                            +1

                                            Так же как гмыло делает с отправкой писем: "перезагружу VM через 10 секунд… отменить | перезагрузить незамедлительно"


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

                                            Или добавить отдельную таблицу, куда добавлять ссылки на объекты для удаления. Много места она не займёт. Или ещё как-нибудь. Смотреть на архитектуру надо.

                                            • НЛО прилетело и опубликовало эту надпись здесь
                                                0

                                                Не хрен знает где, а во вполне определённом месте. Лучше это тем, что пользователю, которому не критично сию секунду в перезагрузку отправить гостя, не придётся отвлекаться на "да/нет?"

                                                • НЛО прилетело и опубликовало эту надпись здесь
                                                    0

                                                    — Папа, а правда, что Windows многозадачная? Покажи!
                                                    — Сейчас, сынок, только дискету доформатирую…


                                                    Какие угодно. Может даже окно менеджера VM закрыть.


                                                    На что отвлекаться?

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


                                                    Чем пользователь занимался до того, как ему VM перезагрузить потребовалось, тем и будет дальше заниматься. Или к другому занятию перейдёт.

                                                    • НЛО прилетело и опубликовало эту надпись здесь
                                                        0

                                                        Существуют ли сценарии, где пользователь будет нажимать "перезагрузить немедленно"? Существуют. Иначе бы зачем я вам про эту кнопку говорил?
                                                        Ровно так же существуют сценарии, где пользователь не будет нажимать эту кнопку. Зачем заставлять 100% пользователей нажимать 2 кнопки там, где можно обойтись одним действием?

                                            –5

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

                                              0

                                              Хороший продукт всегда есть продукт соответствующий бизнес-ожиданиям заказчика. Продукт соответствующий бизнес-ожиданиям заказчика не всегда есть хороший продукт.


                                              И да, я не говорю: «модальные окна делают только люди не умеющие ни во что кроме». Почему вы себе позволяете подобные высказывания? Не хватает аргументов?

                                                –3
                                                Почему вы себе позволяете подобные высказывания?

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


                                                любые другие модальные окна есть следствие непродуманности интерфейса

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


                                                Есть куча бизнес-кейсов, когда переадресация в принципе не вариант, но вы же не спросили сначала «а можем ли мы покинуть страницу в принципе?», вы начали с ультимативного «всегда».


                                                Аргументов у меня полно́, но какой смысл их приводить, если вы их не понимаете, а в ответ цитируете Горбунова и Бирмана? Чтобы нарваться еще на одну цитату из источника, который вообще никаким боком не может быть назван доверенным?

                                                  +1
                                                  Потому что я свободный человек

                                                  Так давайте матом общаться, мы же свободные люди. А потом морды свободно друг другу набьём. Или таки останемся в рамках приличия?


                                                  даже просто не удосужившись поинтересоваться спецификой бизнеса

                                                  Финансы, аудит, проектирование, производство, творчество? Что это изменит? Бизнес логика никак не влияет на решение "модально или нет". Бизнес описывает последовательность действий и условий, у бизнеса нет модальных окон. UI дизайнер делает интерфейс под эту последовательность, решение "показать поверх модальное окно или отключить возможность изменения данных и вывести сообщение в текущем" принимает дизайнер. И если дизайнер не способен продумать интерфейс без модальных окон, они появляются в мире "бизнеса" и только тогда их выбирает бизнес, т. к. "профессионал" показал, что оно — лучший вариант.


                                                  Есть куча бизнес-кейсов, когда переадресация в принципе не вариант, но вы же не спросили сначала «а можем ли мы покинуть страницу в принципе?», вы начали с ультимативного «всегда».

                                                  Модальные окна бывают не только в интернете. И доступность переадресации здесь в принципе не играет роли. Что за бред, простите? Вы как-то модальный диалог показываете? Что мешает в том же скрипте, грубо, спрятать кнопку "перевести деньги" и показать кнопки "уточнить данные" и "подтвердить платёж"?


                                                  в ответ цитируете Горбунова и Бирмана?

                                                  Ну извините, что моё мнение в данном вопросе совпадает с их мнением. Шёл бы разговор о кириллизации названий иностранных компаний — я бы с ними спорил.


                                                  Аргументов у меня полно, но какой смысл их приводить

                                                  Чтобы ваши слова обрели хоть какой-либо вес в диспуте. Пока же кроме "я не знаю как без модального дива интерфейс платежа оформить" вы аргументов не привели.

                                                    –4

                                                    Нет такой профессии «дизайнер».


                                                    Столяр, строитель, шахтёр — это профессии. Люди, которые хотят остричь все вокруг под горшок своих предпочтений могут быть даже востребованы и оплачиваемы, в некоторых местах, в определённое время. Но профессионалами им не стать никогда, просто в силу этимологии этого слова.

                                  • НЛО прилетело и опубликовало эту надпись здесь
                                      +1

                                      Сообщать пользователю "я удалил" тоже надо не просто для галочки, а так, чтобы он этим смог воспользоваться.


                                      А на тему "конфирм спасёт от случайного удаления" в Бюро в советах давно хорошая заметка была: https://bureau.ru/bb/soviet/20151215/

                                        0
                                        Сообщать пользователю «я удалил» тоже надо не просто для галочки [...]

                                        Сообщать пользователю «я удалил» надо даже тогда, когда пользователь этой информацией воспользоваться не может никак, для его, пользователя, спокойствия (и иногда для аудит-отчетности еще).

                                      +1
                                      Я бы не был так категоричен. Идея хорошая, только вот где именно выдавать такое сообщение? А если пользователь его пропустил и не увидел?
                                      Я не просто так про это говорю. Обожглись просто.
                                      В свое время мы делали такое в одной популярной корпоративной CRM -системе. Выдавали такое предупреждение не модалкой, а на странице, назовем их «услугами» или «делами». Т.е. пользователь решив отредактировать свои услуги/дела/задачи и удаляя то, что ему как он думает не нужно, мы скрывали сразу, но рядом с кнопками перехода на другие страницы и вверху экрана мы выдавали такое сообщение, как вы и пишите, со ссылкой где данные можно восстановить. Эта же ссылка на восстановление была в личном кабинете пользователя, причем первая сверху.

                                      Так вот тут и вскрылся один нюанс: если пользователь профессионал, то он спокойно все читает и если надо восстанавливает (администраторы, программисты работали без всяких проблем, даже получали фидбэк что им это удобно), но вот если системой пользовался простой пользователь (менеджер, работники call-центра, торговые представители), то у них сразу начиналась паника и вопли «куда все пропало?» и они судорожно закрывали все окна и открывали их заново, естественно «не замечая» ничего. Сделали модалку, тут все вопли прекратились.

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

                                      «Модальность создает фокусировку, не давая людям заниматься другими делами, прежде чем они не завершат задачу или не отклонят вызванное в модальном окне представление» — Apple

                                      Вот еще
                                        +1

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


                                        Как быть, если "не заметил"? Не допускать этого. Сообщение о том, что элемент удалён не должно быть таким же как уведомление о новом сообщении (повисело в сторонке и пропало). Повторюсь, из списка услуг можно услугу не сразу убирать, а помечать её удалённой, пока есть возможность восстановить.
                                        Или анимацией показать, что удалённый элемент "улетел в корзину".


                                        ЦА знать надо, но тут есть нюанс. Не одного человека видел, который сначала в браузере набирает одним пальцем "яндекс", потом в яндекс вбивает "сбербанк", потом в выдаче яндекса переходит по ссылке и идёт в личный кабинет. Объясняешь ему, что можно сразу в строку написать "сбербанк" и сразу или на сайт сбера попасть (по подсказке из истории) или открыть ту же выдачу яндекса. Нет — это не так удобно. Это же не значит, что разработчикам браузеров следует идти за привычками подобных пользователей.

                                    0

                                    Не понял, если честно.


                                    Вот у нас финтех. В какой-то момент пользователь должен подтвердить трансфер на €10М. Предложите, пожалуйста, альтернативу модальному окну.

                                      +2

                                      10 немодальных по €1M?

                                        0

                                        я бы сделал переадресацию на другую страницу с подтверждением, так безопаснее

                                          0
                                          так безопаснее

                                          Ровно наоборот, вообще-то. Но дело даже не в этом. Переадресация может сломаться, или занять какое-то время, что в случае, например, обмена валюты по текущему курсу — не вариант.

                                            0

                                            лучше сломается переадресация чем вывод модального окна. иногда скрипты не вызываются из-за какой-то ошибки до них, и что тогда? так что с точки зрения безопасности (именно неправильного проведения платежа) безопаснее всё-таки отдельная страница с подтверждением, потому что она идёт через отдельный серверный механизм, или даже через отдельный сервер (как в случае банковских платежей с 3D security)

                                              –3

                                              У меня есть предложение: вы не даете беспощадных советов по теме, в которой явно мало, что понимаете, а я больше не спорю.


                                              Спасибо.

                                                –1

                                                у меня есть альтернативное предложение: поскольку это форум инженеров, и мы тут собрались не чтобы меряться мониторами, а чтобы помогать друг другу разобраться в сложных вещах, предлагаю конструктивно указывать на ошибки. просто стандартный генератор кода CRUD Entity framework в visual studio делает именно так — отдельный action для подтверждения удаления — и я понимаю почему. скрипт может не загрузиться и не отработать, скрипты могут быть вобще выключены в целях безопасности, и я вижу недостатки подхода модальных окон. на десктопе там понятно — одно и то же приложение отвечает за всё, поэтому другого подхода нет. а в вебе, где эти окна можно легко заменить на что-то более удобное и безопасное. в том виде в каком модельные окна используются сейчас в 99% случаев они только раздражают, как мне кажется. если вы видите в моих рассуждениях какую-то техническую ошибку, подскажите мне пожалуйста в чём я не прав и как правильно. если вы просто не хотите со мной общаться можете просто не отвечать на этот комментарий и на все другие

                                                  0

                                                  Ровно наоборот, в десктопном приложении мы имеем полный контроль относительно малой кровью — модалки, уведомления, истории ундо-редо, что угодно. У нас однопользовательское приложение, монопольно, как правило, владеющее данными.

                                          +3

                                          Заблокировать поля ввода и немодально вывести кнопки «Подтвердить платёж» и «Скорректировать данные» на той же странице.


                                          Если пользователь хотел перевести деньги — он нажмёт кнопку подтверждения. Если пользователь опечатался — нажмёт на кнопку изменения данных, чем разблокирует форму и снова "перевести"→"подтвердить".


                                          Если пользователь не хочет этот трансфер — он первым же кликом перейдёт на другую страницу по любой из ссылок в личном кабинете. С модальным окном ему придётся сначала закрыть это окно.


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

                                            –1
                                            Заблокировать поля ввода и немодально вывести кнопки «Подтвердить платёж» и «Скорректировать данные» на той же странице.

                                            Через 10 минут, после того, как мы это прикрутим, middle office будет блокирован шквалом звонков от пользователей «у меня все зависло, памагите!». Появившиеся кнопки заметит 10%. Для того, чтобы об этом узнать, достаточно один раз провести AB тестирование.


                                            Если пользователь не хочет этот трансфер

                                            Пользователь хочет, инфа 100%.


                                            он в новой вкладке откроет другую часть личного кабинета

                                            Пользователи примерно никогда не открывают ничего в соседней вкладке. Вы бы хоть UX статистику какую-нибудь посмотрели, прежде чем советовать.

                                              –2
                                              Для того, чтобы об этом узнать, достаточно один раз провести AB тестирование.

                                              Вы его, конечно, провели. Результатами и их анализом поделитесь? Ну и было бы неплохо посмотреть на реализацию, чтобы исключить проблему в её некорректности.

                                                0

                                                Результатами я поделился в комментарии, на который вы отвечаете. Анализ мы не делали, мы наивно решили, что если 9 из 10 человек предпочитают модальный диалог, велосипед мы изобретён где-нибудь в другом месте.

                                                  +1

                                                  Если «мы не пойми как (возможно очень криво) сделали, и у нас не зашло» — результаты. То извините…
                                                  У нас 10 из 10 человек предпочитают, чтобы интерфейс лишний раз не блокировался без причины.


                                                  Ваши "результаты" против наших "результатов".

                                                    –1
                                                    интерфейс лишний раз не блокировался без причины

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

                                                      0

                                                      Под «Без причины» я понимаю «наш дизайнер не способен решить задачу грамотно, поэтому лепит модалки», а не отсутствие причины.


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

                                                      • НЛО прилетело и опубликовало эту надпись здесь
                                                          +1

                                                          По себе судите? Минусов столько поставить у меня запаса голосов не хватило бы. Так что это не я. А те несколько, что я поставил — исключительно за манеру общения с переходом на личности вместо конструктивного обсуждения, а не за отличное от моего мнение. И те, если не изменяет память, не вам.


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

                                            • НЛО прилетело и опубликовало эту надпись здесь
                                                0
                                                Если не помещается — что делать?

                                                Очевидно, нужно переводить фокус на элемент "отредактировать". С фокусом браузер сам вам прокрутит.


                                                Если не помещается — что делать?

                                                Давай ТЗ и бюджет — обсудим, что делать в вашем конкретном случае. Разработчику голова дана не чтобы код копипастить шаблонный, а чтобы удобный инструмент для решения задач пользователей предоставлять.


                                                я еще могу кучу проблем найти в таком примере, которых модалка не имеет.

                                                Не стесняйтесь, оглашайте.

                                                • НЛО прилетело и опубликовало эту надпись здесь
                                                    0
                                                    Я написал выше про проблемы со скролом

                                                    Это надуманные проблемы. Или проблемы вызванные плохой информативностью интерфейса.


                                                    когда разработчику дают задачи дизайнера начинается такой треш как у вас

                                                    А я — дизайнер, или разработчик? И какой треш? Я вам выше ссылку на Илью Бирмана давал. По данному вопросу я с ним солидарен. У него в голове тоже треш из серии "погромист в дезигнера играет"?

                                      +1

                                      Но зачем блокировать прокрутку при открытом модальном окне? Это же наоборот удобно...

                                        0

                                        Вы меня простите за категоричность, но единственный способ сделать нормальное модальное окно — никогда не использовать модальные окна, исключение есть только для окна ОС с запросом пароля пользователя для повышения прав приложения, и то не факт.


                                        Что «последние китайские предупреждения», что любые другие модальные окна есть следствие непродуманности интерфейса.

                                          –2
                                          любые другие модальные окна есть следствие непродуманности интерфейса

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

                                            +2

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

                                              0

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

                                                +2

                                                Что значит «есть несохранённые данные»? Если пользователь сутки трудился над проектом и у него электричество пропало, всё? Конец проекту?


                                                Пользовательские данные — самое ценное, что есть на компьютере. Их нужно сохранять всегда. Вы либо делаете резервную копию оригинального файла, либо изменённый файл храните "у себя". Пользователю сообщаете «вы тут в прошлый раз не сохранили… а я изменения помню, могу сохранить сейчас. Или не надо?». Только делать это надо не как офисные пакеты, которые вываливают модальное окно "восстановить файлы?". Я сейчас другой документ открыть попытался, что ты ко мне пристаёшь? Выведи плашку сверху\сбоку, как будет возможность — приму решение.


                                                И в настройки добавить "сохранять все изменения сразу", тогда можно просто всегда сохранять.

                                                  –1

                                                  Пользовательские данные — это, в частности, открытая транзакция между нашим сервером и liquidity provider. Этих данных на клиентской машине нет, и быть не может.


                                                  Или вот другой вариант: у клиента установлена максимальная сумма транзакции в день, скажем, сто рублей. И три оператора. В разных странах. Все трое одновременно размещают заказ на 40 рублей. Третья по времени транзакция пройти не сможет (это знаем мы), но если вторую транзакцию отвергнет liquidity provider, то — снова сможет. Если мы переадресуем третьего пользователя куда-нибудь, то что делать, когда сервер поймет, что надо снова показать заленую кнопку? Серия редиректов? Ну-ну.


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

                                                    +1
                                                    Этих данных на клиентской машине нет, и быть не может.

                                                    Если данных на клиентской машине нет — то всё ещё проще: сохранять-то нечего :-)


                                                    Если мы переадресуем третьего пользователя куда-нибудь, то что делать, когда сервер поймет, что надо снова показать заленую кнопку?

                                                    А что, собственно, помешает её показать?

                                                      0
                                                      то всё ещё проще: сохранять-то нечего

                                                      Данных-то нет, состояние-то есть.


                                                      А что, собственно, помешает её показать?

                                                      То, что в случае без модального окна — мы на странице с ошибкой из-за редиректа до этого. Прокрутка к «вспыхнувшей» кнопке, предложенная где-то вокруг — это просто ад, который не поймет ни один пользователь.

                                                        +1
                                                        То, что в случае без модального окна — мы на странице с ошибкой из-за редиректа до этого

                                                        Так предусмотрите для пользователя возможность вернуться обратно-то!

                                                          –2

                                                          Серьезно? Показать «мы не можем выполнить транзакцию», а потом спустя пять секунд сказать «а нет, шутка, можем»? И куда кнопку «вернуться» воткнуть? Вниз и снова блистательный вариант прокрутки к ней? Поверх всего — модальным окном?


                                                          Вы действительно хотите, чтобы из-за дизайнерских изысков пользователи считали нас дебилами?

                                                            0
                                                            Серьезно? Показать «мы не можем выполнить транзакцию», а потом спустя пять секунд сказать «а нет, шутка, можем»?

                                                            А разве не именно это вы делаете модальным окном? По вашему описанию я понял именно так.


                                                            Если модальные окна используются как-то по-другому — то расскажите как именно.

                                                              0

                                                              Мы показываем throttle на некоторое время, потом сообщаем о проблемах со связью и предлагаем подождать, если пользователь хочет. Когда мы получаем подтверждения по всем ранее запущенным транзакциям, показываем кнопку «выполнить», или «недостаточно средств» в зависимости от того, что там вернулось. Пользователь уютно продолжает думать, что он страницу не покидал, все под контролем, процесс идет.


                                                              Это последний комментарий, который я пишу в этой ветке (и, скорее всего, вообще), потому что, оказывается, у меня теперь не хватает кармы комментироват столько, сколько мне хочется.


                                                              Буду заниматься тем, ради чего и завел этот аккаунт: писать про Elixir.

                                                                +1

                                                                Ну так ничего не мешает делать всё то же самое, но без модальных окон.

                                                      +1

                                                      Это что за B2B система у разработчиков которой "либо модальное окно, либо редирект"?


                                                      Рядом с кнопкой подтверждения написать "выполняю транзакцию" — вообще не вариант? Это даже дешевле будет с точки зрения ресурсов.
                                                      Или "что-то где-то зависнуть" может, а с модальным окном сразу все проблемы уходят?


                                                      Вы пытаетесь бизнес логикой оспорить оформление наглядного представления этой же самой логики. Если без "спрятать от пользователя всё, кроме одного сообщения" — это единственный способ донести информацию до пользователя, значит у вас интерфейс перегружен и\или нелогичен.

                                                0

                                                От вас не дождался примера в этой ветке. Ответил выше вам, + в соседней ветке: https://habr.com/ru/post/483114/#comment_21101194

                                              0
                                              Вот такой скрипт есть для блокировки скролла на всех устройствах github.com/willmcpo/body-scroll-lock#readme
                                                0
                                                Еще дополню, что есть еще проблема с fixed элементами, если добавлять отступ к body вместо скролла, то fixed элементы будут тоже дергаться. Решается так же добавлением к ним padding-right или right равные размеру скролла.
                                                  0
                                                  Плагин работает, но у него есть проблема которая описана в статье.
                                                  Gif Demo body-scroll-lock

                                                    0
                                                    У него есть параметр reserveScrollBarGap, по-умолчанию отключен. Он как раз служит для того чтобы зарезервировать пространство вместо скроллбара.
                                                      0
                                                      Супер, плагин реально работает, не заметил сначала этот параметр.

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

                                                +1
                                                Если есть возможность использовать JS, то можно просто запретить скролл
                                                Например
                                                .
                                                offScrollUnderBlock(_overlay) {
                                                      var _clientY = null;
                                                      _overlay.addEventListener("touchstart", function(event) {
                                                        if (event.touches.length === 1) {
                                                          _clientY = event.touches[0].clientY;
                                                        }
                                                      });
                                                
                                                      _overlay.addEventListener("touchmove", function(event) {
                                                        if (event.touches.length === 1) {
                                                          disableRubberBand(event);
                                                        }
                                                      });
                                                      _overlay.addEventListener("mousewheel", function(event) {
                                                        if (parseInt(event.wheelDelta || -event.wheelDeltaY) >= 0) {
                                                          if (_overlay.scrollTop === 0) {
                                                            event.preventDefault();
                                                          }
                                                        } else {
                                                          if (isOverlayTotallyScrolled()) {
                                                            event.preventDefault();
                                                          }
                                                        }
                                                      });
                                                
                                                      function disableRubberBand(event) {
                                                        var clientY = event.touches[0].clientY - _clientY;
                                                        if (_overlay.scrollTop === 0 && clientY > 0) {
                                                          event.preventDefault();
                                                        }
                                                        if (isOverlayTotallyScrolled() && clientY < 0) {
                                                          event.preventDefault();
                                                        }
                                                      }
                                                
                                                      function isOverlayTotallyScrolled() {
                                                        return (
                                                          _overlay.scrollHeight - _overlay.scrollTop <= _overlay.clientHeight
                                                        );
                                                      }
                                                    }


                                                  0

                                                  Только не забудьте повесить аналогичные обработчики на сам диалог, с вызовами event.stopPropagation()

                                                    0
                                                    Вы имеете в виду, чтобы сама модалка скроллилась?
                                                  0
                                                  Здесь мы получаем легкое подергивание страницы. Код. Стоит отметить: проблема встречается только там, где скролл занимает место на странице, например, в Safari такой проблемы нет.

                                                  Chrome/Firefox, MacOS — никакого подергивания, все ОК. Насколько я знаю нa маке во всех браузерах по умолчанию полоски скролла скрыты.
                                                  • НЛО прилетело и опубликовало эту надпись здесь
                                                    +1

                                                    Добавлю несколько советов от себя касательно доступности.


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


                                                    2. При открытии модального окна, нужно обязательно переместить фокус на него. Чтобы скринридеры или ещё что — озвучили, что фокус сместился и куда. Да и при использовании какого-то телевизора, вам не придётся проходить табами всю страницу в поисках как добраться в модальное окно.


                                                    3. Обязательно использовать тег


                                                      <dialog>

                                                      Или секцию с соответствующей ролью


                                                      <section role="dialog">

                                                      Это нужно для того, чтобы ваш блок был семантически опознан как "Диалог".


                                                    4. Внутри модалки, обязательно нужен заголовок. Пусть даже скрытый, чтобы те же скринридеры и ТП озвучили что это за модалка


                                                      <section role="dialog">
                                                      <h2 class="show-screen-reader-only">Подтвердите действие</h2>
                                                      </section>

                                                    5. Если логика модалки предполагает возможность закрыть его без подтверждения (по типу клика на крестик, или клик по кнопке "Отменить") то эту же функциональность необходимо назначить на клик по клавише esc. Так как во многих системах такое поведение является обычным и привычным пользователю. И его необходимо реализовывать в ваших кастомных модальных окнах.


                                                    6. Если модалное окно подразумевает отправку каких-то данных, то внутри обязательно должен быть тег <form>, а саму модалку стоит автоматическии закрывать после успешной отправки данных.


                                                    7. После закрытия модалки, если вы никуда не перенаправляете пользователя, фокус необходимо вернуть туда, где он был на момент открытия модального окна. Сами понимаете, это выбесит любого, если вы перемещаетесь по странице табами, были где-то в середине, открылось модальное окно, а после него вас отправило в начало страницы. И вам снова табать по всему документу в поисках места где вы были.


                                                    8. Бонус: Все скрипты и стили, необходимые для модального окна выносите в отдельный файл. И загружайте непосредственно перед тем как отобразить модалку. Никогда не включайте её в общий бандл.


                                                      –2
                                                      <body>
                                                      
                                                        <input id="input" type="checkbox" hidden>
                                                      
                                                        <div class="root">
                                                          <p>Lorem ipsum ...
                                                          <p>Lorem ipsum ...
                                                          <p>...
                                                        </div>
                                                      
                                                        <div class="modal">
                                                          <div class="c1"><div class="c2"><div class="c3">
                                                            <p>Ahtung!
                                                            <label for="input"><button>Achtung?</button></label>
                                                          </div></div></div>
                                                        </div>
                                                      
                                                      </body>

                                                      * {
                                                        margin: 0; padding: 0;
                                                        line-height: inherit; font: inherit;
                                                      }
                                                      
                                                      html, body, .root, .modal {
                                                        position: absolute;
                                                        top: 0; right: 0; bottom: 0; left: 0;
                                                        overflow: hidden;
                                                      }
                                                      body {
                                                        text-align: center;
                                                      -webkit-user-select: none;
                                                         -moz-user-select: none;
                                                          -ms-user-select: none;
                                                              user-select: none;
                                                      }
                                                      
                                                      .root {
                                                        overflow-y: auto;
                                                      }
                                                      .modal {
                                                        right: -16em; left: -16em;
                                                      }
                                                      
                                                      .c1 {
                                                        display: table;
                                                        width: 100%; height: 100%;
                                                      }
                                                      .c2 {
                                                        display: table-cell;
                                                        margin: 0 auto; vertical-align: middle; text-align: center;
                                                      }
                                                      .c3 {
                                                        display: inline-block;
                                                        margin: 0 auto;
                                                        width: 32em; height: 8em;
                                                        background: #ccc;
                                                      }

                                                      Смысл: Контент выводится не в body, а в root. Два абсолютных блока, root и modal. В body есть скрытый input. Body не имеет прокрутки вообще. Root имеет прокрутку когда нужно. Modal не имеет прокрутки. Modal лежит поверх root-а.
                                                      Кнопки завязаны через лейблы на input и делают видимым/невидимым modal посредством input-а тупо через css. Ровно так же включается/отключается через css свойство user-select там где это нужно.
                                                      Это всё давно делается через css. Убогие скрипты тут совершенно никому не нужны.

                                                      Все каменты просматривать совершенно лень.
                                                      Накидано за минуту. Сами доделаете, кому нужно.
                                                        –1
                                                        А просто padding-right: 15px добавить нельзя при открытие окна? И тогда не будет этого прыжка страницы.
                                                          +2
                                                          Почему 15? У меня например в хроме размер скролла 17px. В других браузер может быть совсем другое значение. Так что это не очень универсальное решение.

                                                        Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                                                        Самое читаемое