Pull to refresh

Popup с затухающим фоном с помощью jQuery

Reading time 8 min
Views 43K
imageМногие из нас сталкивались с всплывающими окнами, когда при этом постепенно потухает фон. Взгляд пользователя невольно фокусируется только на той части экрана, где что-то требуется от этого самого пользователя. Достаточно полезно, не правда ли?

Конечно же, не претендую на какую-то новизну, и данная заметка будет больше полезна начинающим с jQuery (коим и сам являюсь), чем людям, имеющим существенный опыт с данным javascript фреймворком.

Пример


Чтобы разместить пример — завел аккаунт на yandex. Надеюсь, что не забанят, если просмотров будет много. Итак, то, что мы хотим получить в итоге, можно посмотреть здесь.

Описание


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

Реализация


Для начала нам понадобится последняя версия библиотеки jQuery (на момент написания доступна версия 1.3.2).
Далее в начало нашей разметки мы помещаем два блока:
  • «opaco» — это будет темный слой, который спрячет лишнее вокруг окна;
  • «popup» — это будет блок, в который мы вставим необходимое содержимое.
<div id="opaco" class="hidden"></div>
<div id="popup" class="hidden"></div>


* This source code was highlighted with Source Code Highlighter.

Далее нам необходимо добавить сами ссылки и формы, которые по умолчанию будут скрыты:

форма для ошибки:
<div class="user-actions">
  <p class="bug"><a href="#" onCLick="showPopup('bug'); return false;">Сообщите об ошибке на сайте!</a></p>
</div>

 <div id="popup_bug" class="hidden">
 <div class="bug">
  <form action="#" class="bug">
   <h3>Зaвести ошибку</h3>
   <div class="form_error"></div>
   <p>Раздел, где обнаружена ошибка:</p>
   <input type="text" />
   <p>Описание ошибки:</p>
   <textarea rows="5" cols="30"></textarea>
   <input type="button" value="Отправить" onclick="closePopup(); return false;" />
   <input type="button" value="Отмена" onclick="closePopup(); return false;" />
  </form>
 </div>
</div>


* This source code was highlighted with Source Code Highlighter.

Для примера, на обе кнопки мы назначаем действие — закрыть форму (closePopup()).

форма для отзыва:
 <div class="user-actions">
  <p class="reference"><a href="#" onCLick="showPopup('reference'); return false;">Оставьте свой отзыв!</a></p>
</div>

 <div id="popup_reference" class="hidden">
 <div class="reference">
  <form action="#">
   <h3>Оставить отзыв</h3>
   <div class="form_error"></div>
   <p>Ваше мнение:</p>
   <textarea rows="5" cols="30"></textarea>
   <input type="button" value="Отправить" onclick="closePopup(); return false;" />
   <input type="button" value="Отмена" onclick="closePopup(); return false;" />
  </form>
 </div>
</div>


* This source code was highlighted with Source Code Highlighter.

Итак, теперь можно приступать и к самим функциям отображения и закрытия всплывающего окна. Логично начать с отображения:
//open pop-up
function showPopup(popup_type)
{
  //when IE - fade immediately
  if($.browser.msie)
  {
   $('#opaco').height($(document).height()).toggleClass('hidden');
  }
  else
  //in all the rest browsers - fade slowly
  {
   $('#opaco').height($(document).height()).toggleClass('hidden').fadeTo('slow', 0.7);
  }

  $('#popup')
   .html($('#popup_' + popup_type).html())
   .alignCenter()
   .toggleClass('hidden');

  return false;
}


* This source code was highlighted with Source Code Highlighter.

Первая часть функции обрабывает блок с id=«opaco». Первым делом данному блоку присваивается высота равная всему документу, используя jquery метод height. Это нужно, чтобы затемнить даже ту часть страницы, которая под скроллом. Причем мы здесь используем сразу две разновидности метода — если не передавать аргумент, то мы просто получаем текущее значение height объекта (у нас в примере $(document).height()), а если передать аргумент — то мы присваиваем объекту, над которым производим действие, данную высоту (в нашем примере объект $('#opaco')).

Теперь мы уверены, что блок '#opaco' покрывает весь документ и отображаем его, убирая класс 'hidden' (toggleClass('hidden')).
В зависимости от браузера — мы делаем затемнение: если IE — то там плавного затухания сделать не получится (а мы даже и не пытаемся), а вот во всех остальных случаях, мы постепенно затемняем блок, используя метод fadeTo('slow', 0.7).

Вторая половина функции обрабатывает следующий блок — id=«popup».
первым делом мы наполняем этот блок нужным нам содержимым, в зависимости от того, какое значение передается в функцию.
Последним действием мы отображаем этот блок, опять же убирая класс 'hidden'.

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

alignCenter — это определенный нами метод, его нет в стандартном пакете jQuery. Определить свой метод очень просто:
//additional properties for jQuery object
$(document).ready(function(){
  //align element in the middle of the screen
  $.fn.alignCenter = function() {
   //get margin left
   var marginLeft = Math.max(40, parseInt($(window).width()/2 - $(this).width()/2)) + 'px';
   //get margin top
   var marginTop = Math.max(40, parseInt($(window).height()/2 - $(this).height()/2)) + 'px';
   //return updated element
   return $(this).css({'margin-left':marginLeft, 'margin-top':marginTop});
  };
});


* This source code was highlighted with Source Code Highlighter.

Прежде всего, его определять необходимо после загрузки всего DOM документа браузером, для этого мы используем jQuery метод $(document).ready().

Внутри нашего метода мы находим вначале отступ сверху и отступ слева по простой формуле. Для этого нам понадобится размеры экрана у клиента и размеры нашего всплывающего окна. Полезным свойством jQuery здесь является возможность обращаться к объекту, к которому мы собираемся применять наш метод, через $(this). Таким образом, в зависимости от размера всплывающего блока, мы динамически посчитаем необходимые отступы. На всякий случай, если всплывающий блок будет сильно большим или размеры экрана сильно маленькие — мы задаем минимальные отступы в 40px, чтобы не уехать за левую границу экрана.

Ну и под конец нам нужно применить эти новые отступы, что мы делаем через метод css({'margin-left':marginLeft, 'margin-top':marginTop}).

C отображением мы закончили, осталось за малым — закрыть окошко, когда пользователь закончит с ним работать:
//close pop-up box
function closePopup()
{
  $('#opaco').toggleClass('hidden').removeAttr('style');
  $('#popup').toggleClass('hidden');
  return false;
}


* This source code was highlighted with Source Code Highlighter.
Вначале мы добавляем класс 'hidden' на оба блока, скрывая их. Дополнительно мы еще должны убрать атрибут style у блока с id=«opaco», т.к. методы fadeTo и height, которые мы использовали ранее, реализованы через добавление именно этого атрибута элементу.

Про CSS — стоит отметить, что на блок '#opaco' мы навесили z-index: 10, чтобы он покрыл все остальные элементы. А поверх '#opaco' у нас останется popup-окно, которому мы присвоили z-index: 11.

Надеюсь, кому-то будет полезно.

UPD перенес в Блог jQuery.

UPD2 по предложению Auru сделал указание на popup независимым методом jQuery, все тот же пример можно посмотреть здесь.

Для этого добавил метод togglePopup():
  $.fn.togglePopup = function(){
   //detect whether popup is visible or not
   if($('#popup').hasClass('hidden'))
   {
    //hidden - then display
    //when IE - fade immediately
    if($.browser.msie)
    {
     $('#opaco').height($(document).height()).toggleClass('hidden');
    }
    else
    //in all the rest browsers - fade slowly
    {
     $('#opaco').height($(document).height()).toggleClass('hidden').fadeTo('slow', 0.7);
    }

    $('#popup')
     .html($(this).html())
     .alignCenter()
     .toggleClass('hidden');
   }
   else
   {
    //visible - then hide
    $('#opaco').toggleClass('hidden').removeAttr('style');
    $('#popup').toggleClass('hidden');
   }
  };


* This source code was highlighted with Source Code Highlighter.

то есть по сути перенес в этот метод функции showPopup и closePopup.

Вызывать это окошко можно указав имя того блока, который хотим отобразить и этот метод, например:
<a href="#" onCLick="$('#popup_bug').togglePopup(); return false;">Сообщите об ошибке на сайте!</a>

* This source code was highlighted with Source Code Highlighter.
по клику на ссылку откроет popup.

А в самом высплывающем окошке, мы навесим точно такое же действие на кнопку закрытия, только в этом случае, popup закроется:
<input type="button" value="Отмена" onclick="$('#popup_bug').togglePopup(); return false;" />

* This source code was highlighted with Source Code Highlighter.


UPD3 согласно совету dshster переделал немного расчет координат, чтобы блок центрировался по центру, при изменении размера окна браузера. Пример можно посмотреть здесь.

Для этого в CSS свойствах '#popup' добавляем:

left:50%;
top:50%;

А в методе alignCenter() считаем отрицательный margin как половину от ширины блока на момент открытия:
  $.fn.alignCenter = function() {
   //get margin left
   var marginLeft = - $(this).width()/2 + 'px';
   //get margin top
   var marginTop = - $(this).height()/2 + 'px';
   //return updated element
   return $(this).css({'margin-left':marginLeft, 'margin-top':marginTop});
  };


* This source code was highlighted with Source Code Highlighter.


UPD4 была пара комментариев, что по-хорошему при клике на темный фон — нужно закрывать окно. Согласен, было бы удобно. Работает здесь.

Все, что нам нужно для этого — это при отображении окошка навесить метод togglePopup по событию click на блок '#opaco', а в момент закрытия окошка — отвязать это действие.

Очень помогает возможность привязывать обработчики цепочкой — чтобы лишний раз не искать нужный DOM объект. Добавляем событие onclick:
    //when IE - fade immediately
    if($.browser.msie)
    {
     $('#opaco').height($(document).height()).toggleClass('hidden')
          .click(function(){$(this).togglePopup();});
    }
    else
    //in all the rest browsers - fade slowly
    {
     $('#opaco').height($(document).height()).toggleClass('hidden').fadeTo('slow', 0.7)
          .click(function(){$(this).togglePopup();});
    }


* This source code was highlighted with Source Code Highlighter.

а при закрытии — отвязываем:
    $('#opaco').toggleClass('hidden').removeAttr('style').unbind('click');

* This source code was highlighted with Source Code Highlighter.
Tags:
Hubs:
+43
Comments 71
Comments Comments 71

Articles