Как создать пользовательский переключатель с помощью 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;
  }
}

Пользовательский переключатель готов к использованию.

Пожалуйста, оставляйте ваши мнения по текущей теме материала. Мы очень благодарим вас за ваши комментарии, лайки, дизлайки, отклики, подписки!

Пожалуйста, опубликуйте ваши комментарии по текущей теме материала. За комментарии, отклики, подписки, лайки, дизлайки низкий вам поклон!

Вадим Дворниковавтор-переводчик статьи «How to create a custom radio switch in CSS»