Кастомный checkbox средствами HTML и CSS (no-js) #1

kyoshee
4 min readNov 5, 2020

На одном из собеседований мне попалось интересное задание на верстку:

Средствами html и css напишите кастомный checkbox таким образом, чтобы оригинальное изображение checkbox’a не отображалось, но сохранялся весь функционал (checked — unchecked). Вместо оригинального изображения checkbox’a должно быть кастомное изображение или текст, отображающие текущее состояние checkbox’a и обеспечивающие соответствующий функционал.

Где-то в подсознании я вспомнил про псевдоэлементы, но даже с гуглом не смог справиться с заданием за 5 минут, после чего со мной прекратили диалог «до обратной связи». Но я не расстраиваюсь, а беру на вооружение и улучшаю свой скилл, поэтому: существует два способа создания кастомных checkbox’ов.

Способ 1

Подходит для разметки, в которой <input> связан с <label> через id и for:

Checkbox по-умолчанию
<input 
class="custom-checkbox"
id="myCheckbox"
type="checkbox">
<label for="myCheckbox">
Checkbox
</label>

Последовательность элементов важна, т.к. от нее будут зависеть выражения для выбора элементов в CSS.

Скрываем input

.custom-checkbox {
position: absolute;
z-index: -1;
opacity: 0;
}

Преимущество данного способа перед display: none заключается в сохранении возможности получить состояние фокуса для дальнейшей стилизации input.

Создаем поддельный checkbox

.custom-checkbox + label {
cursor: pointer;
display: inline-flex;
align-items: center;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.custom-checkbox + label::before {
content: '';
display: inline-block;
width: 1em;
height: 1em;
flex-shrink: 0;
flex-grow: 0;
border: 1px solid #c3c3c3;
border-radius: 0.25em;
margin-right: 0.5em;
background-repeat: no-repeat;
background-position: center center;
background-size: 50% 50%;
}
Кастомный checkbox

Сначала вертикально центрируем флажок с подписью с помощью align-items: center для flex-контейнеров.

С помощью псевдоэлемента ::before создаем имитацию checkbox’а. Отрисуем его границы для постоянной видимости. Правила background -repeat, -position и -size определяют положение флажка в состоянии checked.

Меняем отображение псевдоэлемента в состоянии checked

.custom-checkbox:checked + label::before {
border-color: blue;
background-color: blue;
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%23fff' d='M6.564.75l-3.59 3.612-1.538-1.55L0 4.26 2.974 7.25 8 2.193z'/%3e%3c/svg%3e");
}
Кастомный checkbox в состоянии checked

Стилизуем checkbox в остальных его состояниях: hover, active, focus и disabled

.custom-checkbox:not(:disabled):not(:checked) + label:hover::before {
border-color: rgba(0, 0, 255, 0.33);
}
.custom-checkbox:not(:disabled):active + label::before {
background-color: rgba(0, 0, 255, 0.66);
}
.custom-checkbox:focus + label::before {
box-shadow: 0 0 0 0.2rem rgba(0, 0, 255, 0.125);
}
.custom-checkbox:focus:not(:checked) + label::before {
border-color: #c3c3c3;
}
.custom-checkbox:disabled + label::before {
background-color: black;
}
Кастомный checkbox в состоянии hover
Кастомный checkbox в состоянии active
Кастомный checkbox в состоянии checked и focus
Кастомный checkbox в состоянии focus
Кастомный checkbox в состоянии disabled

Пример на jsfiddle.

Способ 2

Подходит для разметки, в которой <input> расположен внутри <label>:

<label class="custom-checkbox">
<input type="checkbox">
</label>

В данном случае необходимо добавить <span> после <input>:

<label class="container">Checkbox
<input type="checkbox" checked="checked">
<span class="checkmark"></span>
</label>

Создадим более простой checkbox без учета всех состояний и с задаваемой позицией рисунка.

Стилизуем <label> (контейнер):

.container {
display: block;
position: relative;
padding-left: 35px;
margin-bottom: 12px;
cursor: pointer;
font-size: 22px;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}

Скрываем стандартный <input>:

.container input {
position: absolute;
z-index: -1;
opacity: 0;
}

Рисуем кастомный checkbox в <span>:

.checkmark {
position: absolute;
top: 0;
left: 0;
height: 25px;
width: 25px;
background-color: #eee;
}

Стилизуем <span> в состоянии hover и в состоянии checked:

.container:hover input ~ .checkmark {
background-color: #ccc;
}
.container input:checked ~ .checkmark {
background-color: #2196F3;
}

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

.checkmark:after {
content: "";
position: absolute;
display: none;
}
.container input:checked ~ .checkmark:after {
display: block;
}
.container .checkmark:after {
left: 9px;
top: 5px;
width: 5px;
height: 10px;
border: solid white;
border-width: 0 3px 3px 0;
-webkit-transform: rotate(45deg);
-ms-transform: rotate(45deg);
transform: rotate(45deg);
}

Пример на jsfiddle.

Аналогично можно стилизовать и <input type="radio">.

Примеры

<label> и <input> раздельно, checkbox
<label> и <input> раздельно, radio

<input> внутри <label>, checkbox
<input> внутри <label>, radio

<input> внутри <label>, checkbox, другой стиль
<input> внутри <label>, checkbox, другой стиль

Итого

Мы научились пользоваться псведоэлементами, селекторами состояний и соседних элементов в CSS. Надеюсь, эта информация поможет тебе!

Всех благ,
kyoshee

--

--