Улучшаем элемент select

:

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

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

 

HTML

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

!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Улучшаем элемент Select с помощью jQuery и CSS3 | Демонстрация для сайта RUSELLER.COM</title>

<link rel="stylesheet" type="text/css" href="css/styles.css" />

</head>
<body>

<div id="page">
	<h1>Ваш продукт</h1>

	<form method="post" action="">
    
    	<!-- Мы собираемся использовать jQuery, чтобы скрыть элемент select и заменить его -->
        
		<select name="fancySelect" class="makeMeFancy">
        
        	<!-- Обратите внимание на атрибуты HTML5 данных -->
        
	        <option value="0" selected="selected" data-skip="1">Выберите продукт</option>
        	<option value="1" data-icon="img/products/js.png" data-html-text="JavaScript + jQuery для начинающих в видеоформате&lt;i&gt;посмотреть видеопрезентацию&lt;/i&gt;">JavaScript + jQuery для начинающих в видеоформате</option>
        	<option value="2" data-icon="img/products/php.png" data-html-text="PHP + MySQL для начинающих&lt;i&gt;купить&lt;/i&gt;">PHP + MySQL для начинающих</option>
            <option value="3" data-icon="img/products/wp.png" data-html-text="WordPress - профессиональный блог за один день&lt;i&gt;скачать&lt;/i&gt;">WordPress - профессиональный блог за один день</option>
            <option value="4" data-icon="img/products/joomla.png" data-html-text="Joomla - профессиональный сайт за один день&lt;i&gt;купить&lt;/i&gt;">Joomla - профессиональный сайт за один день</option>
        </select>
    </form>
    
</div>

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.3/jquery.min.js"></script>
<script src="js/script.js"></script>

</body>
</html>

Атрибуты data используются для объединения информации в элементах option. В них размещается иконка продукта и текстовое описание с форматированием. Оба данных пункта будут выводиться в улучшенной версии элемента select.

Произвольный атрибут data-skip в первом элементе сигнализирует нашему скрипту, что данный пункт не надо включать в генерируемый список. Вы можете просто проверить существование атрибутов data-icon и data-html-text и пропустить элемент, если нужно.

Внизу мы включаем библиотеку jQuery версии 1.4.3 (последней версии на момент написания урока) и наш скрипт script.js, который будет разбираться позже.

Улучшенный вариант элемента select

 

jQuery

При обработке события document.ready jQuery проверяет элемент select, и, используя атрибуты данных, строит разметку, которая добавляется сразу за элементом select:

<div style="width: 356px;" class="tzSelect">
	<div class="selectBox expanded">Выберите продукт</div>
	<ul class="dropDown">
		<li><img src="img/products/js.png"><span>JavaScript + jQuery для начинающих в видеоформате<i>посмотреть видеопрезентацию</i></span></li>
		<li><img src="img/products/php.png"><span>PHP + MySQL для начинающих<i>купить</i></span></li>
		<li><img src="img/products/wp.png"><span>WordPress - профессиональный блог за один день<i>скачать</i></span></li>
		<li><img src="img/products/joomla.png"><span>Joomla - профессиональный сайт за один день<i>купить</i></span></li>
	</ul>
</div>

Строится неупорядоченный список с элементами li, которые представляют каждый пункт option из элемента select. А сам элемент select будет представлен элементом div с классом .selectBox.

Теперь можно взглянуть на код JavaScript.

js/script.js

$(document).ready(function(){
	
	// Элемент select, который будет замещаться:
	var select = $('select.makeMeFancy');

	var selectBoxContainer = $('<div>',{
		width		: select.outerWidth(),
		className	: 'tzSelect',
		html		: '<div class="selectBox"></div>'
	});

	var dropDown = $('<ul>',{className:'dropDown'});
	var selectBox = selectBoxContainer.find('.selectBox');
	
	// Цикл по оригинальному элементу select
	
	select.find('option').each(function(i){
		var option = $(this);
		
		if(i==select.attr('selectedIndex')){
			selectBox.html(option.text());
		}
		
		// Так как используется jQuery 1.4.3, то мы можем получить доступ 
		// к атрибутам данных HTML5 с помощью метода data().
		
		if(option.data('skip')){
			return true;
		}
		
		// Создаем выпадающий пункт в соответствии
		// с иконкой данных и атрибутами HTML5 данных:
		
		var li = $('<li>',{
			html:	'<img src="'+option.data('icon')+'" /><span>'+
					option.data('html-text')+'</span>'
		});
				
		li.click(function(){
			
			selectBox.html(option.text());
			dropDown.trigger('hide');
			
			// Когда происходит событие click, мы также отражаем
			// изменения в оригинальном элементе select:
			select.val(option.val());
			
			return false;
		});
		
		dropDown.append(li);
	});
	
	selectBoxContainer.append(dropDown.hide());
	select.hide().after(selectBoxContainer);
	
	// Привязываем пользовательские события show и hide к элементу dropDown:
	
	dropDown.bind('show',function(){
		
		if(dropDown.is(':animated')){
			return false;
		}
		
		selectBox.addClass('expanded');
		dropDown.slideDown();
		
	}).bind('hide',function(){
		
		if(dropDown.is(':animated')){
			return false;
		}
		
		selectBox.removeClass('expanded');
		dropDown.slideUp();
		
	}).bind('toggle',function(){
		if(selectBox.hasClass('expanded')){
			dropDown.trigger('hide');
		}
		else dropDown.trigger('show');
	});
	
	selectBox.click(function(){
		dropDown.trigger('toggle');
		return false;
	});

	// Если нажать кнопку мыши где-нибудь на странице при открытом элементе dropDown,
	// он будет спрятан:
	
	$(document).click(function(){
		dropDown.trigger('hide');
	});
});

После загрузки страницы, скрипт сканирует опции элемента select и генерирует разметку, соответствующую атрибутам данных HTML5, которые содержатся в пунктах элемента select. Так как используется jQuery 1.4.3, то доступ к значениям в данных атрибутах возможен с помощью метода jQuery data(). Это действительно полезная опция, которая существенно облегчает доступ к привязанным данным.

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

Теперь наш код на месте и стоит взглянуть на код CSS3.

 

CSS

Мы использовали минимум разметки HTML для вывода элемента выбора и организации выпадающих пунктов. Если ограничивать проект использованием только предшествующих CSS3 технологий, то придется использовать значительно больше элементов div и span.

css/styles.css

#page{
	width:490px;
	margin:50px auto;
}

#page h1{
	font-weight:normal;
	text-indent:-99999px;
	overflow:hidden;
	background:url('../img/your_product.png') no-repeat;
	width:490px;
	height:36px;
}

#page form{
	margin:20px auto;
	width:460px;
}

.tzSelect{
	
	/* Контейнер для нового элемента select */
	
	height:34px;
	display:inline-block;
	min-width:460px;
	position:relative;
	
	/* Предварительная загрузка фонового изображения для выпадающих пунктов */
	background:url("../img/dropdown_slice.png") no-repeat -99999px;
}

.tzSelect .selectBox{
	position:absolute;
	
	height:100%;
	width:100%;
	
	/* Установка шрифта */
	
	font:13px/34px "Lucida Sans Unicode", "Lucida Grande", sans-serif;
	text-align:center;
	text-shadow:1px 1px 0 #EEEEEE;
	color:#666666;

	/* Использование множественных фонов CSS3 */
	
	background:url('../img/select_slice.png') repeat-x #ddd;
	background-image:url('../img/select_slice.png'),url('../img/select_slice.png'),url('../img/select_slice.png'),url('../img/select_slice.png');
	background-position:0 -136px, right -204px, 50% -68px, 0 0;
	background-repeat: no-repeat, no-repeat, no-repeat, repeat-x;
	
	cursor:pointer;
	
	-moz-border-radius:3px;
	-webkit-border-radius:3px;
	border-radius:3px;
}

.tzSelect .selectBox:hover,
.tzSelect .selectBox.expanded{
	background-position:0 -170px, right -238px, 50% -102px, 0 -34px;
	color:#2c5667;
	text-shadow:1px 1px 0 #9bc2d0;
}

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

Фоновое изображение из частей

В настоящий момент множественные фоновые изображения поддерживаются в Firefox, Safari, Chrome и Opera. Для Internet Explorer и старых версий браузеров, определяется обходной вариант, который просто выводит обычный фон. При разборе документа CSS браузер, который не понимает инструкции для множественных фоновых изображений, просто игнорирует их и использует обычный вариант.

.tzSelect .dropDown{
	position:absolute;
	top:40px;
	left:0;
	width:100%;
	border:1px solid #32333b;
	border-width:0 1px 1px;
	list-style:none;
	
	-moz-box-sizing:border-box;
	-webkit-box-sizing:border-box;
	box-sizing:border-box;
	
	-moz-box-shadow:0 0 4px #111;
	-webkit-box-shadow:0 0 4px #111;
	box-shadow:0 0 4px #111;
}


.tzSelect li{
	height:85px;
	cursor:pointer;
	position:relative;
	
	/* Использование множественных фонов CSS3 */
	
	background:url('../img/dropdown_slice.png') repeat-x #222;
	background-image:url('../img/dropdown_slice.png'),url('../img/dropdown_slice.png'),url('../img/dropdown_slice.png');
	background-position: 50% -171px, 0 -85px, 0 0;
	background-repeat: no-repeat, no-repeat, repeat-x;
}

.tzSelect li:hover{
	background-position: 50% -256px, 0 -85px, 0 0;
}

.tzSelect li span{
	left:88px;
	position:absolute;
	top:27px;
}

.tzSelect li i{
	color:#999999;
	display:block;
	font-size:12px;
}

.tzSelect li img{
	left:9px;
	position:absolute;
	top:13px;
}

Свойство box-sizing, которое используется в классе .dropDown, определяет, как рамочка добавляется к общему размеру элемента. Обычно рамочка увеличивает общую ширину элемента на 2px и рушит все выравнивание. Присвоив свойству box-sizing значение border-box, мы предотвращаем увеличение общей ширины, так как рамочка будет размещаться внутри элемента.

Готово!

 

Заключение

В данном уроке продемонстрированы некоторые особенности jQuery 1.4.3 и CSS3. Разработанный скрипт сохраняет оригинальный элемент  select на странице и изменяет его в соответствии с действиями пользователя. Таким образом, форма содержит правильные значения, которые могут быть корректно обработаны другими частями проекта.