Табы (вкладки) для сайта на CSS и JavaScript – 3 способа

Александр Мальцев
Александр Мальцев
58K
50
Табы (вкладки) для сайта на CSS и JavaScript – 3 способа
Содержание:
  1. Что такое табы
  2. Вкладки на чистом CSS
  3. Табы с использованием JavaScript
  4. Комментарии

В этой статье рассмотрим примеры вкладок для сайта, выполненных как с использованием только CSS, так и с применением JavaScript.

Что такое табы

На странице очень часто бывает необходимо вывести большое количество информации.

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

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

В вебе табы – это просто набор ссылок или других HTML элементов, которые визуально можно представить по-разному: в виде вкладок, группы кнопок и другими способами. По сути, они просто включают видимость какого-то одного блока с контентом, скрывая при этом другие.

Табы предназначены для экономии места и более удобного представления информации на сайте (по названию вкладки можно определить какой контент отобразится на странице, если нажать на неё).

Вкладки на чистом CSS

Рассмотрим несколько способов создания табов на CSS.

Первый способ построен на радиокнопках (input с type="radio") и CSS селекторе checked.

HTML и CSS код таба:

<style>
.tabs {
font-size: 0;
}

.tabs>input[type="radio"] {
display: none;
}

.tabs>div {
/* скрыть контент по умолчанию */
display: none;
border: 1px solid #e0e0e0;
padding: 10px 15px;
font-size: 16px;
}

/* отобразить контент, связанный с вабранной радиокнопкой (input type="radio") */
#tab-btn-1:checked~#content-1,
#tab-btn-2:checked~#content-2,
#tab-btn-3:checked~#content-3 {
display: block;
}

.tabs>label {
display: inline-block;
text-align: center;
vertical-align: middle;
user-select: none;
background-color: #f5f5f5;
border: 1px solid #e0e0e0;
padding: 2px 8px;
font-size: 16px;
line-height: 1.5;
transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out;
cursor: pointer;
position: relative;
top: 1px;
}

.tabs>label:not(:first-of-type) {
border-left: none;
}

.tabs>input[type="radio"]:checked+label {
background-color: #fff;
border-bottom: 1px solid #fff;
}
</style>

<div class="tabs">
<input type="radio" name="tab-btn" id="tab-btn-1" value="" checked>
<label for="tab-btn-1">Вкладка 1</label>
<input type="radio" name="tab-btn" id="tab-btn-2" value="">
<label for="tab-btn-2">Вкладка 2</label>
<input type="radio" name="tab-btn" id="tab-btn-3" value="">
<label for="tab-btn-3">Вкладка 3</label>

<div id="content-1">
  Содержимое 1...
</div>
<div id="content-2">
  Содержимое 2...
</div>
<div id="content-3">
  Содержимое 3...
</div>
</div>
Табы для сайта на чистом CSS

Посмотреть

В этом варианте радиокнопки связаны с определённым label. Связь элемента label с input выполнена через атрибут for. Это действие необходимо для того, чтобы можно было скрыть элементы input, а управление ими (установку checked) выполнять через клики по элементам label.

Стилизация выбранного элемента label в этом примере выполнена с использованием селектора input[type="radio"]:checked+label. Этот селектор выбирает элемент label, который расположен сразу же после элемента input[type="radio"], находящимся в состоянии checked.

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

#tab-btn-1:checked~#content-1,
#tab-btn-2:checked~#content-2,
#tab-btn-3:checked~#content-3 {
display: block;
}

Отобразить вкладки можно по-разному. В следующем примере они визуально отображаются как кнопки.

CSS код для создания адаптивных вкладок в виде кнопок:

.tabs>input[type="radio"] {
display: none;
}

.tabs>input[type="radio"]:checked+label {
background-color: #bdbdbd;
}

.tabs>div {
/* скрыть контент по умолчанию */
display: none;
border: 1px solid #eee;
padding: 10px 15px;
border-radius: 4px;
}

/* отобразить контент, связанный с вабранной радиокнопкой (input type="radio") */
#tab-btn-1:checked~#content-1,
#tab-btn-2:checked~#content-2,
#tab-btn-3:checked~#content-3 {
display: block;
}

.tabs>label {
display: inline-block;
text-align: center;
vertical-align: middle;
user-select: none;
background-color: #eee;
border: 1px solid transparent;
padding: 2px 8px;
font-size: 16px;
line-height: 1.5;
border-radius: 4px;
transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out;
margin-right: 6px;
cursor: pointer;
margin-bottom: 10px;
}

.tabs>label:first-of-type {
margin-left: 0;
}
Табы для сайта на чистом CSS

Посмотреть

В этом примере вкладки визуально представлены в виде хэштегов:

.tabs>input[type="radio"] {
display: none;
}

.tabs>input[type="radio"]:checked+label {
font-weight: bold;
cursor: default;
}

.tabs>div {
display: none;
border-top: 1px solid #eee;
padding: 10px 15px;
}

#tab-btn-1:checked~#content-1,
#tab-btn-2:checked~#content-2,
#tab-btn-3:checked~#content-3 {
display: block;
}

.tabs>label {
display: inline-block;
text-align: center;
vertical-align: middle;
user-select: none;
padding: 2px 8px;
font-size: 14px;
line-height: 1.5;
transition: color 0.15s ease-in-out;
margin-left: 6px;
cursor: pointer;
margin-bottom: 4px;
}

.tabs>label:first-of-type {
margin-left: 0;
}
Табы для сайта на чистом CSS

Посмотреть

Второй способ основывается на использовании псевдокласса :target.

Пример HTML и CSS кода для создания адаптивных вкладок, механизм работы которых организован через :target:

<style>
.tabs {
  display: flex;
  flex-direction: column;
}

.tabs__links {
  display: flex;
  width: 100%;
  overflow-x: auto;
  overflow-y: hidden;
  margin-left: auto;
  margin-right: auto;
  margin-bottom: 10px;
  order: 0;
  white-space: nowrap;
  background-color: #fff;
  border: 1px solid #e3f2fd;
  box-shadow: 0 2px 4px 0 #e3f2fd;
}

.tabs__links>a {
  display: inline-block;
  text-decoration: none;
  padding: 6px 10px;
  text-align: center;
  color: #1976d2;
}

.tabs__links>a:hover {
  background-color: rgba(227, 242, 253, 0.3);
}

.tabs>#content-1:target~.tabs__links>a[href="#content-1"],
.tabs>#content-2:target~.tabs__links>a[href="#content-2"],
.tabs>#content-3:target~.tabs__links>a[href="#content-3"] {
  background-color: #bbdefb;
  cursor: default;
}

.tabs>div:not(.tabs__links) {
  display: none;
  order: 1;
}

.tabs>div:target {
  display: block;
}
</style>

<div class="tabs">
<div id="content-1">
  Содержимое 1...
</div>
<div id="content-2">
  Содержимое 2...
</div>
<div id="content-3">
  Содержимое 3...
</div>

<div class="tabs__links">
  <a href="#content-1">Вкладка 1</a>
  <a href="#content-2">Вкладка 2</a>
  <a href="#content-3">Вкладка 3</a>
</div>
</div>
Табы для сайта на чистом CSS

Посмотреть

Логика этих табов основана на следующих моментах. Первый момент заключается в добавлении хэша к URL-адресу страницы при нажатии на ссылку (вкладку). Второй – это стилизация элементов, выбор которых осуществляется в зависимости от хэша в URL-адресе. Выбрать элемент, идентификатор которого соответствует хэшу в URL-адресе в CSS можно выполнить посредством псевдокласса :target. С помощью него мы можем написать селектор не только для получения элемента, на который он указывает, но и для выбора других элементов, которые каким-то определённым образом связаны с ним.

Например, выбрать вкладку, которая должна быть активной для элемента на который указывает :target можно так:

.tabs>#content-1:target~.tabs__links>a[href="#content-1"],
.tabs>#content-2:target~.tabs__links>a[href="#content-2"],
.tabs>#content-3:target~.tabs__links>a[href="#content-3"] {
background-color: #bbdefb;
cursor: default;
}

В зависимости от дизайна проекта табы можно визуально представить так, как вам это нужно.

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

.tabs {
display: flex;
flex-direction: column;
}

.tabs__links {
display: flex;
flex-direction: row;
order: 0;
white-space: nowrap;
margin-bottom: 15px;
background-color: #fff;
border: 1px solid #e3f2fd;
box-shadow: 0 2px 4px 0 #e3f2fd;
}

.tabs__links>a {
display: inline-block;
text-decoration: none;
color: #1976d2;
padding: 6px 10px;
text-align: center;
}

.tabs__links>a:hover {
background-color: rgba(227, 242, 253, 0.3);
}

.tabs>#content-1:target~.tabs__links>a[href="#content-1"],
.tabs>#content-2:target~.tabs__links>a[href="#content-2"],
.tabs>#content-3:target~.tabs__links>a[href="#content-3"] {
background-color: #bbdefb;
cursor: default;
}

.tabs>div:not(.tabs__links) {
display: none;
order: 1;
flex-grow: 1;
}

@media (min-width: 576px) {
.tabs {
  flex-direction: row;
}

.tabs__links {
  flex-direction: column;
  border: none;
  box-shadow: none;
}

.tabs__links>a {
  border: 1px solid #e3f2fd;
  box-shadow: 0 2px 4px 0 #e3f2fd;
  margin-bottom: 8px;
}

.tabs__links>a:last-child {
  margin-bottom: 0;
}

.tabs>div:not(.tabs__links) {
  padding-left: 15px;
}
}

.tabs>div:target {
display: block;
}
Табы для сайта на чистом CSS

Посмотреть

При этом табы отображаются вертикально только на больших экранах, а на маленьких (мобильных) они отображаются горизонтально. Адаптивность табов в коде реализуется с помощью медиа-запросов.

Табы с использованием JavaScript

В этом разделе разберём как можно создать табы на чистом JavaScript (без использования библиотеки jQuery).

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

HTML и CSS код вкладок:

<style>
.tabs {
  border: 1px solid lightgray;
}

.tabs__nav {
  display: flex;
  flex-wrap: wrap;
  list-style-type: none;
  background: #f8f8f8;
  margin: 0;
  border-bottom: 1px solid lightgray;
}

.tabs__link {
  padding: 0.5rem 0.75rem;
  text-decoration: none;
  color: black;
  text-align: center;
  flex-shrink: 0;
  flex-grow: 1;
}

.tabs__link_active {
  background: lightgray;
  cursor: default;
}

.tabs__link:not(.tabs__link_active):hover,
.tabs__link:not(.tabs__link_active):focus {
  background-color: #efefef;
}

.tabs__content {
  padding: 1rem;
}

.tabs__pane {
  display: none;
}

.tabs__pane_show {
  display: block;
}
</style>

<div class="tabs">
<div class="tabs__nav">
  <a class="tabs__link tabs__link_active" href="#content-1">Вкладка 1</a>
  <a class="tabs__link" href="#content-2">Вкладка 2</a>
  <a class="tabs__link" href="#content-3">Вкладка 3</a>
</div>
<div class="tabs__content">
  <div class="tabs__pane tabs__pane_show" id="content-1">
    Содержимое 1...
  </div>
  <div class="tabs__pane" id="content-2">
    Содержимое 2...
  </div>
  <div class="tabs__pane" id="content-3">
    Содержимое 3...
  </div>
</div>
</div>

JavaScript код:

var $tabs = function (target) {
var
  _elemTabs = (typeof target === 'string' ? document.querySelector(target) : target),
  _eventTabsShow,
  _showTab = function (tabsLinkTarget) {
    var tabsPaneTarget, tabsLinkActive, tabsPaneShow;
    tabsPaneTarget = document.querySelector(tabsLinkTarget.getAttribute('href'));
    tabsLinkActive = tabsLinkTarget.parentElement.querySelector('.tabs__link_active');
    tabsPaneShow = tabsPaneTarget.parentElement.querySelector('.tabs__pane_show');
    // если следующая вкладка равна активной, то завершаем работу
    if (tabsLinkTarget === tabsLinkActive) {
      return;
    }
    // удаляем классы у текущих активных элементов
    if (tabsLinkActive !== null) {
      tabsLinkActive.classList.remove('tabs__link_active');
    }
    if (tabsPaneShow !== null) {
      tabsPaneShow.classList.remove('tabs__pane_show');
    }
    // добавляем классы к элементам (в завимости от выбранной вкладки)
    tabsLinkTarget.classList.add('tabs__link_active');
    tabsPaneTarget.classList.add('tabs__pane_show');
    document.dispatchEvent(_eventTabsShow);
  },
  _switchTabTo = function (tabsLinkIndex) {
    var tabsLinks = _elemTabs.querySelectorAll('.tabs__link');
    if (tabsLinks.length > 0) {
      if (tabsLinkIndex > tabsLinks.length) {
        tabsLinkIndex = tabsLinks.length;
      } else if (tabsLinkIndex < 1) {
        tabsLinkIndex = 1;
      }
      _showTab(tabsLinks[tabsLinkIndex - 1]);
    }
  };

_eventTabsShow = new CustomEvent('tab.show', { detail: _elemTabs });

_elemTabs.addEventListener('click', function (e) {
  var tabsLinkTarget = e.target;
  // завершаем выполнение функции, если кликнули не по ссылке
  if (!tabsLinkTarget.classList.contains('tabs__link')) {
    return;
  }
  // отменяем стандартное действие
  e.preventDefault();
  _showTab(tabsLinkTarget);
});

return {
  showTab: function (target) {
    _showTab(target);
  },
  switchTabTo: function (index) {
    _switchTabTo(index);
  }
}

};

$tabs('.tabs');
Адаптивные вкладки на CSS и JavaScript

Посмотреть

Инициализация табов на странице осуществляется с помощью вызова функции $tabs и передаче ей в качестве аргумента CSS селектора или DOM-элемента, содержащего вкладки:

$tabs('.tabs');

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

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

var listTabs = document.querySelectorAll('.tabs');
for (var i = 0, length = listTabs.length; i < length; i++) {
$tabs(listTabs[i]);
}

Кроме этого, если результат вызова функции $tabs сохранить в переменную, то можно использовать методы, которые она представляет.

Например:

var tabs1 = $tabs('.tabs');
// программно переключиться на 2 вкладку (2 – номер вкладки, на которую нужно перейти)
tabs1.switchToTab(2);

Примеры

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

...
var mytabs = $tabs('.tabs');
if (localStorage.getItem('mytabs')) {
mytabs.showTab(document.querySelector('[href="' + localStorage.getItem('mytabs') + '"]'));
}

document.addEventListener('tab.show', function (e) {
localStorage.setItem('mytabs', e.detail.querySelector('.tabs__link_active').getAttribute('href'));
});

2. Пример синхронизации вкладок на разных открытых страницах, относящихся к одному источнику (через LocalStorage):

window.onstorage = function (e) {
mytabs.showTab(document.querySelector('[href="' + e.newValue + '"]'));
};

3. Пример, в котором показано как на одной странице можно вывести несколько табов с сохранением их состояний (активных вкладок) в LocalSorage:

<div class="tabs" id="tabs-1">...</div>
<div class="tabs" id="tabs-2">...</div>

<script>
var
nameKey = 'mytabs2',
mytabs = {},
mytabsStorage = {},
listTabs = document.querySelectorAll('.tabs');

for (var i = 0, length = listTabs.length; i < length; i++) {
if (listTabs[i].id) {
  mytabs[listTabs[i].id] = $tabs(listTabs[i]);
}
}
if (localStorage.getItem(nameKey)) {
mytabsStorage = JSON.parse(localStorage.getItem(nameKey));
for (var key in mytabsStorage) {
  if (mytabs.hasOwnProperty(key)) {
    mytabs[key].showTab(document.querySelector('[href="' + mytabsStorage[key] + '"]'));
  }
}
}
document.addEventListener('tab.show', function (e) {
mytabsStorage[e.detail.closest('.tabs').getAttribute('id')] = e.detail.querySelector('.tabs__link_active').getAttribute('href');
localStorage.setItem(nameKey, JSON.stringify(mytabsStorage));
})
</script>

4. Табы, содержащие видео с YouTube. При переходе на другую вкладку будет приостанавливаться воспроизведение текущего видеофайла.

Табы, содержащие YouTube видео

Контент вкладок:

<div class="tabs__content">
  <div class="tabs__pane tabs__pane_show" id="content-1">
    <!-- Контент 1 вкладки -->
    <div class="iframe">
      <div class="player" id="player-1" data-video-id="5NTvXKUXEX4" data-width="560" data-height="315"></div>
    </div>
  </div>
  <div class="tabs__pane" id="content-2">
    <!-- Контент 2 вкладки -->
    <div class="iframe">
      <div class="player" id="player-2" data-video-id="Cy35h6DF8hY" data-width="560" data-height="315"></div>
    </div>
  </div>
  <div class="tabs__pane" id="content-3">
    <!-- Контент 3 вкладки -->
    <div class="iframe">
      <div class="player" id="player-3" data-video-id="6tyB97J1cVA" data-width="560" data-height="315"></div>
    </div>
  </div>
</div>

Во элементах .player атрибут data-video-id определяет videoId ролика, а data-width и data-height - ширину и высоту iframe.

Загрузку API IFrame Player будем выполнять асинхронно. Для этого напишем следующий код:

const tag = document.createElement('script');
tag.src = "https://www.youtube.com/iframe_api";
const firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);

Создание <iframe> и проигрывателя YouTube будем выполнять после загрузки кода API посредством функции onYouTubeIframeAPIReady:

const players = {};
function onYouTubeIframeAPIReady() {
  for (let i = 0, length = document.querySelectorAll('.player').length; i < length; i++) {
    const player = document.querySelectorAll('.player')[i];
    players[player.id] = new YT.Player(player.id, {
      height: player.dataset.height,
      width: player.dataset.width,
      videoId: player.dataset.videoId
    });
  }
}

Приостанавливает воспроизведение видео будем посредством метода pauseVideo, а выполнять это после переключения вкладки (используя для этого событие tab.show):

document.addEventListener('tab.show', function (e) {
  const from = e.detail.from;
  if (from) {
    const player = from.querySelector('.player');
    if (player) {
      players[player.id].pauseVideo();
    }
  }
});

Открыть пример

Описание исходного JavaScript кода

Исходный JavaScript код состоит из функции $tabs. Внутри этой функции имеется переменная _elemTabs и функции _showTab, _switchTabTo. Переменная _elemTabs хранит DOM-элемент, предоставляющий собой контейнер с вкладками. Метод _showTab предназначен для скрытия текущей (активной) вкладки и отображения другой в зависимости от переданной ему ссылки. Метод _switchTabTo используется для переключения вкладки по её порядковому номеру. Установка обработчиков событий для вкладок определяется с помощью addEventListener и выполняется в момент вызова $tabs.

Вне функции доступен только методы showTab и switchTabTo. Первый метод позволяет программно перейти на вкладку через передачу ему ссылки на DOM-элемент (ссылки), а второй - по её порядковому номеру.

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

  1. Primerio
    12 июля 2021, 13:00
    Есть баг с табами, если рядом с названием вкладки будет картинка, про нажатие на нее таб не открывается, только если нажать на текст
    1. Alex Maker
      31 мая 2021, 13:18
      Здравствуйте, скажите что из выше перечисленного может помочь в решении моей проблемы?
      Есть табы с категориями, в каждой из категорий есть табы с товаром, переключение между категориями и товарами написано на чистом Javascript, а теперь проблема. Необходимо чтобы по ссылке с другой страницы открывалась необходимая категория и товар. Дайте пример пожалуйста, я не силен в js((
      1. Олег
        19 мая 2021, 09:42
        Доброго времени суток друзья.
        Очень интересные и полезные примеры работы скриптов, но к сожалению для решения свой задачи ничего подходящего не нашёл.
        Возможно похожее есть решение с синхронизацией табов на разных страница как на примере itchief.ru/examples/lab.php?topic=javascript&file=tabs-v3, но немного не то что надо.
        Александр, может Вы как мастер сможете помочь с реализацией моей задачи.
        У меня на сайте есть 2 отдельный блока div.
        В одном блоке содержится информация от квадроциклах, те. Есть цена и характеристики, а во втором блоке есть табы, в которых есть информация о предоставляемых услугах, в каждом табе разная услуга.
        Зада состоит в том, чтобы при клике на каждом табе справа менялась цена.
        Например:
        Клик по табу №1 справа менялась цена в левом блоке и так при нажатии на каждый таб. пример на картинке


        Буду очень признателен за помощь.
        1. Siarhei
          14 апреля 2021, 15:26
          То что надо. Спасибо автору большое!
          Ребят. Использую Табы с использованием JavaScript. Главный код сначала в посте. Без дополнений.

          У меня важный вопрос:
          У меня табы с плеерами (iframe).
          Так вот, как остановить подзагрузку и воспроизведение видео, при переходе на другую вкладку.
          А то открываю другую, а на первой идет все и не останавливается. И соответственно грузятся сразу все вкладки.


          Если бы разрешить загружать основную только, а остальные при переключении, останавливая первую…

          Заранее благодарю, если есть решение!
          1. Александр Мальцев
            20 апреля 2021, 09:23
            Пожалуйста!
            Добавил в статью пример табов, содержащие YouTube видео. При переключении видео приостанавливается.
            Открыть пример
            1. Siarhei
              30 апреля 2021, 20:05
              Просто красавчик!
              Спасибо огромное!!!
          2. Александр Сидоров
            01 апреля 2021, 14:58
            Добрый день Александр!

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

            — листающийся слайдер с категориями товара;
            — ниже блок с первым товаром из выбранной категории товаров и в этом блоке без перезагрузки страницы можно выбрать другой товар (торговое предложение по типу SKU битрикс), с другой ценой и например расцветкой, но относящийся к основному товару.
            Меняются фото, цена и описание.

            Пример блока:
            prnt.sc/10xv629
            sklad-kuhni.moscow/

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

            Как копать в сторону аякса — это тоже на данный момент по знаниям проблематично…
            1. Дмитрий
              19 марта 2021, 17:10
              Здравствуйте! Подскажите как сделать несколько блоков с табами на одной странице их мне нужно 4 (https://itchief.ru/assets/uploadify/9/8/8/9889f32d8a70fb4e1dc8bd505ace4887.jpg). Пробую вариант с отображением как кнопки. У меня только две вкладки, в каждом блоке разное содержание, название вкладок одинаковое.
              1. Александр Мальцев
                20 марта 2021, 15:14
                Привет! Связывание вкладок с содержимым выполняется через id, название может быть любым. Тут всё просто, проблем не должно быть. Как сделать: пример.
                1. Дмитрий
                  21 марта 2021, 07:49
                  Просто огромное спасибо, все работает как надо.
              2. ofam
                15 декабря 2020, 06:12
                Здравствуйте.
                Подскажите, пожалуйста, как реализовать возможность переключения сразу нескольких табов кнопкой?
                Для примера: у меня 5 блоков, в каждом по 2 вкладке. Над ними 2 кнопки, которые должны переключить сразу все табы.
                1. Александр Мальцев
                  17 декабря 2020, 13:24
                  Привет!
                  Можно например так (открыть пример):
                  <!-- Добавить к кнопкам или ссылкам атрибут data-switch-to, в котором указать номер открываемых вкладок для табов -->
                  <a href="#" data-switch-to="1">1</a>
                  <a href="#" data-switch-to="2">2</a>
                  
                  <script>
                  // ...
                  // массив, в который будем помещать табы
                  let tabs = [];
                  // переберём все табы, инициализируем их, и поместим результат в массив tabs
                  document.querySelectorAll('.tabs').forEach(function ($element) {
                    tabs.push($tabs($element));
                  });
                  
                  // при клике будем определять имеет ли цель data-switch-to и если да, то выполнять переключение вкладок
                  document.onclick = function (e) {
                    if (e.target.dataset.switchTo) {
                      e.preventDefault();
                      // получим номер вкладки
                      const index = +e.target.dataset.switchTo;
                      // переберём все табы
                      tabs.forEach(function ($tab) {
                        // переключим вкладку на нужную
                        $tab.switchTabTo(index);
                      })
                    }
                  }
                  </script>
                2. Илья
                  05 декабря 2020, 18:02
                  А как сделать кнопку «Добавить новую вкладку»? К примеру, чтобы скопировало содержание вкладки с чистым независимым input от копируемой вкладки
                  1. Александр Мальцев
                    06 декабря 2020, 16:15
                    Лучше наверно не копировать, а самостоятельно определять контент, например, с помощью функции getTabsPaneContent.
                    Для этого необходимо (открыть пример):
                    1. Добавить кнопку:
                    <button id="add-new-tab" type="button">Добавить новую вкладку:</button>
                    
                    2. Создать функцию getTabsPaneContent, которая должна будет возвращать то, что мы хотим увидеть в новой вкладке:
                    <code>const getTabsPaneContent = (counter) => {
                      return `<div class="tabs__pane" id="content-${counter}">
                          <p>Содержимое ${counter}...</p>
                          <input type="text" id="content-${counter}-input" value="">
                        </div>`;
                    }
                    3. Получить в JavaScript саму кнопку и привязать к ней обработчик события click, который будет добавлять новую вкладку с контентом, определяемым функцией getTabsPaneContent:
                    const $addNewTab = document.querySelector('#add-new-tab');
                    $addNewTab.onclick = function () {
                      const $tabsNav = document.querySelector('.tabs__nav');
                      const counter = $tabsNav.children.length + 1;
                      // вставляем новый tabs__link
                      const $tabsLink = `<a class="tabs__link" href="#content-${counter}">Вкладка ${counter}</a>`
                      $tabsNav.insertAdjacentHTML('beforeend', $tabsLink);
                      // вставляем новый tabs__content
                      const $tabsContent = document.querySelector('.tabs__content');
                      $tabsContent.insertAdjacentHTML('beforeend', getTabsPaneContent(counter));
                    }
                  2. Ola
                    05 октября 2020, 18:31
                    Супер! как всегда просто и понятно! Спасибо!
                    1. Александр Мальцев
                      08 октября 2020, 13:19
                      Пожалуйста!
                    2. Владимир
                      26 августа 2020, 18:09
                      еще есть вопросик, при нажатии на вкладку страница прокручивается к началу вкладку сверху alutat.com.ua/ а как отменить это?
                      1. Александр Мальцев
                        02 сентября 2020, 14:19
                        Так вы это реализовали в виде отдельных страниц, а не на одной странице. А новая страница по умолчанию всегда открывается сначала. Чтобы это реализовать, вам нужно дополнительно добавить скрипт на страницу, который будет её прокручивать до этого состояния.
                      2. Владимир
                        19 августа 2020, 18:09
                        Здравствуйте, Александр!

                        Сперва, спасибо за полезную статью )

                        Хочу использовать вот эти вертикальные табы itchief.ru/examples/lab.php?topic=css&file=tabs-v4 <itchief.ru/examples/lab.php?topic=css&file=tabs-v4> на сайте, но не могу решить вопрос с отображением сразу контента первой вкладки. Знаю, что можно страницу itchief.ru/examples/output.php#content-1 <itchief.ru/examples/output.php#content-1> открывать, но они у меня на главной будут сразу и нужно чтобы сразу была активна первая вкладка.

                        Как такое можно реализовать?

                        Буду признателен за ответ.
                        1. Александр Мальцев
                          20 августа 2020, 04:01
                          Здравствуйте! На сколько понимаю вы хотите без JavaScript. На CSS это можно выполнить, если только разместить содержимое вкладки, которая по умолчанию должна быть открытой, после остальных.
                          <div id="content-3">
                            Содержимое 3...
                          <div>
                          <div id="content-2">
                            Содержимое 2...
                          </div>
                          <div id="content-1">
                            Содержимое 1...
                          </div>
                          
                          А также внести необходимые изменения в CSS. Готовый пример можно посмотреть здесь.
                          1. Владимир
                            20 августа 2020, 08:18
                            супер! спасибо большое!
                        2. Nik
                          11 апреля 2020, 20:36
                          Доброго времени Александр! Подскажите как в данном скрипте добавить localStorage или cookie или sessionStorage, чтобы при F5 остаться на той же самой вкладке?
                          1. Александр Мальцев
                            12 апреля 2020, 08:32
                            Привет! Пример как это сделать с помощью localStorage добавил в статью.
                            1. Nik
                              12 апреля 2020, 20:47
                              А для двух табов подряд на странице не работает почему-то, код инициализации сразу всех вкладок делает нерабочим скрипт. Только если убрать один из двух табов, тогда да, сохранение в LocalStorage отрабатывает великолепно!
                              1. Nik
                                13 апреля 2020, 13:28
                                Разобрался, все работает!
                                1. Александр Мальцев
                                  13 апреля 2020, 14:16
                                  Отлично!
                                  1. Nik
                                    13 апреля 2020, 14:30
                                    Правда как-то очень интересно работает))) Пока еще не понял, но вроде «через раз»
                                    1. Александр Мальцев
                                      13 апреля 2020, 14:41
                                      Может что-то не учёл. Пример как это можно сделать для нескольких вкладок в статью добавил.
                                      1. Nik
                                        14 апреля 2020, 02:25
                                        Нашел одну причину, почему скрипт «ломало», банальная невнимательность, лишний раз обернул в дивы tabs, то, что вообще не надо было оборачивать.
                                        Остальные примеры в статье разобрал, проверил на своем сайте, все работает как положено, кроме одного загадочного для меня явления))) Одни табы с одним контентом у меня на одной странице, другие с другим контентом на совершенно другой странице. Футер где скрипт, на всем сайте один и тот же. Табы работают, но допустим в хроме на одной странице с табами вкладка остаётся после F5 которую открыл, на другой local storage не срабатывает. В мозилле наоборот, та которая не работала в хроме, работает. «Мудрый» код скрипта покажу завтра
                                        1. Nik
                                          14 апреля 2020, 02:50
                                          Код скрипта такой:
                                           <script>
                                              var $tabs = function (target) {
                                                var
                                                  _elemTabs = (typeof target === 'string' ? document.querySelector(target) : target),
                                                  _eventTabsShow,
                                                  _showTab = function (tabsLinkTarget) {
                                                    var tabsPaneTarget, tabsLinkActive, tabsPaneShow;
                                                    tabsPaneTarget = document.querySelector(tabsLinkTarget.getAttribute('href'));
                                                    tabsLinkActive = tabsLinkTarget.parentElement.querySelector('.tabs__link_active');
                                                    tabsPaneShow = tabsPaneTarget.parentElement.querySelector('.tabs__pane_show');
                                                    // если следующая вкладка равна активной, то завершаем работу
                                                    if (tabsLinkTarget === tabsLinkActive) {
                                                      return;
                                                    }
                                                    // удаляем классы у текущих активных элементов
                                                    if (tabsLinkActive !== null) {
                                                      tabsLinkActive.classList.remove('tabs__link_active');
                                                    }
                                                    if (tabsPaneShow !== null) {
                                                      tabsPaneShow.classList.remove('tabs__pane_show');
                                                    }
                                                    // добавляем классы к элементам (в завимости от выбранной вкладки)
                                                    tabsLinkTarget.classList.add('tabs__link_active');
                                                    tabsPaneTarget.classList.add('tabs__pane_show');
                                                    document.dispatchEvent(_eventTabsShow);
                                                  },
                                                  _switchTabTo = function (tabsLinkIndex) {
                                                    var tabsLinks = _elemTabs.querySelectorAll('.tabs__link');
                                                    if (tabsLinks.length > 0) {
                                                      if (tabsLinkIndex > tabsLinks.length) {
                                                        tabsLinkIndex = tabsLinks.length;
                                                      } else if (tabsLinkIndex < 1) {
                                                        tabsLinkIndex = 1;
                                                      }
                                                      _showTab(tabsLinks[tabsLinkIndex - 1]);
                                                    }
                                                  };
                                          
                                                _eventTabsShow = new CustomEvent('tab.show', { detail: _elemTabs });
                                          
                                                _elemTabs.addEventListener('click', function (e) {
                                                  var tabsLinkTarget = e.target;
                                                  // завершаем выполнение функции, если кликнули не по ссылке
                                                  if (!tabsLinkTarget.classList.contains('tabs__link')) {
                                                    return;
                                                  }
                                                  // отменяем стандартное действие
                                                  e.preventDefault();
                                                  _showTab(tabsLinkTarget);
                                                });
                                          
                                                return {
                                                  showTab: function (target) {
                                                    _showTab(target);
                                                  },
                                                  switchTabTo: function (index) {
                                                    _switchTabTo(index);
                                                  }
                                                }
                                          
                                              };
                                          //Инициализация всех вкладок иначе не работает
                                          var listTabs = document.querySelectorAll('.tabs');
                                          for (var i = 0, length = listTabs.length; i < length; i++) {
                                            $tabs(listTabs[i]);
                                          }
                                          //Сохраняем в  LocalStorage
                                              var mytabs = $tabs('.tabs');
                                              if (localStorage.getItem('mytabs')) {
                                                mytabs.showTab(document.querySelector('[href="' + localStorage.getItem('mytabs') + '"]'));
                                              }
                                          
                                              document.addEventListener('tab.show', function (e) {
                                                localStorage.setItem('mytabs', e.detail.querySelector('.tabs__link_active').getAttribute('href'));
                                              })
                                              
                                            </script>
                                          
                                          1. Александр Мальцев
                                            14 апреля 2020, 16:36
                                            Так корректно работать не будет. В mytabs будет находится результат вызова функции $tabs('.tabs') для первого таба. Кроме этого в этом случае в LocalStorage нужно сохранять не просто href ссылку, а, например, их в виде некоторого объекта, как в этом примере.
                                            Как этот пример работает? В этом примере к табам добавляется id:
                                            <div class="tabs" id="tabs-1">...</div>
                                            <div class="tabs" id="tabs-2">...</div>
                                            
                                            Они нужны чтобы определить какой это таб.
                                            Далее выполняем их инициализацию следующим образом
                                            var
                                              mytabs = {
                                                'tabs-1': $tabs('#tabs-1'),
                                                'tabs-2': $tabs('#tabs-2')
                                              },
                                              ...
                                            Теперь у нас в mytabs['tabs-1'] и mytabs['tabs-2'] находятся результаты соответственно вызова $tabs для первого и второго tabs.
                                            Сохранение данных в LocalStorage в этом примере выполняется в таком формате:
                                            {"tabs-2":"#content-6","tabs-1":"#content-2"}
                                            
                                            Вам нужно написать что-то подобное.
                                            1. Nik
                                              14 апреля 2020, 17:13
                                              Наверно я что-то не недопонимаю, когда мы вызываем функцию $tabs('.tabs') и происходит инициализация определенного id с помощью:
                                              var
                                                mytabs = {
                                                  'tabs-1': $tabs('#tabs-1'),
                                                  'tabs-2': $tabs('#tabs-2')
                                                }
                                              
                                              такая конструкция отлично работает, если табы на одной и той же странице. но если они расположены на разных страницах, то не работает, пробовал по разному ничего пока не получается.
                                              1. Александр Мальцев
                                                15 апреля 2020, 04:07
                                                В этом случае его можно сделать более динамичным (пример обновил в статье). Теперь он будет сохранять состояния в LocalStorage и восстанавливать открытые вкладки только для тех табов, которые имеют id.
                                                1. Nik
                                                  16 апреля 2020, 11:43
                                                  Да, теперь табы работают на любых страницах, спасибо за наглядный пример!
                                        2. Nik
                                          13 апреля 2020, 14:44
                                          Сейчас проанализирую, сравню
                                2. Nik
                                  12 апреля 2020, 13:09
                                  Благодарю!
                              2. Vlad
                                30 января 2020, 12:22
                                как во втором способе сделать, чтобы первая вкладка была уже активной?
                                1. Александр Мальцев
                                  30 января 2020, 14:45
                                  Для этого нужно добавить к URL страницы соответствующий хэш.
                                  Например:
                                  // content-1 - хэш URL
                                  https://myblog.ru/post-7#content-1
                                  
                                  1. Петр
                                    14 августа 2020, 21:57
                                    Александр помоги.
                                    Не срабатывает указанный метод.
                                    Необходимо перейти на определенную вкладку с другой страницы.
                                    index.html — products.html#content-2 например
                                    1. Александр Мальцев
                                      16 августа 2020, 12:21
                                      А вы их как выполнили? С использованием псевдокласса :target или с использованием JavaScript. Если они у вас организованы на JavaScript, то это необходимо дополнительно прописать в коде.
                                      1. Петр
                                        16 августа 2020, 13:17
                                        С использованием javascripta. В ie 11 он не работает, даже разрешая заблокированные сценарии.
                                2. Vlad
                                  28 января 2020, 16:14
                                  не так подключаю что ли на вордпрессе? кроме первой вкладки не открываются.
                                  itchief.ru/assets/uploadify/4/5/3/453a9690d5d48b71c6bbf050a7894874.jpg
                                  1. Александр Мальцев
                                    28 января 2020, 16:24
                                    Необходимо js-файл подключать после HTML-кода вкладок или поместить код в обработчик события DOMContentLoaded, чтобы он выполнился после загрузки DOM-документа:
                                    document.addEventListener('DOMContentLoaded', function() {
                                      // ...
                                    });
                                    
                                    1. Vlad
                                      28 января 2020, 16:47
                                      Здорово сработало )
                                  2. Vlad
                                    28 января 2020, 10:21
                                    Здравствуйте, автор! А вы платные услуги не оказываете? Мне нужно сделать табы, и внутри у каждого карусель.
                                    1. Александр Мальцев
                                      28 января 2020, 13:43
                                      Здравствуйте! Карусель можно взять отсюда, после этого нужно будет просто вставить карусель в каждую вкладку.
                                    2. Nik
                                      07 декабря 2019, 18:12
                                      Александр подскажите а как использовать табы два раза подряд на одной странице? Те которые с использованием java script. Сделал форму авторизации/регистрации во всплывающем окне, разместил в хэдере, форма с применением табов. Соответственно размещая табы уже в теле, получается они используются два раза подряд. И не работают которые вторые, после хэдера. Пробовал менять id, не выходит. Похоже для одновременного использования скрипт должен быть другой…
                                      1. Nik
                                        07 декабря 2019, 21:39
                                        Не внимательно прочёл статью до конца, все работает, все табы на странице!
                                        var listTabs = document.querySelectorAll('.tabs');
                                        for (var i = 0; i <= listTabs.length; i++) {
                                          tabs(listTabs[i]);
                                        } 
                                         
                                      2. Nik
                                        06 декабря 2019, 12:44
                                        Отличные табы! Уже применил для авторизации, и в личном кабинете. Все работает супер, Спасибо!
                                        1. Александр Мальцев
                                          06 декабря 2019, 13:24
                                          Рад, что понравились!
                                        Войдите, пожалуйста, в аккаунт, чтобы оставить комментарий.