Как создать пользовательский переключатель с помощью CSS
В этой статье мы расскажем, как с помощью CSS создать пользовательский переключатель.

Недавно мы создали компонент Radio Switch. Чтобы обеспечить его доступность необходимо учитывать некоторые моменты.
Компонент, который мы создадим в этом руководстве, основан на платформе CodyHouse.
Давайте сделаем это!
Основная идея заключается в следующем: мы создаем список, состоящий из двух переключателей (два доступных варианта). Затем скрываем эти элементы ввода и применяем стиль к видимым label.
Вот структура HTML:
<ul class="radio-switch">
<li class="radio-switch__item">
<input type="radio" class="radio-switch__input sr-only" id="radio1" name="radioSwitch" checked>
<label for="radio1" class="radio-switch__label">Monthly</label>
</li>
<li class="radio-switch__item">
<input type="radio" class="radio-switch__input sr-only" id="radio2" name="radioSwitch">
<label for="radio2" class="radio-switch__label">Yearly</label>
</li>
</ul>
Мы применили класс sr-only к обоим элементам ввода, чтобы визуально скрыть их. Но они все еще доступны для программ чтения с экрана. Вы можете узнать больше об этом классе из документации к платформе.
Теперь добавим стили к label, чтобы они были выровнены и имели одинаковую ширину. А также к элементу .radio-switch:
:root {
// стили
--radio-switch-width: 186px;
--radio-switch-height: 46px;
--radio-switch-padding: 3px;
--radio-switch-radius: 50em;
// анимация
--radio-switch-animation-duration: 0.3s;
}
.radio-switch {
display: inline-flex;
padding: var(--radio-switch-padding);
border-radius: var(--radio-switch-radius);
border: 1px solid var(--color-contrast-low);
}
.radio-switch__item {
height: calc(var(--radio-switch-height) - 2*var(--radio-switch-padding));
width: calc(var(--radio-switch-width)*0.5 - var(--radio-switch-padding));
}
.radio-switch__label {
display: block;
line-height: calc(var(--radio-switch-height) - 2*var(--radio-switch-padding));
text-align: center;
border-radius: var(--radio-switch-radius);
}
После этого создадим маркер, чтобы использовать его в качестве элемента фона, перемещающегося с одной стороны переключателя на другую. Можно добавить этот маркер во второй элемент списка:
<ul class="radio-switch">
<li class="radio-switch__item">
<!-- input + label -->
</li>
<li class="radio-switch__item">
<!-- input + label -->
<div class="radio-switch__marker" aria-hidden="true"></div>
</li>
</ul>
Мы добавили aria-hidden true, чтобы скрыть элемент от программ чтения с экрана. Теперь стилизуем его:
.radio-switch__item {
position: relative;
}
.radio-switch__marker {
position: absolute;
top: 0;
left: -100%;
height: 100%;
width: 100%;
background-color: var(--color-primary);
border-radius: var(--radio-switch-radius);
transition: transform var(--radio-switch-animation-duration);
.radio-switch__input:checked ~ & { // перемещаем маркер с одной стороны на другую
transform: translateX(100%);
}
}
Нужно, чтобы пользователи, перемещающиеся по странице с помощью клавиатуры, видели, что элемент переключателя находится в фокусе ввода. Для этого можно использовать псевдокласс :focus-within:
.radio-switch {
// ...
&:focus-within {
box-shadow: 0 0 0 3px var(--color-contrast-lower);
}
}
Когда переключатель выделен фокусом ввода (класс .radio-switch), к переключателю добавляется тень, которая сигнализирует о его выделении фокусом ввода.
Примечание: на момент написания данной статьи псевдокласс :focus-within поддерживается не во всех современных браузерах.
Чтобы исправить это, можно реализовать другой эффект а затем переписать его для браузеров, которые поддерживают :focus-within :
.radio-switch {
// ...
&:focus-within {
box-shadow: 0 0 0 3px var(--color-contrast-lower);
}
}
.radio-switch__label {
//..
.radio-switch__input:focus ~ & {
// эффект выделения фокусом ввода в браузерах, не поддерживающих :focus-within
background-color: lightness(var(--color-primary), 0.6);
}
:not(*):focus-within, // trick to detect :focus-within support -> https://css-tricks.com/using-feature-detection-conditionals-and-groups-with-selectors/
.radio-switch__input:focus ~ & {
// переключение эффекта фокуса для браузеров, поддерживающих :focus-within
background-color: transparent;
}
}
Пользовательский переключатель готов к использованию.