На одном из собеседований мне попалось интересное задание на верстку:
Средствами html и css напишите кастомный checkbox таким образом, чтобы оригинальное изображение checkbox’a не отображалось, но сохранялся весь функционал (checked — unchecked). Вместо оригинального изображения checkbox’a должно быть кастомное изображение или текст, отображающие текущее состояние checkbox’a и обеспечивающие соответствующий функционал.
Где-то в подсознании я вспомнил про псевдоэлементы, но даже с гуглом не смог справиться с заданием за 5 минут, после чего со мной прекратили диалог «до обратной связи». Но я не расстраиваюсь, а беру на вооружение и улучшаю свой скилл, поэтому: существует два способа создания кастомных checkbox’ов.
Способ 1
Подходит для разметки, в которой <input>
связан с <label>
через id
и for
:
<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%;
}
Сначала вертикально центрируем флажок с подписью с помощью 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 в остальных его состояниях: 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;
}
Способ 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);
}
Аналогично можно стилизовать и <input type="radio">
.
Примеры
<label>
и <input>
раздельно, checkbox<label>
и <input>
раздельно, radio
<input>
внутри <label>
, checkbox<input>
внутри <label>
, radio
<input>
внутри <label>
, checkbox, другой стиль<input>
внутри <label>
, checkbox, другой стиль
Итого
Мы научились пользоваться псведоэлементами, селекторами состояний и соседних элементов в CSS. Надеюсь, эта информация поможет тебе!
Всех благ,
kyoshee