CSS - Переключатель с использованием JavaScript

CSS - Переключатель с использованием JavaScript
Содержание:
  1. Что такое переключатель
  2. HTML разметка переключателя
  3. CSS стили для переключателя
  4. JavaScript код для переключателя
  5. Комментарии

В этой статье разберем процесс создания переключателя для сайта с использованием CSS и JavaScript. Кроме этого ещё рассмотрим пример, в котором покажем, как можно отслеживать состояние переключателя и выполнять при его изменении некоторый код.

Что такое переключатель

Переключатель - это элемент интерфейса, предназначенный для выбора одно из двух состояний (включено или выключено).

Данный элемент можно использовать в некоторых случаях в качестве альтернативы checkbox (флажку).

HTML разметка переключателя

HTML код переключателя:

HTML
<div class="switch-btn"></div>

Для отображения переключателя во включенном состоянии необходимо дополнительно к switch-btn добавить ещё класс switch-on:

HTML
<div class="switch-btn switch-on"></div>

CSS стили для переключателя

Создать дизайн переключателю можно по-разному. В качестве примера рассмотрим 5 вариантов дизайна.

Дизайн переключателя как в Material Design

Дизайн переключателя как в Material Design
CSS
.switch-btn {
  display: inline-block;
  width: 62px; /* ширина переключателя */
  height: 24px; /* высота переключателя */
  border-radius: 12px; /* радиус скругления */
  background: #bfbfbf; /* цвет фона */
  z-index: 0;
  margin: 0;
  padding: 0;
  border: none;
  cursor: pointer;
  position: relative;
  transition-duration: 300ms; /* анимация */
}
.switch-btn::after {
  content: "";
  height: 36px; /* высота кнопки */
  width: 36px; /* ширина кнопки */
  border-radius: 18px; /* радиус кнопки */
  background: #fff; /* цвет кнопки */
  top: -6px; /* положение кнопки по вертикали относительно основы */
  left: -6px; /* положение кнопки по горизонтали относительно основы */
  transition-duration: 300ms; /* анимация */
  box-shadow: 0 0 10px 0 #999999; /* тень */
  position: absolute;
  z-index: 1;
}
.switch-on {
  background: #fff;
  box-shadow: inset 0 0 10px 0 #999999; /* тень */
}
.switch-on::after {
  left: 30px;
  background: #118c4e;
}

Дизайн переключателя для интерфейсов, не использующих скругления углов

Дизайн переключателя для интерфейсов, не использующих  скругления углов
CSS
.switch-btn {
  display: inline-block;
  width: 62px; /* ширина переключателя */
  height: 24px; /* высота переключателя */
  background: #bfbfbf; /* цвет фона */
  z-index: 0;
  margin: 0;
  padding: 0;
  border: none;
  cursor: pointer;
  position: relative;
  transition-duration: 300ms; /* анимация */
}
.switch-btn::after {
  content: "";
  height: 36px; /* высота кнопки */
  width: 36px; /* ширина кнопки */
  background: #fff; /* цвет кнопки */
  top: -6px; /* положение кнопки по вертикали относительно основы */
  left: -12px; /* положение кнопки по горизонтали относительно основы */
  transition-duration: 300ms; /* анимация */
  box-shadow: 0 0 10px 0 #999999; /* тень */
  position: absolute;
  z-index: 1;
}
.switch-on {
  background: #fff;
  box-shadow: inset 0 0 10px 0 #999999; /* тень */
}
.switch-on::after {
  left: 36px;
  background: #118c4e;}

Дизайн переключателя, в котором кнопка расположена внутри элемента, вдоль которого она перемещается

Дизайн переключателя, в котором кнопка расположена внутри элемента, вдоль которого она перемещается
CSS
.switch-btn {
  display: inline-block;
  width: 72px; /* ширина */
  height: 38px; /* высота */
  border-radius: 19px; /* радиус скругления */
  background: #bfbfbf; /* цвет фона */
  z-index: 0;
  margin: 0;
  padding: 0;
  border: none;
  cursor: pointer;
  position: relative;
  transition-duration: 300ms; /* анимация */
}
.switch-btn::after {
  content: "";
  height: 32px; /* высота кнопки */
  width: 32px; /* ширина кнопки */
  border-radius: 17px;
  background: #fff; /* цвет кнопки */
  top: 3px; /* положение кнопки по вертикали относительно основы */
  left: 3px; /* положение кнопки по горизонтали относительно основы */
  transition-duration: 300ms; /* анимация */
  position: absolute;
  z-index: 1;
}
.switch-on {
  background: #118c4e;
}
.switch-on::after {
  left: 37px;
}

Дизайн переключателя с квадратной кнопкой

Дизайн переключателя с квадратной кнопкой
CSS
.switch-btn {
  display: inline-block;
  width: 72px; /* ширина */
  height: 38px; /* высота */
  background: #bfbfbf; /* цвет фона */
  z-index: 0;
  margin: 0;
  padding: 0;
  border: none;
  cursor: pointer;
  position: relative;
  transition-duration: 300ms; /* анимация */
}
.switch-btn::after {
  content: "";
  height: 32px; /* высота кнопки */
  width: 32px; /* ширина кнопки */
  background: #fff; /* цвет кнопки */
  top: 3px; /* положение кнопки по вертикали относительно основы */
  left: 3px; /* положение кнопки по горизонтали относительно основы */
  transition-duration: 300ms; /* анимация */
  position: absolute;
  z-index: 1;
}
.switch-on {
  background: #118c4e;
}
.switch-on::after {
  left: 37px;
}

Дизайн переключателя с градиентом

Дизайн переключателя с градиентом
CSS
.switch-btn {
  display: inline-block;
  width: 72px; /* ширина */
  height: 38px; /* высота */
  background: #bfbfbf; /* цвет фона */
  z-index: 0;
  margin: 0;
  padding: 0;
  border: none;
  cursor: pointer;
  position: relative;
  transition-duration: 300ms; /* анимация */
}
.switch-btn::after {
  content: "";
  height: 32px; /* высота кнопки */
  width: 32px; /* ширина кнопки */
  background: #fff; /* цвет кнопки */
  top: 3px; /* положение кнопки по вертикали относительно основы */
  left: 3px; /* положение кнопки по горизонтали относительно основы */
  transition-duration: 300ms; /* анимация */
  position: absolute;
  z-index: 1;
}
.switch-on {
  background: #118c4e;
}
.switch-on::after {
  left: 37px;
}

JavaScript код для переключателя

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

HTML
<script>
$('.switch-btn').click(function(){
  $(this).toggleClass('switch-on');
});
</script>

Но, чтобы было более удобно выполнять некоторые действия при изменении состояния переключателя, в js желательно добавить генерацию событий.

HTML
<script>
$('.switch-btn').click(function(){
  $(this).toggleClass('switch-on');
  if ($(this).hasClass('switch-on')) {
    $(this).trigger('on.switch');
  } else {
    $(this).trigger('off.switch');
  }
});
</script>

Событие on.switch будет возникать при перемещении ползунка переключателя в положение включено, а off.switch – в выключено.

Пример работы с событиями:

HTML
$('.switch-btn').on('on.switch', function(){
  console.log('Кнопка переключена в состояние on');
});
$('.switch-btn').on('off.switch', function(){
  console.log('Кнопка переключена в состояние off');
});

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

HTML
<script>
$(function(){
  $('.switch-btn').click(function (e, changeState) {
    if (changeState === undefined) {
      $(this).toggleClass('switch-on');
    }
    if ($(this).hasClass('switch-on')) {
      $(this).trigger('on.switch');
    } else {
      $(this).trigger('off.switch');
    }
  });

  $('.switch-btn').on('on.switch', function(){
    console.log('Кнопка переключена в состояние on');
  });

  $('.switch-btn').on('off.switch', function(){
    console.log('Кнопка переключена в состояние off');
  });

  $('.switch-btn').each(function(){
    $(this).triggerHandler('click', false);
  });

});
</script>

Финальный пример с двумя переключателями, каждый из которых управляет видимостью определенного блока:

HTML
<!-- Два переключателя -->
<div class="switch-btn" data-id="#bl-1" style="margin: 10px;"></div>
<div class="switch-btn switch-on" data-id="#bl-2" style="margin: 10px;"></div>

<!-- Два элемента, первый переключатель управляет видимостью первого элемента, а второй - второго -->
<div id="bl-1" class="bl-hide" style="height: 20px; margin: 10px; background: orange;"></div>
<div id="bl-2" style="height: 20px; margin: 10px; background: lime;"></div>

...

<script>
  $(function () {
    $('.switch-btn').click(function () {
      $(this).toggleClass('switch-on');
      if ($(this).hasClass('switch-on')) {
        $(this).trigger('on.switch');
      } else {
        $(this).trigger('off.switch');
      }
    });
    $('.switch-btn').on('on.switch', function () {
      $($(this).attr('data-id')).removeClass('bl-hide');
    });
    $('.switch-btn').on('off.switch', function () {
      $($(this).attr('data-id')).addClass('bl-hide');
    });
  });
</script>

Комментарии: 17

DMIKA
DMIKA

Здравствуйте. Мой вопрос немного не по статье, за что прошу прощения (в том плане что не этот код используется), а js я не знаю (не дошел до него). Я нашел себе этот переключатель тем (https://codepen.io/pwadev/pen/xxqogKr), встроил к себе в верстку, переключение тем работает на текущей странице нормально (при обновлении тема не сбрасывается), но стоит перейти на другую страницу по ссылке - то все, значение стоит по умолчанию (темная). И да, для понимания я верстаю локально , т.е. страницы (7шт на текущий момент, 7 файлов .html и 1 файл .css) открываю в браузере по ссылке file:///... , без подключения локальных серверов или подключения сайта к инету (домен и прочее). В каждую страницу добавлен переключатель. Как я понимаю из своей ситуации (моя мысля), я скорее всего по сути загружаю как бы отдельный сайт (то бишь страницу), поэтому для каждой страницы и стоит по умолчанию темная, т.е. страницы мои как бы не связанны вместе, хоть и переключатель везде стоит на них; ну или код не корректен или я дурак.

Помогите пожалуйста! Или как в вашем примере в статье сделать переключение тем (светлая и темная)?
DMIKA
DMIKA

а не, ответ нашел: Да, если вы разместите свой сайт на веб-сервере (с локальным сервером или на реальном хостинге с доменом), то проблема сохранения состояния темы в localStorage решится. Это происходит потому, что localStorage привязан к домену, и он будет общим для всех страниц вашего сайта на этом домене. Таким образом, состояние темы будет сохраняться между страницами даже после перезагрузки.

При использовании локальных файлов (как вы делали с "file:///..."), каждая страница рассматривается браузером как отдельный домен, поэтому localStorage не общий между ними.

Итак, чтобы сохранить состояние темы между страницами, вам потребуется разместить свой сайт на веб-сервере с доменом или использовать локальный сервер (например, Open Server), который симулирует работу сервера и позволяет вам работать с сайтом так, как будто он находится в интернете.

Александр Мальцев
Александр Мальцев

Добрый день!

Если пользуетесь Visual Studio Code или каким-то другим редактором, то в большинстве это можно решить намного проще (через расширение). Например, можно установить Live Server.

Обычно не открываю файлы так как описали, всегда использую какой-то сервер. Решил проверить это утверждение. Добавил в один файл установку некоторого значения в LocalStorage: localStorage.setItem('a', 'a'). Открыл её отдельно с помощью Chrome. Потом другую страницу, значение есть. То есть Origin у них один, это file://. Как в других браузерах не проверял. Поэтому в Chrome должно это работать и так, без сервера.

Если нужен пример с переключением тем, то могу сделать.

DMIKA
DMIKA

Благодарю за отклик на мою проблему. Свой вопрос я решил уже, путем закидывания своих страниц на GitHub Pages (ну и там все корректно работает; вообщем сам дурак + еще кипишь развел... эх). Проблема действительно была в не связанности страниц между собой под одним доменом (локальным или реальным). За подсказку насчет расширения - спасибо, в эту сторону я и не думал даже, а юзаю и вправду VScode.

DMIKA
DMIKA

Вопрос такой, можете сделать из этого кода (https://codepen.io/pwadev/pen/xxqogKr) переключатель для трех тем?) к примеру темная, светлая и пергамент.

Александр Мальцев
Александр Мальцев

В примере работа переключателя основана на чекбоксе <input type="checkbox">. Чекбокс имеет 2 состояния, а тут нужно три. Для этого случая это нужно организовать как-то по-другому. Например, сделать это просто на JavaScript.

Igorrr_2022
Igorrr_2022
Добрый день, имеются вложенные табы, при перезагрузке страницы все сбрасывается до таба 1-го уровня, хотелось бы чтоб при перезагрузке открывался последний таб (вложенный). Благодарю за помощь!
Вот код:
<ul class="nav nav-tabs" id="myTab" role="tablist">
        <li class="nav-item">
            <a class="nav-link " id="home-tab" data-toggle="tab" href="#home" role="tab" aria-controls="home" aria-selected="true">Home</a>
        </li>
    </ul>
    <div class="tab-content" id="myTabContent">
        <div class="tab-pane fade" id="home" role="tabpanel" aria-labelledby="home-tab">

            <ul class="nav nav-tabs" id="myTab" role="tablist">
                <li class="nav-item">
                    <a class="nav-link " id="profile-tab" data-toggle="tab" href="#profile" role="tab" aria-controls="profile" aria-selected="true">Profile</a>
                </li>
            </ul>

            <div class="tab-content" id="myTabContent">
                <div class="tab-pane fade" id="profile" role="tabpanel" aria-labelledby="profile-tab"> Profile </div>

        </div>
     </div>
<script>
    $(function() {
        $('[data-toggle="tab"]').on('shown.bs.tab', function () {
            window.location.hash = '_' + $(this).attr('id');
        });
        if (window.location.hash) {
            $('[id="' + window.location.hash.substr(2) + '"]').trigger('click');
        } else {
            $('[data-toggle="tab"]:first').tab('show');
        }
        $(window).on('hashchange', function() {
            $('[id="' + window.location.hash.substr(2) + '"]').trigger('click');
        });
    });
</script>
deus
deus
Добрый день. Можете подсказать пожалуйста как сделать похожий переключатель как тут: napas-project.ru/privileges/ze
Чтобы он переключатель между такими таблицами + выбор кнопки. Благодарю.
Андрей
Андрей
Подскажите, а как сделать 1 переключатель, но чтобы в одном положении отображался один блок, а в другом — другой?
Александр Мальцев
Александр Мальцев
Тут всё просто. В выключенном положении включаете отображение 1-ого блока и выключаете 2-ого. В включенном — наоборот.
Например:
$('#switch-btn-1').click(function () {
  $(this).toggleClass('switch-on');
  if ($(this).hasClass('switch-on')) {
    $(this).trigger('on.switch');
  } else {
    $(this).trigger('off.switch');
  }
});
$('#switch-btn-1').on('on.switch', function () {
  $('#block-1').addClass('bl-hide');
  $('#block-2').removeClass('bl-hide');
});
$('.switch-btn').on('off.switch', function () {
  $('#block-1').removeClass('bl-hide');
  $('#block-2').addClass('bl-hide');
});
Пример в песочнице доступен по этой ссылке.
Егор
Егор
Самый нижний пример, только видоизменил, работает, но не знаю насколько правильно сделал.

	$(function () {
		$('.switch-btn').click(function () {
			$(this).toggleClass('switch-on');
			if ($(this).hasClass('switch-on')) {
				$(this).trigger('on.switch');
			} else {
				$(this).trigger('off.switch');
			}
		});
		$('.switch-btn').on('on.switch', function () {
			$('.price-norm').addClass('price-hide');
			$('.price-sell').removeClass('price-hide');
		});
		$('.switch-btn').on('off.switch', function () {
			$('.price-sell').addClass('price-hide');
			$('.price-norm').removeClass('price-hide');
		});
	});
Александр Мальцев
Александр Мальцев
Синтаксически всё правильно.
Егор
Егор
Здравствуйте, спасибо, нужно было сделать переключатель цен в таблице со скидкой и без, как раз то, что нужно.
Александр Мальцев
Александр Мальцев
Привет! Рад, что данный переключатель помог.
Elvis
Elvis
Александр, здравствуйте! Спасибо за переключатель, мне тоже нужен один для смены языка на странице. Понимаю, что, скорей всего, смена языка другим способом должна быть реализована, но можете подсказать как сохранить выбранный режим после перезагрузки страницы или переходу на другую страничку внутри сайта, если использовать для этого метод переключения указанный в данной статье?
Александр Мальцев
Александр Мальцев
Добрый день! Пожалуйста! Вы куда его хотите сохранить? В куки, LocalStorage и какое-то другое место?
Elvis
Elvis
Тут у меня синий экран смерти в голове возник… Я вообще просто два текста в html разметке написал — один на английском, второй на русском и переключателем добавлял display none. Где это должно храниться я не думал. Но теперь догоняю, что тексту где-то надо храниться чтобы было откуда подгружать после обновления странички.