Xiper

Нестандартные radio

Автор: Александр Головко Дата публикации:

Задача

Стильно оформить элемент формы input type="radio".

Этот переключатель, как и чекбокс - один из самых «вредных» контроллов. Вот так он выглядит в разных браузерах по-умолчанию:

радиобатон в ff радиобатон в opera радиобатон в ie радиобатон в safari
ff opera ie safari

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

цветной радиобатон в ff цветной радиобатон в opera цветной радиобатон в opera
ff и safari игнорируют
свойство background
opera справилась
с заливкой
ie пытается красить,
но как всегда делает это по-своему

Перефразируя известную поговорку, можно сказать, что «проблемы верстальщиков дизайнера не волнуют». Радиобатон в дизайне может выглядеть, например, так:

примеры стилизированного радиобатона

Попробуем этого добиться.

При внедрении красивого radio будем придерживаться следующих требований:

  • точное соответствие дизайну
  • функциональное соответствие нового radio стандартному с точки зрения программиста (значения передаются в том же виде, группы радиобатонов связанны по атрибуту name)
  • при загрузке страницы вид radio устанавливается в зависимости от значения
  • простота реализации
  • минимум дополнительного кода в html
  • минимальный вес скрипта
  • кроссбраузерность
  • соответствие стандартам

Решение

Задача решается в четыре шага:

  1. оборачиваем обычный input type="radio" в контейнер
  2. задаем оформление этому контейнеру
  3. скрываем настоящий input
  4. с помощью javascript делаем нестандартный radio рабочим

В качестве контейнера будем использовать <span> — нейтральный строчный элемент. Строчный, а если точнее inline-block, нам нужен для того чтоб можно было задать размеры элементу (width / height) и при этом он вел себя как обычный radio (находится на одном уровне с другими полями формы и текстом). Поручим эту работу скрипту.

Подготовим картинки для двух состояний радиобатона. Тут можно воспользоваться техникой спрайтов — составим одну склеенную картинку:

подготвленный спрайт для нестандартного radio

Описываем стили для нового radio. Настоящее radio прячем отрицательным отступом (для того чтобы поле могло получать фокус и изменять значение по клику на label)

.niceRadio {
	width: 16px;
	height: 16px;
	display: inline-block;
	cursor: pointer;
	background: url(paht-to/radio.png);
	overflow: hidden;
}
.radioChecked {
	background-position: 0 -16px;
}
.niceRadio input {
	margin-left: -17px;
}
		

В форме обычным radio, которым хотим изменить внешний вид добавляем class="niceRadio"

<div><input type="radio" class="niceRadio" name="myradio" id="myradio1" tabindex="1" checked="checked"/> <label for="myradio1">первый</label></div>
<div><input type="radio" class="niceRadio" name="myradio" id="myradio2" tabindex="2" /> <label for="myradio2">второй</label></div>
<div><input type="radio" class="niceRadio" name="myradio" id="myradio3" tabindex="3" /> <label for="myradio3">третий</label></div>
Скрипт на jQuery

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

<script type="text/javascript" src="js/jquery.js"></script>
<script type="text/javascript" src="js/jquery.radio.js"></script>

где содержимое jquery.radio.js это:

jQuery(document).ready(function(){
jQuery(".niceRadio").each(
/* при загрузке страницы меняем обычные на стильные radio */
function() {
     changeRadioStart(jQuery(this));
});
});
function changeRadio(el)
/* 
	функция смены вида и значения radio при клике на контейнер
*/
{
	var el = el,
		input = el.find("input").eq(0);
	var nm=input.attr("name");
	jQuery(".niceRadio input").each(
	function() {
		if(jQuery(this).attr("name")==nm)
		{
			jQuery(this).parent().removeClass("radioChecked");
		}
	});					  
	if(el.attr("class").indexOf("niceRadioDisabled")==-1)
	{	
		el.addClass("radioChecked");
		input.attr("checked", true);
	}
    return true;
}
function changeVisualRadio(input)
{
/*
	меняем вид radio при смене значения
*/
	var wrapInput = input.parent();
	var nm=input.attr("name");
	jQuery(".niceRadio input").each(
	function() {
		if(jQuery(this).attr("name")==nm)
		{
			jQuery(this).parent().removeClass("radioChecked");
		}
	});
	if(input.attr("checked")) 
	{
		wrapInput.addClass("radioChecked");
	}
}
function changeRadioStart(el)
/* 
	новый контрол выглядит так <span class="niceRadio"><input type="radio" name="[name radio]" id="[id radio]" [checked="checked"] /></span>
	новый контрол получает теже name, id и другие атрибуты что и были у обычного
*/
{
try
{
var el = el,
	radioName = el.attr("name"),
	radioId = el.attr("id"),
	radioChecked = el.attr("checked"),
	radioDisabled = el.attr("disabled"),
	radioTab = el.attr("tabindex"),
	radioValue = el.attr("value");
	if(radioChecked)
		el.after("<span class='niceRadio radioChecked'>"+
			"<input type='radio'"+
			"name='"+radioName+"'"+
			"id='"+radioId+"'"+
			"checked='"+radioChecked+"'"+
			"tabindex='"+radioTab+"'"+
			"value='"+radioValue+"' /></span>");
	else
		el.after("<span class='niceRadio'>"+
			"<input type='radio'"+
			"name='"+radioName+"'"+
			"id='"+radioId+"'"+
			"tabindex='"+radioTab+"'"+
			"value='"+radioValue+"' /></span>");
	/* если контрол disabled - добавляем соответсвующий класс для нужного вида и добавляем атрибут disabled для вложенного radio */		
	if(radioDisabled)
	{
		el.next().addClass("niceRadioDisabled");
		el.next().find("input").eq(0).attr("disabled","disabled");
	}
	/* цепляем обработчики стилизированным radio */		
	el.next().bind("mousedown", function(e) { changeRadio(jQuery(this)) });
	if(jQuery.browser.msie)	el.next().find("input").eq(0).bind("click", function(e) { changeVisualRadio(jQuery(this)) });	
	else el.next().find("input").eq(0).bind("change", function(e) { changeVisualRadio(jQuery(this)) });
	el.remove();
}
catch(e)
{
	// если ошибка, ничего не делаем
}
    return true;
}

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

Динамическое добавление radio

update: Алгоритм:

  • добавляется radio с классом niceRadio
  • вызывается функция changeRadioStart, параметром которой является ссылка на добавленное radio
/* 
	динамическое добавление radio
*/
jQuery("#addRadio").click(
function() {
	jQuery("#testForm").append("
"); var el = jQuery("input.niceRadio"); changeRadioStart(el); });

Демо пример.

update by Ksayri плагин может не работать в IE6, если в коде скрипта оставить комментарии.

По теме