Этот скрип довольно простой в освоении и успешно работает в разных браузерах на различных устройствах. Частенько применялся мною в "боевых условиях" и всегда стабильно отрабатывал свои функции.
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 требуются картинки как для обычного, так и для активного состояния.

Для уменьшения запросов к серверу, все фрагменты засунем в спрайт.
С 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 не тестировался)