Кастомные чекбоксы и радиокнопки

Вступление

Браузерные чекбоксы и радиокнопки в разных браузерах могут выглядеть по-разному. Кроме того, внешний вид этих элементов практически всегда выбивается из стиля сайта. А как их стилизовать? Как у чекбокса поменять рамку с галочкой, а радиокнопку сделать квадратной?

Я вам покажу два способа. Первый способ самый удобный, но необходимо его использовать с аккуратностью, так как могут быть проблемы с кроссбраузерностью. Он основывается на appearance: none;. Это свойство достаточно хорошо поддерживается, но для моей работы он всё-таки не подходит, так как мы работаем для множества стран, и не везде всё так хорошо с вебом как у нас. Второй способ более кроссбраузерный, но менее удобный. Есть ещё один способ — о нём кратко в конце.

видео

Кастомные чекбоксы и радиокнопки

Самый простой способ кастомизации.

Самый простой, и при этом более надёжный способ, у которого могут быть проблемы с кроссбраузерностью если нужна поддержка очень старых браузеров.

Начну с HTML разметки и не забываю про семантику:

html

<label class="label">
  <input type="checkbox" class="checkbox" name="name" checked>
  Кнопка 1
</label>
<label class="label">
  <input type="checkbox" class="checkbox" name="name">
  Кнопка 2
</label>
<label class="label">
  <input type="checkbox" class="checkbox" name="name" disabled>
  Кнопка 3
</label>

<label class="label">
  <input type="radio" class="radio" name="name" checked>
  Кнопка 4
</label>
<label class="label">
  <input type="radio" class="radio" name="name">
  Кнопка 5
</label>
<label class="label">
  <input type="radio" class="radio" name="name" disabled>
  Кнопка 6
</label>
Три кнопки чекбокс: первая отмечена, третья отключена; три радиокнопки: первая отмечена, третья отключена
вид кнопок по-умолчанию.

Основные стили.

Первым делом отключаю браузерные стили и сразу прописываю правила для стилизации кнопок в спокойном состоянии. Для этого возьму готовые картинки из одного учебного проекта.

css

.radio,
.checkbox {
  appearance: none;
  display: inline-block;
  margin: 0;
  width: 16px;
  height: 16px;
  background-image: url(./img/input.svg);
  background-repeat: no-repeat;
  background-position: center;
  background-size: contain;
  vertical-align: baseline;
}
шесть стилизованых кнопок: перед подписью простой прямоугольник
вид стилизованых не выбранных кнопок.

Что тут происходит?

  • Правила прописываю сразу и для чекбоксов и для радиокнопок
  • appearance: none; отключает все браузерные стили, после этого свойства input совсем не будет видно
  • display: inline-block; добавляю чтобы можно было задать размеры
  • margin: 0; сбрасывает браузерные отступы
  • vertical-align: baseline; выравнивает кнопку в строке, возможно вам это не нужно
  • Остальные правила добавляют фоновую — картинку рамку для кнопок.

Отмечаем выбранные кнопки.

У чекбоксов достаточно поменять фоновую картинку, а у радиокнопок точку добавлю другим способом — псевдоэлемент создам.

css

.checkbox:checked {
  background-image: url(./img/input-checked.svg);
}

.radio:checked::before {
  content: '';
  display: block;
  width: 6px;
  height: 6px;
  background-color: #2D3440;
  border-radius: 2px;
  margin: 5px;
}
Три кастомные кнопки чекбокс: первая отмечена, третья отключена и без стилей; три кастомные радиокнопки: первая отмечена, третья отключена и без стилей
вид стилизованых кнопок, но отключенные кнопки выглядят как и включенные неотмеченные.

Чекбоксы комментировать не вижу смысла, а про радиокнопки немного расскажу:

  • Когда отмечена кнопка — создаю псевдоэлемент
  • content: ''; обязательное свойство для псевдоэлемента
  • display: block; для размеров и отступов
  • border-radius: 2px; слегка закруглят углы
  • Остальное и так понятно))

Стилизация событий кнопок.

Фокус стилизовать не буду — есть браузерный оутлайн, а остальное, в том числе :disabled — необходимо.

css

.radio:hover,
.checkbox:hover {
  opacity: 0.8;
}

.radio:active,
.checkbox:active {
  opacity: 0.6;
}

.radio:disabled,
.checkbox:disabled {
  opacity: 0.4;
}

К сожалению такой подход не позволяет менять цвет кнопок, но на следующем примере я покажу как это можно сделать и ещё добавить анимацию.

вид стилизованых кнопок, со всеми событиями.

Что мы получили? Две кнопки доступные с клавиатуры, с эффектами состояний для всех событий. А скомбинировав этот и следующий способ можно будет использовать красивые «плюшки».

Радиокнопки и чекбоксы на span.

Разметка практически такая же как и у первого варианта, но после каждой кнопки добавляется span для визуализации кнопки и класс .visually-hidden для доступного cкрытия кнопок. Он необходим для того, что бы пользователь мог попасть клавишей TAB по нашей кнопке и взаимодействовать с ней. Стили этого класса прописаны так, что бы его не было визуально видно, но при этом пользователям клавиатуры и программ чтения с экрана был виден элемент.

css

.visually-hidden {
  position: absolute;
  width: 0;
  height: 0;
  margin: 0;
  padding: 0;
  overflow: hidden;
  border: none;
}

html

<label class="label">
  <input type="checkbox" class="checkbox visually-hidden" name="name" checked>
  <span class="checkbox-view"></span>
  Кнопка 1
</label>
<label class="label">
  <input type="checkbox" class="checkbox visually-hidden" name="name">
  <span class="checkbox-view"></span>
  Кнопка 2
</label>
<label class="label">
  <input type="checkbox" class="checkbox visually-hidden" name="name" disabled>
  <span class="checkbox-view"></span>
  Кнопка 3
</label>

<label class="label">
  <input type="radio" class="radio visually-hidden" name="name" checked>
  <span class="radio-view"></span>
  Кнопка 4
</label>
<label class="label">
  <input type="radio" class="radio visually-hidden" name="name">
  <span class="radio-view"></span>
  Кнопка 5
</label>
<label class="label">
  <input type="radio" class="radio visually-hidden" name="name" disabled>
  <span class="radio-view"></span>
  Кнопка 6
</label>
шесть кнопок с подписями, сами кнопки скрыты
самих кнопок не видно.

Основные стили кнопок на span.

Так как я хочу анимировать цвет кнопок, и мне нужна обводка при фокусе, сам span не будет иметь никакого внешнего вида — визуализировать будут его псевдоэлементы. Для этого span необходимо подготовить:

css

.radio-view,
.checkbox-view {
  display: inline-block;
  width: 16px;
  height: 16px;
  vertical-align: baseline;
  position: relative;
  color: #2D3440;
}

Всё просто:

  • display: inline-block; для того чтобы можно было добавить размеры
  • position: relative; необходим чтобы отсчет координат выбитых из потока псевдоэлементов шел от span
  • color: #2D3440; необходим для более удобной смены цвета кнопок
  • Ну и размеры и выравнивание в строке.

Теперь добавим рамку:

css

.radio-view::before,
.checkbox-view::before {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  mask-image: url(./img/input.svg);
  -webkit-mask-image: url(./img/input.svg);
  mask-position: center;
  -webkit-mask-position: center;
  mask-repeat: no-repeat;
  -webkit-mask-repeat: no-repeat;
  mask-size: contain;
  -webkit-mask-size: contain;
  background-color: currentColor;
}
шесть стилизованых кнопок: перед подписью простой прямоугольник
вид стилизованых не выбранных кнопок.

Получилось много всего, но это только на первый взгляд:

  • content: ''; обязательное свойство для псевдоэлемента
  • position: absolute; и следующие два свойства — позиционируем внутри span псевдоэдементы
  • Ширина и высота — это понятно))
  • background-color: currentColor; что бы отображалась маска. Причём currentColor добавляет цвет текста. Если поменять значение свойства color, то и этот фон поменяется.
  • Ну и шесть три свойства добавляет маску и настройки этой маски.

Теперь нужно отметить выбранные кнопки, но для анимации нужно немного доработать псевдоэлементы у span

css

.checkbox-view::after {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  mask-image: url(./img/input-checked.svg);
  -webkit-mask-image: url(./img/input-checked.svg);
  mask-position: center;
  -webkit-mask-position: center;
  mask-repeat: no-repeat;
  -webkit-mask-repeat: no-repeat;
  mask-size: contain;
  -webkit-mask-size: contain;
  background-color: currentColor;
  opacity: 0;
}

.checkbox-view::after,
.checkbox-view::before {
  transition: opacity 0.25s ease-in-out;
}

По сути дела я создал псевдоэлемент ::after такой же как и ::before, только добавил прозрачность. Ну и добавил анимацию прозрачности. Тут стоит добавить, что лучше указывать какие свойства нужно анимировать, и время анимации лучше не делать более чем 0.3 секунды.

Ну а добавить галочку можно так:

css

.checkbox:checked+.checkbox-view::before {
  opacity: 0;
}

.checkbox:checked+.checkbox-view::after {
  opacity: 1;
}

С радио кнопками тоже нужна подготовка:

css

.radio-view::after {
  content: '';
  display: block;
  width: 6px;
  height: 6px;
  background-color: currentColor;
  border-radius: 2px;
  margin: 5px;
  opacity: 0;
  transition: opacity 0.25s ease-in-out;
}

Стили почти как у псевдоэлемента радиокнопки в первом случае, только я заменил значение цвета фона, сделал псевдоэлемент полностью прозрачным и добавил анимацию прозрачности. По аналогии с чекбоксом ставим точку у выбранной радиокнопки:

css

.radio:checked + .radio-view::after {
  opacity: 1;
}
Три кастомные кнопки чекбокс: первая отмечена, третья отключена и без стилей; три кастомные радиокнопки: первая отмечена, третья отключена и без стилей
вид стилизованых кнопок, но отключенные кнопки выглядят как и включенные неотмеченные.

Осталось добавить состояния событий интерактивного элемента. Есть оговорка)) Судя по поведению кнопок при наведении на label в первом случае, необходимо добавлять эффект наведения кнопкам при попадании курсора на label и сейчас.

css

.label:hover .checkbox:not(:disabled):not(:active)+.checkbox-view,
.label:hover .radio:not(:disabled):not(:active)+.radio-view {
  color: blue;
}

Усложнение :not(:disabled):not(:active)+ необходимо, что бы к отключенной кнопке и в состоянии [code :active] не применялись стили. Цвет меняется, но без анимации — поправим:

css

.checkbox-view::before,
.checkbox-view::after,
.radio-view::before,
.radio-view::after {
  transition: opacity 0.25s ease-in-out, color 0.25s ease-in-out;
}

Ну и оставшееся:

css

.checkbox:not(:disabled)+.checkbox-view:active,
.radio:not(:disabled)+.radio-view:active {
  color: red;
}

.checkbox:focus-visible+.checkbox-view,
.radio:focus-visible+.radio-view {
  outline: auto;
}

.checkbox:disabled+.checkbox-view,
.radio:disabled+.radio-view {
  opacity: 0.4;
}
вид стилизованых кнопок, со всеми событиями.

Итоги

Я не стал показывать третий вариант: то же самое что и со span, но без него. Если вам первые два варианта не подходят — можете немного модифицировать второй. А этих двух хватает для большинства случаев.

Объявление

Если вы хотите обучаться вместе со мной, то приглашаю вас на индивидуальные курсы HTML Academy: «Профессиональная вёрстка сайтов» или «Адаптивная вёрстка и автоматизация».

Просто спросите у менеджера меня — наставника Зиновьева Александра. Обучение проходит в помесячном индивидуальном формате, и вы можете начать в любое удобное для вас время.

Кроме того, в HTML Academy вы получите профессию и даже сможете устроиться на работу с новой профессией.