Нестандартные radio
Дата публикации: 28.01.2010
Задача
Стильно оформить элемент формы input type=»radio».
Этот переключатель, как и чекбокс — один из самых «вредных» контроллов. Вот так он выглядит в разных браузерах по-умолчанию:
![]() |
![]() |
![]() |
![]() |
| ff | opera | ie | safari |
Попытки изменить размер радиобатона приводят к увеличению кликабельной зоны, но сам кружок меняться не желает. На изменение, например, свойства background этот инпут реагирует в зависимости от браузера:
![]() |
![]() |
![]() |
| ff и safari игнорируют свойство background |
opera справилась с заливкой |
ie пытается красить, но как всегда делает это по-своему |
Перефразируя известную поговорку, можно сказать, что «проблемы верстальщиков дизайнера не волнуют». Радиобатон в дизайне может выглядеть, например, так:

Попробуем этого добиться.
При внедрении красивого radio будем придерживаться следующих требований:
- точное соответствие дизайну
- функциональное соответствие нового radio стандартному с точки зрения программиста (значения передаются в том же виде, группы радиобатонов связанны по атрибуту name)
- при загрузке страницы вид radio устанавливается в зависимости от значения
- простота реализации
- минимум дополнительного кода в html
- минимальный вес скрипта
- кроссбраузерность
- соответствие стандартам
Решение
Задача решается в четыре шага:
- оборачиваем обычный input type=»radio» в контейнер
- задаем оформление этому контейнеру
- скрываем настоящий input
- с помощью javascript делаем нестандартный radio рабочим
В качестве контейнера будем использовать <span> — нейтральный строчный элемент. Строчный, а если точнее inline-block, нам нужен для того чтоб можно было задать размеры элементу (width / height) и при этом он вел себя как обычный 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)) });
el.next().find("input").eq(0).bind("change", function(e) { changeVisualRadio(jQuery(this)) });
if(jQuery.browser.msie)
{
el.next().find("input").eq(0).bind("click", function(e) { changeVisualRadio(jQuery(this)) });
}
el.remove();
}
catch(e)
{
// если ошибка, ничего не делаем
}
return true;
}
Демо пример. Проверено в:
Динамическое добавление radio
update: 20.05.10 Алгоритм:
- дабавляется radio с классом niceRadio
- вызывается функция changeRadioStart, параметром которой является ссылка на добавленное radio
/*
динамическое добавление radio
*/
jQuery("#addRadio").click(
function() {
jQuery("#testForm").append("");
var el = jQuery("input.niceRadio");
changeRadioStart(el);
});







