SiteIS

jQuery - безграничные возможности в дизайне Вашего сайта!

- Один из самых популярных на сегодня среди веб разработчиков фреймворк

- Позволяет быстро и легко создать потрясающие веб-приложения

- Удивительно красивые анимационные эффекты

- Улучшение пользовательского интерфейса

Стилизация select, checkbox и radio

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

HTML разметка не требует никаких дополнительных оберток. Все необходимое добавляет скрипт.

<form class="select_form">
	<div class="form_line">
		<select>
			<option>Пункт 1</option>
			<option>Пункт 2</option>
			<option>Пункт 3</option>
			<option>Пункт 4</option>
		</select>
	</div>
	<div class="form_line">
		<select>
			<option>Пункт 1</option>
			<option>Пункт 2</option>
			<option>Пункт 3</option>
			<option>Пункт 4</option>
		</select>
	</div>				
	<div class="form_line">
		<input type="checkbox" class="check" name="check_1" />
		<label>Чекбокс 1</label>
		<input type="checkbox" class="check" name="check_2" />
		<label>Чекбокс 2</label>					
	</div>	
	<div class="form_line">
		<input type="radio" class="radio" name="radio_1" />
		<label>Радио кнопка 1</label>
		<input type="radio" class="radio" name="radio_1" />
		<label>Радио кнопка 2</label>					
	</div>				
</form>

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

$(function(){
	initCustomForms();
});

// custom forms init
function initCustomForms() {
	$('select').customSelect();
	$('input:radio').customRadio();
	$('input:checkbox').customCheckbox();
}

// custom forms plugin
;(function(jQuery){
	// custom checkboxes module
	jQuery.fn.customCheckbox = function(_options){
		var _options = jQuery.extend({
			checkboxStructure: '<div></div>',
			checkboxDisabled: 'disabled',
			checkboxDefault: 'checkboxArea',
			checkboxChecked: 'checkboxAreaChecked',
			filterClass:'default'
		}, _options);
		return this.each(function(){
			var checkbox = jQuery(this);
			if(!checkbox.hasClass('outtaHere') && checkbox.is(':checkbox') && !checkbox.hasClass(_options.filterClass)){
				var replaced = jQuery(_options.checkboxStructure);
				this._replaced = replaced;
				if(checkbox.is(':disabled')) replaced.addClass(_options.checkboxDisabled);
				else if(checkbox.is(':checked')) replaced.addClass(_options.checkboxChecked);
				else replaced.addClass(_options.checkboxDefault);

				replaced.click(function(){
					if(checkbox.is(':checked')) checkbox.removeAttr('checked');
					else checkbox.attr('checked', 'checked');
					changeCheckbox(checkbox);
				});
				checkbox.click(function(){
                    changeCheckbox(checkbox);
                    if(!checkbox.is(':checked')) checkbox.removeAttr('checked');
					else checkbox.attr('checked', 'checked');
				});
				checkbox.click(function(){
					changeCheckbox(checkbox);
				});
				replaced.insertBefore(checkbox);
				checkbox.addClass('outtaHere');
			}
		});
		function changeCheckbox(_this){
			_this.change();
			if(_this.is(':checked')) _this.get(0)._replaced.removeClass().addClass(_options.checkboxChecked);
			else _this.get(0)._replaced.removeClass().addClass(_options.checkboxDefault);
		}
	}

	// custom radios module
	jQuery.fn.customRadio = function(_options){
		var _options = jQuery.extend({
			radioStructure: '<div></div>',
			radioDisabled: 'disabled',
			radioDefault: 'radioArea',
			radioChecked: 'radioAreaChecked',
			filterClass:'default'
		}, _options);
		return this.each(function(){
			var radio = jQuery(this);
			if(!radio.hasClass('outtaHere') && radio.is(':radio') && !radio.hasClass(_options.filterClass)){
				var replaced = jQuery(_options.radioStructure);
				this._replaced = replaced;
				if(radio.is(':disabled')) replaced.addClass(_options.radioDisabled);
				else if(radio.is(':checked')) replaced.addClass(_options.radioChecked);
				else replaced.addClass(_options.radioDefault);
				replaced.click(function(){
					if(jQuery(this).hasClass(_options.radioDefault)){
						radio.attr('checked', 'checked');
						changeRadio(radio.get(0));
					}
				});
				radio.click(function(){
					if(!jQuery(this).hasClass(_options.radioDefault)){
						radio.attr('checked', 'checked');
						changeRadio(radio.get(0));
					}
				});
				radio.click(function(){
					changeRadio(this);
				});
				replaced.insertBefore(radio);
				radio.addClass('outtaHere');
			}
		});
		function changeRadio(_this){
			jQuery(_this).change();
			jQuery('input:radio[name='+jQuery(_this).attr("name")+']').not(_this).each(function(){
				if(this._replaced && !jQuery(this).is(':disabled')) this._replaced.removeClass().addClass(_options.radioDefault);
                $(this).removeAttr('checked');
			});
			_this._replaced.removeClass().addClass(_options.radioChecked);
		}
	}

	// custom selects module
	jQuery.fn.customSelect = function(_options) {
		var _options = jQuery.extend({
			selectStructure: '<div class="selectArea"><span class="left"></span><span class="center"></span><a href="#" class="selectButton"></a><div class="disabled"></div></div>',
			hideOnMouseOut: false,
			copyClass: true,
			selectText: '.center',
			selectBtn: '.selectButton',
			selectDisabled: '.disabled',
			optStructure: '<div class="optionsDivVisible"><div class="select-center"><ul></ul></div></div>',
			optList: 'ul',
			filterClass:'default'
		}, _options);
		return this.each(function() {
			var select = jQuery(this);
			if(!select.hasClass('outtaHere') && !select.hasClass(_options.filterClass)) {
				if(select.is(':visible')) {
					var hideOnMouseOut = _options.hideOnMouseOut;
					var copyClass = _options.copyClass;
					var replaced = jQuery(_options.selectStructure);
					var selectText = replaced.find(_options.selectText);
					var selectBtn = replaced.find(_options.selectBtn);
					var selectDisabled = replaced.find(_options.selectDisabled).hide();
					var optHolder = jQuery(_options.optStructure);
					var optList = optHolder.find(_options.optList);
					if(copyClass) optHolder.addClass('drop-'+select.attr('class'));

					if(select.attr('disabled')) selectDisabled.show();
					select.find('option').each(function(){
						var selOpt = jQuery(this);
						var _opt = jQuery('<li><a href="#">' + selOpt.html() + '</a></li>');
						if(selOpt.attr('selected')) {
							selectText.html(selOpt.html());
							_opt.addClass('selected');
						}
						_opt.children('a').click(function() {
							optList.find('li').removeClass('selected');
							select.find('option').removeAttr('selected');
							jQuery(this).parent().addClass('selected');
							selOpt.attr('selected', 'selected');
							selectText.html(selOpt.html());
							select.change();
							optHolder.hide();
							return false;
						});
						optList.append(_opt);
					});
					replaced.width(select.outerWidth());
					replaced.insertBefore(select);
					optHolder.css({
						width: select.outerWidth(),
						display: 'none',
						position: 'absolute'
					});
					jQuery(document.body).append(optHolder);

					var optTimer;
					replaced.hover(function() {
						if(optTimer) clearTimeout(optTimer);
					}, function() {
						if(hideOnMouseOut) {
							optTimer = setTimeout(function() {
								optHolder.hide();
							}, 200);
						}
					});
					optHolder.hover(function(){
						if(optTimer) clearTimeout(optTimer);
					}, function() {
						if(hideOnMouseOut) {
							optTimer = setTimeout(function() {
								optHolder.hide();
							}, 200);
						}
					});
					selectBtn.click(function() {
						if(optHolder.is(':visible')) {
							optHolder.hide();
						}
						else{
							if(_activeDrop) _activeDrop.hide();
							optHolder.find('ul').css({height:'auto', overflow:'hidden'});
							optHolder.css({
								top: replaced.offset().top + replaced.outerHeight(),
								left: replaced.offset().left,
								display: 'block'
							});
							//if(optHolder.find('ul').height() > 200) optHolder.find('ul').css({height:200, overflow:'auto'});
							_activeDrop = optHolder;
						}
						return false;
					});
					replaced.addClass(select.attr('class'));
					select.addClass('outtaHere');
				}
			}
		});
	}

	// event handler on DOM ready
	var _activeDrop;
	jQuery(function(){
		jQuery('body').click(hideOptionsClick)
		jQuery(window).resize(hideOptions)
	});
	function hideOptions() {
		if(_activeDrop && _activeDrop.length) {
			_activeDrop.hide();
			_activeDrop = null;
		}
	}
	function hideOptionsClick(e) {
		if(_activeDrop && _activeDrop.length) {
			var f = false;
			jQuery(e.target).parents().each(function(){
				if(this == _activeDrop) f=true;
			});
			if(!f) {
				_activeDrop.hide();
				_activeDrop = null;
			}
		}
	}
})(jQuery);

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

Самое время заняться подготовкой нужных изображений для select, radio и checkbox. Тут уж дизайнер может себя не сдерживать и творить, что ему фантазия навеет. Единственное условие - для radio и checkbox требуются картинки как для обычного, так и для активного состояния.

checkbox checkbox radio radio

Для уменьшения запросов к серверу, все фрагменты засунем в спрайт.

С select дело обстоит чуть сложнее. Если ширина у селектов фиксированная, то можно обойтись одной картинкой, но, как правило, на сайте частенько ширина этих элементов отличается и что бы не резать картинку для каждого такого случая, лучше сразу сделать select резиновым по ширине. В этом случае понадобится разрезать изображение на три части. Должно получиться примерно так:

select select select

Левую и правую части можем положить в спрайт, центральная часть будет тянуться по оси х на всю ширину select.

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

.select_form {
margin-top:30px;
}
.form_line {
margin:0 auto;
padding:0 0 10px 20px;
width:380px;
}
label {
padding:0 20px 0 10px;
width:110px;
display:inline-block;
line-height:12px;
}

/*all*/
.outtaHere {
position:absolute;
left:-3000px;
}
span.left, span.center, .selectArea a, .checkboxArea, .checkboxAreaChecked, .radioArea, .radioAreaChecked {
display:inline-block;
*display:inline;
zoom:1;
vertical-align:top;
}

/*select*/
.form_line select {
width:265px;
}
.selectArea {
margin:0 25px 0 10px;
position:relative;
background:url(select_center.png) repeat-x;
}
a.selectButton, span.left {
height:27px;
position:absolute;
top:0;
}
span.left {
width:10px;
left:-10px;
background:url(select_sprite.png) no-repeat 0 -27px;
}
span.center {
line-height:27px;
}
a.selectButton {
width:25px;
right:-25px;
background:url(select_sprite.png) no-repeat 0 0;
}

/*option*/
.optionsDivVisible {
margin-left:-5px;
}
.select-center {
padding:5px 5px;
background:#fff;
border:1px solid #ccc;
border-top:0;
}
.select-center a {
padding-left:10px;
line-height:18px;
color:#666;
text-decoration:none;
}
.select-center a:hover {
color:#333;
}
.radioArea, .radioAreaChecked, .checkboxArea, .checkboxAreaChecked {
margin-top:4px;
width:15px;
}

/*checkbox*/
.checkboxArea, .checkboxAreaChecked {
height:14px;
}
.checkboxArea {
background:url(radio_sprite.png) no-repeat 0 -22px;
}
.checkboxAreaChecked {
background:url(radio_sprite.png) no-repeat 0 -36px;
}

/*radio*/
.radioArea, .radioAreaChecked {
height:11px;
}
.radioArea {
background:url(radio_sprite.png) no-repeat 0 0px;
}
.radioAreaChecked {
background:url(radio_sprite.png) no-repeat 0 -11px;
}

Скрипт оттестирован и успешно работает во всех браузерах настольных машин и мобильных устройств (в ИЕ6 не тестировался)

Автор: Super User

Комментарии  

 
+1 # uster 02.12.2012 16:33
отличный скрипт, действительно боевой и скорый, спасибо.,
с выпадающим списком (меню), он справляется на ура.., к сожалению мне не помогло :sad: , в моём случае к списку привязаны функции другого скрипта, и нужный список для вызова не выпадает.., но положим на заметку, явная выручалочка такая, пригодится...
Ответить | Ответить с цитатой | Цитировать
 
 
+1 # uster 02.12.2012 16:36
почему большинство форм комментариев не принимают первое сообщение :-? ?, обязательно попросит ещё раз ввести код на картинке :lol:
Ответить | Ответить с цитатой | Цитировать
 
 
-1 # Admin 02.12.2012 17:36
Цитирую uster:
почему большинство форм комментариев не принимают первое сообщение :-? ?, обязательно попросит ещё раз ввести код на картинке :lol:

Это явление пока неведомо мне так же, как и вам :lol: Пока принимаю его как неизбежное зло :roll:
Ответить | Ответить с цитатой | Цитировать
 
 
+3 # Владимир 26.04.2013 12:23
Скрипт с багой - невозможно использовать имена радио-инпутов вида radio_name[group].
Скрипт хочет оперировать только с "простыми" именами без символов [].
То есть какие-то более-менее сложные формы устанете делать.
Так что программисты при внедрении вашей волшебной вёрстки неоднократно расскажут вам куда идти, как это делал я тому доброму человеку, который внедрил данный кусок кода в проект.
Ответить | Ответить с цитатой | Цитировать
 
 
+2 # админ 28.04.2013 21:40
Благодарю, Владимир, за оставленный комментарий. Только у меня есть несколько возражений.
Скрипт не с багой, как вы выразились, а всего лишь выполняет более узкие функции, нежели вам бы хотелось (судя по вашим словам). Он всего навсего предназначен изменить вывод кастомных элементов в соответствии с фантазиями дизайнеров.
Так же скрипт не имеет отношения к верстке - тут вы маленько перепутали понятия...
Кидать апельсинами я бы посоветовал не в сторону js кода, а в сторону разработчиков, сделавших невозможным стилизацию элементов форм без танцев с бубном. Иначе бы не было бы таких проблем при решении подобных задач, которые, кстати, братья программисты без зазрения совести перекинули на плечи фронтенд разработчиков. :-)
Ответить | Ответить с цитатой | Цитировать
 
 
+2 # Мирослав 20.06.2013 17:32
Скрипт просто отличный! Громадную работу проделали. Единственный вопрос - как можно изменить код, чтобы в селекте была возможность использовать тэг optgroup?
Ответить | Ответить с цитатой | Цитировать
 
 
+2 # admin 20.06.2013 17:54
Спс за похвалу, вот только не я автор этого скрипта :-)

В этом скрипте без модификации, увы, использовать тэг optgroup не получится.
Ответить | Ответить с цитатой | Цитировать
 
 
+2 # Денис 21.07.2013 14:31
Огромное спасибо за скрипт, он действительно хорошо работает и легко поддается настройке. Но есть нюанс из-за которого я сказал, что скрипт работает хорошо, а не отлично. Нюанс заключается в том, что если использовать версию jQuery 1.10.2. (последнюю на текущий момент), то переключение классов при клике на чекбоксе работает не корректно - класс переключается только ОДИН раз.
Ответить | Ответить с цитатой | Цитировать
 
 
+3 # admin 22.07.2013 11:11
Да, Денис, есть такая проблема. В ближайшем будущем (как только дойдут руки) покумекаем над этой проблемой :-)
Ответить | Ответить с цитатой | Цитировать
 
 
+2 # Richard 27.07.2013 13:48
На IE7 в selecte не работает select_button, подскажите решение?
Ответить | Ответить с цитатой | Цитировать
 
 
+3 # Андрей 24.10.2013 16:00
Проблемам у скрипта при использовании AJAX, второй раз скрипт, без перезагрузки страницы отказывается применяться. Как можно решить эту проблему?
Ответить | Ответить с цитатой | Цитировать
 
 
+1 # Виталий 21.11.2013 00:31
а как же атрибут disabled,про него я так понял совсем забыли?
Ответить | Ответить с цитатой | Цитировать
 
 
+1 # Дмитрий 05.09.2014 11:50
Используя вот этот плагин "jQuery Migrate v1.2.1 | (c) 2005, 2013 jQuery Foundation" подключенный после библиотеки jQuery,удалось добиться корректной работы чекбоксов c jQuery 1.10.2 и выше.
Ответить | Ответить с цитатой | Цитировать