Стилизация чекбоксов и радиокнопок на чистом CSS с совместимостью для старых браузеров

Честно говоря, я «слегка» припозднился с данной статьей, т.к. то, что в ней изложено, можно было применять на практике уже довольно давно. Но лучше поздно, чем никогда, тем более, что я уверен, что среди моих читателей найдутся и те, кто не пользуется этим способом при верстке по тем или иным причинам, как, собственно, и я до недавнего времени.

Для того, чтобы оформить чекбоксы и радиокнопки, как того требует дизайн, сегодня не обязательно использовать JavaScript-решения (типа моего плагина jQuery Form Styler), т.к. для этого можно задействовать чистый CSS, причем с обратной совместимостью для старых браузеров (т.е. не в ущерб юзабилити), которые не поддерживают современные CSS-правила.

Другими словами — в современных браузерах чекбоксы и радиокнопки будут выглядеть красиво, в соответствии с задуманным дизайном, а в старых (это относится к Internet Explorer версии 8 и ниже) они останутся с оформлением «по умолчанию», характерным для каждой конкретной операционной системы.

Фокус заключается в использовании псевдоселекторов :checked и :not. При этом сам чекбокс или радиокнопка делаются невидимыми, а их эмуляция осуществляется с помощью псевдоселекторов :before и :after для тега <label>, который, как мы знаем, переключает состояния элемента формы, если он привязан к нему через атрибут for.

В HTML-коде это выглядит следующим образом:

<input type="checkbox" class="checkbox" id="checkbox" />
<label for="checkbox">Я переключаю чекбокс</label>

<input type="radio" class="radio" id="radio" />
<label for="radio">А я переключаю радиокнопку</label>

При этом важно, чтобы тег <label> обязательно был расположен после тега <input>.

Далее в дело вступает CSS. В комментариях к коду для чекбокса я написал пояснения:

/* Cначала обозначаем стили для IE8 и более старых версий
т.е. здесь мы немного облагораживаем стандартный чекбокс. */
.checkbox {
	vertical-align: top;
	margin: 0 3px 0 0;
	width: 17px;
	height: 17px;
}
/* Это для всех браузеров, кроме совсем старых, которые не поддерживают
селекторы с плюсом. Показываем, что label кликабелен. */
.checkbox + label {
	cursor: pointer;
}

/* Далее идет оформление чекбокса в современных браузерах, а также IE9 и выше.
Благодаря тому, что старые браузеры не поддерживают селекторы :not и :checked,
в них все нижеследующие стили не сработают. */

/* Прячем оригинальный чекбокс. */
.checkbox:not(checked) {
	position: absolute;
	opacity: 0;
}
.checkbox:not(checked) + label {
	position: relative; /* будем позиционировать псевдочекбокс относительно label */
	padding: 0 0 0 60px; /* оставляем слева от label место под псевдочекбокс */
}
/* Оформление первой части чекбокса в выключенном состоянии (фон). */
.checkbox:not(checked) + label:before {
	content: '';
	position: absolute;
	top: -4px;
	left: 0;
	width: 50px;
	height: 26px;
	border-radius: 13px;
	background: #CDD1DA;
	box-shadow: inset 0 2px 3px rgba(0,0,0,.2);
}
/* Оформление второй части чекбокса в выключенном состоянии (переключатель). */
.checkbox:not(checked) + label:after {
	content: '';
	position: absolute;
	top: -2px;
	left: 2px;
	width: 22px;
	height: 22px;
	border-radius: 10px;
	background: #FFF;
	box-shadow: 0 2px 5px rgba(0,0,0,.3);
	transition: all .2s; /* анимация, чтобы чекбокс переключался плавно */
}
/* Меняем фон чекбокса, когда он включен. */
.checkbox:checked + label:before {
	background: #9FD468;
}
/* Сдвигаем переключатель чекбокса, когда он включен. */
.checkbox:checked + label:after {
	left: 26px;
}
/* Показываем получение фокуса. */
.checkbox:focus + label:before {
	box-shadow: 0 0 0 3px rgba(255,255,0,.5);
}

Для радиокнопки будет по сути то же самое:

.radio {
	vertical-align: top;
	width: 17px;
	height: 17px;
	margin: 0 3px 0 0;
}
.radio + label {
	cursor: pointer;
}
.radio:not(checked) {
	position: absolute;
	opacity: 0;
}
.radio:not(checked) + label {
	position: relative;
	padding: 0 0 0 35px;
}
.radio:not(checked) + label:before {
	content: '';
	position: absolute;
	top: -3px;
	left: 0;
	width: 22px;
	height: 22px;
	border: 1px solid #CDD1DA;
	border-radius: 50%;
	background: #FFF;
}
.radio:not(checked) + label:after {
	content: '';
	position: absolute;
	top: 1px;
	left: 4px;
	width: 16px;
	height: 16px;
	border-radius: 50%;
	background: #9FD468;
	box-shadow: inset 0 1px 1px rgba(0,0,0,.5);
	opacity: 0;
	transition: all .2s;
}
.radio:checked + label:after {
	opacity: 1;
}
.radio:focus + label:before {
	box-shadow: 0 0 0 3px rgba(255,255,0,.5);
}

Вот таким несложным образом это и делается. Благодаря данному способу, оформить чекбоксы и радиокнопки с помощью CSS можно так, как вам будет угодно.

Комментарии (77)
  1. 1
    Сергей
    /* Показываем получение фокуса. */
    .checkbox:focus + label:before {
     box-shadow: 0 0 0 3px rgba(255,255,0,.5);
    }

    Не вижу, что тут происходит, что это за тень? Поясните пожалуйста!
    А за решение спасибо!

  2. 8
    Мой Хозяин

    Здравствуйте и все-таки как сделать для радио кнопки?

  3. 10
    Михаил

    Здравствуйте. Если обновить станицу, то все чекбоксы (выбранные) остаются в состание чекет. Что можно с эти сделать?

  4. 12
    RiA

    Здравствуйте, подскажите пожалуйста в чем может быть проблема?: стоит фильтр характеристик на сайте, при нажатии на любой фильтр — работает только самый верхний чекбокс (только самая первая характеристика — все остальные не подвижны)

  5. 13
    Роман

    Когда клацаю по чекбоксу, текст сползает постепенно вниз.

  6. 14
    Артем

    Ничего не работает в мозиле и в хроме пробовал не пашет как было так и осталось!

  7. 15
    Никита

    Всё прекрасно работает. Автору спасибо)

  8. 16
    PuNKeR

    Подскажите, а как сделать, чтобы label был с левой стороны?

  9. 17
    Дмитрий

    Спасибо, очень полезно

  10. 18
    Алексей

    Доброго времени суток!
    Спасибо за отличную статью.
    Небольшое дополнение: в хроме может не срабатывать стиль checkbox:checked + label:after
    Что бы исправить это нужно поместить чекбокс в div:
    checkbox

  11. 20

    Классная статья о таком способе я еще не знал

  12. 21
    xxxLOGIATxxx

    Слишком большая зависимость от тега label. Например в Drupal 8 эти два элемента периодически отображаются в таблицах, причём в разных столбцах, что делает этот код неюзабельным, поскольку ячейка таблицы останется пустой. Попробую Ваш js вариант. А статья хорошая и доходчивая.

  13. 22
    Николай

    Спасибо, страница в закладках, очень часто возвращаюсь сюда, от себя добавлю в sass тот же код(без выделения фокусом):

    .checkbox{
    		vertical-align: top;
    	 margin: 0 3px 0 0;
    	 width: 17px;
    	 height: 17px;
    		&amp; + label{
    			cursor: pointer;
    		}
    		&amp;:not(checked){
    			position: relative;
     			padding: 0 0 0 60px;
    			&amp; + label::before{
    				content: '';
    				position: absolute;
    				top: -4px;
    				left: 0;
    				width: 50px;
    				height: 26px;
    				border-radius: 13px;
    				background: #CDD1DA;
    				box-shadow: inset 0 2px 3px rgba(0,0,0,.2);
    			}
    			&amp; + label::after{
    				content: '';
    				position: absolute;
    				top: -2px;
    				left: 2px;
    				width: 22px;
    				height: 22px;
    				border-radius: 10px;
    				background: #FFF;
    				box-shadow: 0 2px 5px rgba(0,0,0,.3);
    				transition: all .2s;
    			}
    		}
    		&amp;:checked{
    			&amp; + label::before{
    				background: #9FD468;
    			}
    			&amp; + label::after{
    				left: 26px;
    			}
    		}
    
    	}
    
    
  14. 23
    Iryna

    Спасибо большое.
    Очередной раз пришла подглядеть код и стало даже стыдно, что до сих пор не поблагодарила автора. Огромное-огромное спасибо!!!)

  15. 24
    Николай

    А как в этом красивом стиле достучаться хотя бы до value радиобаттонов?
    У меня даже простой сумматор чекнутых радио с ними не срабатывает (

    <form>
    
    <input class="radio" id="radio-1" name="radio" type="radio" value="1">
    <label for="radio-1">111</label>
    
    <input class="radio" id="radio-2" name="radio" type="radio" value="2">
    <label for="radio-2">222</label>
    
    <input class="radio" id="radio-3" name="radio" type="radio" value="3">
    <label for="radio-3">333</label>
    
    <input class="radio" id="radio-4" name="radio" type="radio" value="4">
    <label for="radio-4">444</label>
    
     <input type="button" value="Подсчитать">
     <br>Сумма:
     <input type="text" name="sumOut" disabled="false" value="">
    
    </form>
    
    
    <script>
    window.onload = function() {
     document.forms.formText.onclick = function() {
     var sum = 0,
     els = this.querySelectorAll('input[type="radio"]:checked');
     for (var i = 0; i < els.length; i++) {
     sum += +els[i].value;
     }
     this.sumOut.value = sum;
     };
    };
    </script>
  16. 26

    Я только не понял почему когда мы стилизуем :not(checked), то инпут стилизуется не только в «невыбранном» состоянии но в выбранном. Объясните пожалуйста

  17. 30
    Vasya Pupkin

    Себя же и поправил

    .checkbox:disabled + label:before {
    background: #ccc;
    }
    .radio:disabled + label:before {
    background: #eee;
    }
    .radio:disabled:checked + label:after {
    background: #ccc;
    }

    Обнови стили, Людям будет проще копитырить.

  18. 31
    Дмитрий
    @

    Здравствуйте! скажите пожалуйста, мне надо в label:before при .checkbox:checked вставить svg иконку «галочку». Пишу .chekbox:checked+label:before{ display:block; background: url(../icons/check.svg) no-repeat center } и ничего не работает. только если в content «» вставляю fontawesome, то работает, а мне нужно вставить svg иконку. как это решить?

  19. 33
    Unknow Coder

    для radio и checkbox можно более легкое решение — без :not-ов!

    /*HTML*/
    <label><input type="radio"><span></span></label>
    
    /*CSS*/
    
    input[type="radio"] {
    	display: none;
    }
    
    label {
    	position: relative;
    	
    	margin-bottom: 23px;
    	padding-left: 62px;
    	
    	line-height: 42px;
    }
    
    label::before {
    	content: "";
    	position: absolute;
    	// top: -17px;
    	left: 0;
    	
    	width: 42px;
    	height: 42px;
    	
    	border: 3px solid #666666;
    	border-radius: 50%;
    }
    
    input[type="radio"]:checked + span::after {
    	content: "";
    	position: absolute;
    	top: 1px;
    	left: 13px;
    	
    	width: 16px;
    	height: 16px;
    	
    	background: aqua;
    	border: 3px solid aqua;
    	border-radius: 50%;
    }
    
  20. 35
    Unknow Coder

    так даже более симантично так как input в label лежит и for не нужен), но автору респект за содержательную статью!

Ваш комментарий