Делаем плагин модальных окон на jQuery и CSS3

9 Февраль 2012

Ох, я так давно ничего не писал в блог, не так ли. Вот собственно решил исправить ситуацию новым но очень поздним постом. Сегодня расскажу про создание плагина модальных окон на jQuery. Плагин не сверхъестествен, просто отображение любого рода HTML кода в модальном окне.

Шаг первый. Вертска

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

<div id="jm-fader"></div>
<div id="jm-container">
	<a href="#" class="jm-close"></a>
	<div class="jm-header">Some title</div>
	<div class="jm-content">Lorem ipsum!</div>
</div>

Этот код вы можете разместить у себя на сайте в конце или в начале элемента BODY, разницы нет.

Шаг второй. Стили

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

#jm-fader { 
	background: #888; 
	display: none;
	position: absolute; top: 0; left: 0; right: 0; bottom: 0; z-index: 100;
}

#jm-container { 
	background-color: #000;
	padding: 10px;
	width: 400px;
	font-family: Ubuntu, Tahoma, Arial; 
	
	display: none; overflow: hidden;
	position: absolute; top: 0; left: -1000px; z-index: 150;
	
	-webkit-border-radius: 5px;
	-moz-border-radius: 5px;
	-o-border-radius: 5px;
	border-radius: 3px;
	
	-webkit-box-shadow: 0px 0px 15px #333;
	-moz-box-shadow: 0px 0px 15px #333;
	-o-box-shadow: 0px 0px 15px #333;
	box-shadow: 0px 0px 15px #333;
}

div.jm-header { 
	font-size: 15px;
	color: #fff; 
	margin: 0px 5px 10px;
}

div.jm-content { 
	background-color: #fff;
	font-size: 13px;
	color: #454545;
	padding: 10px;
	
	-webkit-border-radius: 3px;
	-moz-border-radius: 3px;
	-o-border-radius: 3px;
	border-radius: 3px;
}

a.jm-close {
	background: url('../images/jm-close.png') center no-repeat;
	width: 15px; height: 15px;
	display: block; float: right;
	margin: 2px 3px 0;
	
	-webkit-border-radius: 3px;
	-moz-border-radius: 3px;
	-o-border-radius: 3px;
	border-radius: 3px;
	
	-webkit-opacity: .2;
	-moz-opacity: .2;
	-o-opacity: .2;
	opacity: .2;
}

#jm-container:hover a.jm-close {
	-webkit-opacity: 1;
	-moz-opacity: 1;
	-o-opacity: 1;
	opacity: 1;
}

Вот такой вот CSS получился в итоге, конечно же из-за CSS3 красивостей код потолстел в два раза, что не может не огорчать, увы! Но не будем об этом, нам ведь главное чтобы все было красиво :)

Шаг третий. jQuery плагин

Что нам необходимо от небольшого плагина для показа модальных окон? Раз он не большой то нам достаточно лишь показывать его и дать возможность закрывать, для полезности добавим еще колбек-функции на открытие и закрытие. И для удобности сделаем возможность закрывать окно по клавише Escape, а не только по клику на крестик. Я думаю можно добавить еще эффект появления окна из-за границы экрана при откртыии и наоборот. Ну приступим:

(function($) {
	$.jModal = function(header, content, options) {
		// устанавливаем настройки и смерживаем их с дефолтными
		options = $.extend({
			width: '400px'
		}, options);

		// находим все необходимые элементы
		var fader = $('#jm-fader');
		var container = $('#jm-container').css('width', options.width);
	
		var headerContainer = $('#jm-container > .jm-header');
		var contentContainer = $('#jm-container > .jm-content');
		var closeButton = $('#jm-container > .jm-close');
	
		// проверяем оверлей и показываем его
		if (fader.length) {
			fader.css({
				opacity: .35,
				height: $(document).height()
			}).show();
		} else {
			if (console && console.error) {
				console.error('[jModal] #jm-fader контейнер не найден.');	
			}
			return false;
		}
	
		// проверяем все ли части модального окна есть
		if (!container.length && !headerContainer.length && !contentContainer.length && !closeButton.length) {
			if (console && console.log) {
				console.error('[jModal] Нехватает некоторых контейнеров модального окна.');
			}
			return false;
		}
	
		// настраиваем модальное окно
		headerContainer.text(header);
		contentContainer.html(content);
	
		// центрируем и показываем модальное окно
		container.show().css({
			top: (parseInt($(window).height()) / 2) - (parseInt(container.height()) / 2)
		}).animate({left: (parseInt($(document).width()) / 2) - (parseInt(options.width) / 2)}, 350, function () {
			// если есть коллбек на открытие, выполняем его
			if (typeof options.open != 'undefined') {
				options.open.call(container);
			}
		});
	
		// вешаем закрытие окна на кнопку закрыть
		closeButton.one('click', function() {
			container.animate({left: '-1000px'}, 350, function() {
				this.style.display = 'none';
				fader.hide();

				// если есть колбек на закрытие, то выполняем
				if (typeof options.close != 'undefined') {
					options.close.call(container);
				}
			});
		});
	
		// и клавишу Escape
		$(document).one('keydown', function(e) {
			if (e.keyCode == 27) {
				container.animate({left: '-1000px'}, 350, function() {
					this.style.display = 'none';
					fader.hide();

					// если есть колбек на закрытие, то выполняем		
					if (typeof options.close != 'undefined') {
						options.close.call(container);
					}
				});
			}
		});
	
		// если пользователь скроллит, тогда перемещаем окно
		$(window).scroll(function() {
			container.stop(true, false).animate({top: window.scrollY + (parseInt($(window).height()) / 2) - (parseInt(container.height()) / 2)}, 500);
		});
	
		return true;
	}
})(jQuery);

Ухтышка! У нас получилось! Надеюсь комментариев в коде предостаточно для понимания алгоритма и сти работы скрипта. Если нет, тогда жду вопросы в комментариях :)

Шаг четвертый. Запускаем

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

<!DOCTYPE html>
<html>
<head>
	<meta charset="utf-8" />
	<title>jModal</title>
	
	<link href="css/base.css" rel="stylesheet" />
	<link href="css/jmodal.css" rel="stylesheet" />
	
	<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
	<script type="text/javascript" src="js/jmodal.js"></script>
	<script type="text/javascript">
	$(window).ready(function() {
		$('#show-jm-first').click(function() {
			$.jModal('Обычное сообщение', 'Это просто красивое модальное окошко, ничего больше. Используется для уведомления пользователя о каких либо действиях.');
		});
		$('#show-jm-second').click(function() {
			$.jModal('Сообщение с коллбеками', 'На окна можно вешать коллбек, на открытие и на закрытие.', {
				open: function(container) { 
					$('#show-jm-log').text('Модальное окно открылось!');
				},
				close: function(container) { 
					$('#show-jm-log').text('Модальное окно закрылось :)');
				}
			});
		});
	});
	</script>
</head>
<body>
	<div id="wrap">
		<a href="#" id="show-jm-first" class="jm-show">Показать обычное модальное окно</a>
		<a href="#" id="show-jm-second" class="jm-show">С коллбеками на клик и закрытие</a>
		<br />
		<div id="show-jm-log" style="text-align: center; color: #666;"></div>
	</div>
	
	<div id="jm-fader"></div>
	<div id="jm-container">
		<a href="#" class="jm-close"></a>
		<div class="jm-header">Some title</div>
		<div class="jm-content">Lorem ipsum!</div>
	</div>
</body>
</html>

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

$.jModal('Обычное модальное окно', 'Содержимое модального окна.');

Вариант второй, указываем ширину и колбеки:

$('#show-jm-second').click(function() {
	$.jModal('Сообщение с коллбеками', 'На окна можно вешать коллбек, на открытие и на закрытие.', {
		width: 600,
		open: function(container) { 
			alert('Модальное окно открылось!');
		},
		close: function(container) { 
			alert('Модальное окно закрылось :)');
		}
	});
});

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

Ну вот и все, на этом можно поставить точку и надеяться, что разъяснил как можно проще и доступней, ведь в первую очередь этот пост нацелен на аудиторию новичков в jQuery :)

Комментарии к записи

  • 20 Май 2012

    отличный плагин!!, У меня вот такой немного отходящий вопрос от темы, где взять вот такой вот задний фон как у вас.. я его много где встречаю в многих цветовых гамах. Возможно есть какой то генератор? Не поделитесь ссылочкой:))

  • Simba
    27 Май 2012

    Случаем, не знаете, на просторах инета существует подобная замечательная вещь, но только кроссбраузерная?

    • 30 Май 2012

      Эта тоже кроссбраузерная :)

  • Павел
    30 Май 2012

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

    • 30 Май 2012

      Хм, не замечаю, вроде нормально. Можете по подробнее описать проблему?

  • 31 Май 2012

    Аналогичная проблема, после прокрутки не показывается! Кто поможет решить проблему?

    • 31 Май 2012

      Можно подробные шаги, при разных прокрутках (и до и после) у меня нормальный полет.

  • Павел
    3 Июнь 2012

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

  • 10 Июль 2012

    Я думаю нужно просто поменять стиль #jm-container {position:absolute} на #jm-container{position:fixed}
    =)

  • 11 Июль 2012

    У меня точно такая же проблема как у #Павел и #Bumaga!
    И еще… Высоту он автоматически определяет и ставится по центру, нужно сделать точно так же и в длину!
    top: (parseInt($(window).height()) / 2) — (parseInt(container.height()) / 2)
    left: (parseInt($(document).width()) / 2) — (parseInt(options.width) / 2)}, 350

    • 19 Июль 2012

      Он и определяет координаты горизонтального центрирования!

  • 11 Июль 2012

    Даже у вас демо нажмите Ctrl + Scroll UP а потом покрутите вниз и нажмите на кнопку и увидите!

    • 19 Июль 2012

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

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

  • 16 Июль 2012

    А как можно сделать модалку анологичную, как у вк с чатом…?

    • 16 Июль 2012

      PHP+JS в руки и вперед :)

  • 18 Июль 2012

    с php то понятно, а вот с js не дружу пока что =(

    • 18 Июль 2012

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

  • Света
    11 Октябрь 2012

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

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