Вкладки и кнопка Back

Автор: Евгений Рыжков и Андрей Косяк Дата публикации: 21.11.2011

Задача

Сделать так чтобы пользователь имел возможность открыть страницу сразу с открытой нужной вкладкой. Так же чтобы при навигации по вкладкам< работала кнопка «Back» в браузере.

пример вкладок на сайте

Решение

В этом нам помогут Javascript событие hashchange и CSS3 псевдокласс :target (для красоты решения). Использование :target мы уже как-то рассматривали и в данном материале повторяться не будем.

Событие hashchange происходит при изменении URL, когда новый отличается от предыдущего только фрагментом идентификатора (часть URL, которая идет после знака # и называется хеш (hash)).

Как применять на практике продемонстрирует простой пример: сделаем блок, состоящий из трех вкладок:

<dl id="tabs">
	<dt><a href="#menu">Меню</a></dt>
	<dd id="menu"><div>Содержимое вкладки меню</div></dd>
	<dt><a href="#info">Инфо</a></dt>
	<dd id="info"><div>Содержимое вкладки инфо</div></dd>
	<dt><a href="#photo">Фото</a></dt>
	<dd id="photo"><div>Содержимое вкладки фото</div></dd>
</dl>

Замечу ,что <div> используется в декоративных целях.

В CSS тоже в целом ничего особенного и нового:

#tabs dt {
	float: left;
	line-height: 25px;
	margin: 0 2px 0 0;
	background: #ff8600;
	border: 1px solid #e47200;
	border-bottom: none;
	color: #f4ece1;
	-moz-border-radius: 8px 8px 0 0;
	-webkit-border-radius: 8px 8px 0 0;
	border-radius: 8px 8px 0 0;
	cursor: pointer;
	position: relative;
}
#tabs dt:first-child {
	margin-left: 10px;
}

#tabs dt a {
	display: block;
	height: 24px;
	color: #fff;
	text-decoration: none;
	padding: 0 22px;	
}
#tabs dt.active {
	background: #77b001;
	border: 1px solid #679200;	
	cursor: default;
}

	#tabs dt a:hover {
		text-decoration: underline;
	}
#tabs dt.active a { /* вид активной вкладки */
	cursor: default;
	text-decoration: none !important;
}

#tabs dd {
	width: 100%;
	display: none; /* все вкладки по умолчанию не видимы */
	float: right;
	margin: 0 0 0 -100%;
	padding-top: 25px;
}
#tabs dd.target,
#tabs dd:target { 
	display: block; /* вкладка получившая target становится видимой */
}

К этому добавляем небольшой JS:

jQuery(document).ready(function(){
		var	tabs = ["#menu", "#info", "#photo"], // создаем массив id вкладок для удобства проверок
			tabList = jQuery("#tabs"),
			ltie9 = jQuery.browser.msie && (jQuery.browser.version <= 9);
			 /*
				 ltie9 будет true если используется IE8 или ниже
				 IE9 сюда попал из-за того что при нажатии на Back предыдущая вкладка не скрывалась
			*/
			
			// смена таба
			function changeTab(tabId){
				if (!tabId) window.location.hash = tabs[0]; // если не указана вкладка показываем первую
				tabList.find(".active").removeClass("active"); 
				jQuery(tabId).prev().addClass("active"); // активной вкладке добавляем класс чтобы придать нужный вид
				
				/* 
					определив id вкладки можно выполнить какие-то дополнительные действия,
					например, выполнить ajax запрос
				*/
				switch (tabId)
				{
					case tabs[1]: 	jQuery("#info div").append("<p>динамически добавленный код</p>quot;);
									break;
					default: 		break;
				};
				
			}
		
			// проверка хеша
			function checkHash(){
				
				var	tabId = window.location.hash,
					result = false;
					
				// для ИЕ6-8 эмуляция :target
				function setTarget(obj){
					jQuery("#tabs dd").removeClass("target");
					jQuery(tabId).addClass("target");
				};
				
				// при загрузке страницы проверяем какую вкладку следует открыть	
				jQuery.each(tabs, function(){
					if (tabId == this) 
					{
						changeTab(tabId);
						result = true;
						ltie9 ? setTarget(tabId) : false;

						return false;
					};
				});

				if (result == false) changeTab();
			};
			// проверка хеша при загрузке
			checkHash();			
						
			// отслеживаем изменение хеша
			jQuery(window).bind("hashchange", function() {
				checkHash();
			});
			
});

Демо пример. Проверено:

  • IE 8-9
  • Opera 11.11
  • Firefox 8
  • Safari 5
  • Chrome

Следует отметить что событие hashchange многими браузерами поддерживается достаточно давно: IE8, FF 3.6, Opera 10.6 уже поддерживали данное событие. Если же требуется поддержка более старых браузеров, можно воспользоваться jQuery плагином от Ben Alman.

Материалы