Нестандартные radio
Задача
Стильно оформить элемент формы 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)) }); 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, если в коде скрипта оставить комментарии.