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

Табы (вкладки) для сайта на CSS и JavaScript – 3 способа
Содержание:
  1. Что такое вкладки (табы)?
  2. Вкладки на CSS с использованием радиокнопок и :checked
  3. Вкладки на CSS с использованием :target
  4. Табы с использованием JavaScript
  5. Как работает JavaScript код табов?
  6. Примеры
  7. Комментарии

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

Что такое вкладки (табы)?

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

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

В вебе, вкладки обычно реализуются посредством ссылок (<a>) или кнопок (<button>). При этом каждая из них связана с определённым блоком. При нажатии на определённую ссылку или кнопку все блоки с контентом скрываются, кроме одного, с которым она связана. Кроме этого, чтобы было понятно какой контент сейчас отображается, заголовок соответсвующей вкладки как-то выделяют.

Вкладки на CSS с использованием радиокнопок и :checked

Один из способов создать вкладки на CSS – это использовать радиокнопки(<input> с type="radio") и CSS-селектор :checked.

Без оформления минимальный код табов будет выглядеть следующим образом:

HTML
<style>
  /* скрываем все input[type="radio"], расположенные в .tab
  .tab > input[type="radio"] {
    display: none;
  }

  /* скрываем все .tab-content */
  .tab-content {
    display: none;
  }

  /* отображаем только тот контент, который соответствует отмеченной радоикнопки */
  #tab-btn-1:checked~#content-1,
  #tab-btn-2:checked~#content-2,
  #tab-btn-3:checked~#content-3 {
    display: block;
  }
</style>

<div class="tab">
  <input checked id="tab-btn-1" name="tab-btn" type="radio" value="">
  <label for="tab-btn-1">Вкладка 1</label>
  <input id="tab-btn-2" name="tab-btn" type="radio" value="">
  <label for="tab-btn-2">Вкладка 2</label>
  <input id="tab-btn-3" name="tab-btn" type="radio" value="">
  <label for="tab-btn-3">Вкладка 3</label>
  <div class="tab-content" id="content-1">
    Содержимое 1...
  </div>
  <div class="tab-content" id="content-2">
    Содержимое 2...
  </div>
  <div class="tab-content" id="content-3">
    Содержимое 3...
  </div>
</div>
Вкладки (табы) для сайта на чистом CSS, в основу работых которых положены радиокнопки и CSS-селектор :checked

Посмотреть

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

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

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

Для выделения названия текущей (активной) вкладки можно использовать следующий код:

HTML
.tab > input[type="radio"]:checked + label {
  color: red;
}
Табы на основе радиокнопок и CSS-селектора :checked, в которых добавлен ещё код для выделения активной	вкладки

Посмотреть

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

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

CSS
.tab {
  display: flex;
  flex-wrap: wrap;
}

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

.tab-content {
  display: none;
  width: 100%;
  margin-top: 1rem;
}

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

.tab > label {
  display: block;
  padding: 0.5rem 1rem;
  cursor: pointer;
  transition: color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out;
  text-decoration: none;
  color: #0d6efd;
  border: 0;
  border-radius: 0.375rem;
  background: 0 0;
}

.tab > input[type="radio"]:checked + label {
  cursor: default;
  color: #fff;
  background-color: #0d6efd;
}
Табы для сайта на основе радиокнопок и CSS-селектора :checked, которые имеют внешний вид кнопок

Посмотреть

Вкладки с нижнем подчеркивание названий секций:

Табы для сайта на основе радиокнопок и CSS-селектора :checked, которые имеют нижнее подчёркивание названий секций

Посмотреть

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

Табы для сайта на основе радиокнопок и CSS-селектора :checked, которые в качестве названий вкладок имеют хештеги

Вкладки, которые имеют привычный вид (с использованием селектора :has():

Табы для сайта на основе радиокнопок и CSS-селектора :checked, которые имеют привычный вид

Посмотреть

Вкладки на CSS с использованием :target

Ещё создать вкладки только на CSS можно с использованием псевдокласса :target.

Без оформления минимальный код будет выглядеть следующим образом:

HTML
<style>
  .tab-content {
    display: none;
  }

  .tab-content:target {
    display: block;
  }
</style>

<div class="tab">
  <div class="tab-content" id="content-1">
    Содержимое 1...
  </div>
  <div class="tab-content" id="content-2">
    Содержимое 2...
  </div>
  <div class="tab-content" id="content-3">
    Содержимое 3...
  </div>
  <div class="tab-nav">
    <a class="tab-link" href="#content-1">Вкладка 1</a>
    <a class="tab-link" href="#content-2">Вкладка 2</a>
    <a class="tab-link" href="#content-3">Вкладка 3</a>
  </div>
</div>
Вкладки (табы) для сайта на чистом CSS, работающие на основе псевдокласса :target

Посмотреть

Работа этих табов основана:

  • на добавлении хеша к URL-адресу страницы при нажатии на вкладку (ссылку);
  • на скрытии всех блоков (display: none) и отображении только одного их них, id которого сейчас находится в хеше URL-адреса.

С помощью псевдокласса :target мы можем также выбрать другие элементы, которые каким-то определённым образом связаны с ним. Например, можем это использовать, чтобы выделить активную (текущую) вкладку:

CSS
#content-1:target~.tab-nav>[href="#content-1"],
#content-2:target~.tab-nav>[href="#content-2"],
#content-3:target~.tab-nav>[href="#content-3"] {
  color: red;
}
Вкладки (табы) для сайта на чистом CSS, в которых :target ещё используется для выделения активной	вкладки

Посмотреть

В HTML-код табов уже добавлены классы. Используя их мы можем стилизовать табы так, как нам нужно.

Пример вёрстки вкладок на Flexbox, которые имеют стандартный вид:

Табы для сайта на основе псевдокласса :target, которые имеют обычный вид

Посмотреть

Пример оформления вкладок, которые имеют внешний вид кнопок:

Табы для сайта на основе псевдокласса :target, которые имеют внешний вид кнопок

Посмотреть

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

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

Посмотреть

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

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

  .tab-nav {
    flex-direction: column;
    margin-right: 1rem;
  }
}

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

Сейчас рассмотрим реализацию табов на чистом JavaScript (без использования jQuery и каких-либо других библиотек). Этот вариант может потребоваться, когда мы хотим от табов больше, чем можно сделать с помощью CSS. Например, если мы хотим при открытии вкладки загружать туда контент через AJAX.

Код HTML и CSS без дополнительного оформления:

HTML
<style>
  .tab-btn-active {
    pointer-events: none;
    color: red;
  }

  .tab-pane:not(.tab-pane-show) {
    display: none;
  }
</style>

<div class="tab" id="tab-1">
  <div class="tab-nav">
    <button type="button" class="tab-btn tab-btn-active" data-target-id="0">Вкладка 1</button>
    <button type="button" class="tab-btn" data-target-id="1">Вкладка 2</button>
    <button type="button" class="tab-btn" data-target-id="2">Вкладка 3</button>
  </div>
  <div class="tab-content">
    <div class="tab-pane tab-pane-show" data-id="0">Содержимое 1...</div>
    <div class="tab-pane" data-id="1">Содержимое 2...</div>
    <div class="tab-pane" data-id="2">Содержимое 3...</div>
  </div>
</div>

К вкладке, которая должна быть активной по умолчанию необходимо добавить класс tab-btn-active. А к контенту, связанному с ней tab-pane-show.

JavaScript:

JavaScript
const showTab = (elTabBtn) => {
  const elTab = elTabBtn.closest('.tab');
  if (elTabBtn.classList.contains('tab-btn-active')) {
    return;
  }
  const targetId = elTabBtn.dataset.targetId;
  const elTabPane = elTab.querySelector(`.tab-pane[data-id="${targetId}"]`);
  if (elTabPane) {
    const elTabBtnActive = elTab.querySelector('.tab-btn-active');
    elTabBtnActive.classList.remove('tab-btn-active');
    const elTabPaneShow = elTab.querySelector('.tab-pane-show');
    elTabPaneShow.classList.remove('tab-pane-show');
    elTabBtn.classList.add('tab-btn-active');
    elTabPane.classList.add('tab-pane-show');
  }
}

document.addEventListener('click', (e) => {
  if (e.target && !e.target.closest('.tab-btn')) {
    return;
  }
  const elTabBtn = e.target.closest('.tab-btn');
  showTab(elTabBtn);
});
Табы для сайта на CSS и JavaScript

Посмотреть

Если нужно программно открыть другую вкладку, то можно использовать функцию showTab(). Ей в качестве аргумента нужно передать ту вкладку (<button>), которую необходимо сделать активной:

JavaScript
// получим все кнопки
const elTabBtns = document.querySelectorAll('#tab-1 .tab-btn');
// показать первую вкладку
showTab(elTabBtns[0]);
// показать вторую вкладку
showTab(elTabBtns[1]);
// показать третью вкладку
showTab(elTabBtns[2]);

Как работает JavaScript код табов?

Центральное место в коде JavaScript занимает функция showTab(). Она имеет параметр elTabBtn.

Сначала внутри функции мы получаем элемент .tab, который содержит elTabBtn. Если вкладка уже активна, то дальше ничего не делаем и завершаем функцию с помощью инструкции return. В противном случае получаем значение атрибута data-target-id с помощью следующего кода:

JavaScript
const targetId = elTabBtn.dataset.targetId;

После этого, получаем элемент .tab-pane, используя targetId:

JavaScript
const elTabPane = elTab.querySelector(`.tab-pane[data-id="${targetId}"]`);

Затем проверяем наличие элемента elTabPane, который мы получили в предыдущем шаге с помощью метода querySelector. Если элемент существует, то удаляем классы tab-btn-active и tab-pane-show у элементов, который в данный момент их содержат:

JavaScript
const elTabBtnActive = elTab.querySelector('.tab-btn-active');
elTabBtnActive.classList.remove('tab-btn-active');
const elTabPaneShow = elTab.querySelector('.tab-pane-show');
elTabPaneShow.classList.remove('tab-pane-show');

В конце добавляем к элементам elTabBtn и elTabPane соответственно классы tab-btn-active и tab-pane-show:

JavaScript
lTabBtn.classList.add('tab-btn-active');
elTabPane.classList.add('tab-pane-show');

Обработку события click выполняем с помощью следующего кода:

JavaScript
document.addEventListener('click', (e) => {
  if (e.target && !e.target.closest('.tab-btn')) {
    return;
  }
  const elTabBtn = e.target.closest('.tab-btn');
  showTab(elTabBtn);
});

Примеры

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

JavaScript
const showTab = (elTabBtn) => {
  // ...
  if (elTabPane) {
    // ...
    // сохраняем состояние вкладки в LocalStorage
    const tabStorage = JSON.parse(localStorage.getItem('tab') ?? '{}');
    tabStorage[elTab.id] = targetId;
    localStorage.setItem('tabs', JSON.stringify(tabStorage));
  }
}

// ...
  
// восстанавливаем состояние вкладок из LocalStorage
const updateTabs = (tabStorage) => {
  Object.keys(tabStorage).forEach((tabId) => {
    const elTab = document.querySelector(`#${tabId}`);
    const elTabBtn = elTab.querySelector(`.tab-btn[data-target-id="${tabStorage[tabId]}"]`);
    showTab(elTabBtn);
  });
}

const tabStorage = JSON.parse(localStorage.getItem('tabs') ?? '{}');
updateTabs(tabStorage);

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

JavaScript
window.onstorage = (e) => {
  if (e.key === 'tabs') {
    const tabStorage = JSON.parse(e.newValue);
    updateTabs(tabStorage);
  }
}

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

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

<script>
  class ItcTabs { ... }

  // массив табов
  const tabs = {};
  const elTabs = document.querySelectorAll('.tabs');
  const storage = localStorage.getItem('tabs');
  let storageData = {};

  elTabs.forEach(el => {
    tabs[el.id] = new ItcTabs(el);
    el.addEventListener('tab.itc.change', (e) => {
      const index = +el.querySelector('.tabs__btn_active').dataset.index;
      storageData[el.id] = index;
      localStorage.setItem('tabs', JSON.stringify(storageData));
    })
  })

  if (storage) {
    storageData = JSON.parse(storage);
    for (let key in storageData) {
      if (tabs.hasOwnProperty(key)) {
        tabs[key].showByIndex(storageData[key]);
      }
    }
  }
</script>

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

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

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

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

HTML
<div class="tab" id="tab-1">
  <div class="tab-nav">
    <button type="button" class="tab-btn tab-btn-active" data-target-id="0">Вкладка 1</button>
    <button type="button" class="tab-btn" data-target-id="1">Вкладка 2</button>
    <button type="button" class="tab-btn" data-target-id="2">Вкладка 3</button>
  </div>
  <div class="tab-content">
    <div class="tab-pane tab-pane-show" data-id="0">
      <div class="iframe">
        <div class="player" id="player-1" data-video-id="5NTvXKUXEX4" data-width="560" data-height="315"></div>
      </div>
    </div>
    <div class="tab-pane" data-id="1">
      <div class="iframe">
        <div class="player" id="player-2" data-video-id="Cy35h6DF8hY" data-width="560" data-height="315"></div>
      </div>
    </div>
    <div class="tab-pane" data-id="2">
      <div class="iframe">
        <div class="player" id="player-3" data-video-id="6tyB97J1cVA" data-width="560" data-height="315"></div>
      </div>
    </div>
  </div>
</div>

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

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

JavaScript
const elScript = document.createElement('script');
elScript.src = 'https://www.youtube.com/iframe_api';
document.head.append(elScript);

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

JavaScript
const players = {};
function onYouTubeIframeAPIReady() {
  document.querySelectorAll('.player').forEach(el => {
    players[el.id] = new YT.Player(el.id, {
      height: el.dataset.height,
      width: el.dataset.width,
      videoId: el.dataset.videoId,
      playerVars: {
        origin: location.origin,
      }
    });
  })
}

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

JavaScript
document.addEventListener('tab.itc.show', (e) => {
  const elTabPanePrev = e.detail.elTabPanePrev;
  if (elTabPanePrev) {
    const player = elTabPanePrev.querySelector('.player');
    player ? players[player.id].pauseVideo() : null;
  }
});

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

Ksenya
Ksenya

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

HTML:
<div class="tab_titles">
  <p class="tab_links active-link" onclick="opentab('skills')">Навыки</p>
  <p class="tab_links" onclick="opentab('experience')">Опыт</p>
  <p class="tab_links" onclick="opentab('education')">Образование</p>
</div>

<div class="tab_contents active_tab" id="skills">
  <ul>
    <li><span> Lorem ipsum</span><br>Html,Css</li>
    <li><span> Lorem ipsum</span><br>Html,Css</li>
    <li><span> Lorem ipsum</span><br>Html,Css</li>
  </ul>
</div>
<div class="tab_contents" id="experience">
  <ul>
    <li><span> Lorem ipsum</span><br>Html,Css</li>
    <li><span> Lorem ipsum</span><br>Html,Css</li>
    <li><span> Lorem ipsum</span><br>Html,Css</li>
  </ul>
</div>
<div class="tab_contents" id="education">
  <ul>
    <li><span> Lorem ipsum</span><br>Html,Css</li>
    <li><span> Lorem ipsum</span><br>Html,Css</li>
    <li><span> Lorem ipsum</span><br>Html,Css</li>
  </ul>
</div>
CSS:
.tab_links::after{
  content: '';
  width: 0;
  height: 5px;
  background-color: crimson;
  position: absolute;
  left:0;
  bottom: -8px;
  transition: 0.5s ease-in-out;
}

.tab_links.active-link::after{
  width: 100%;
}

.tab_contents ul li {
  list-style: none;
  margin: 10px 0;
}
 
.tab_contents ul li span {
  color: crimson;
  font-size: 18px;
}

.tab_contents{
  display: none;
}

.tab_contents.active_tab{
  display:block;
}
JavaScript:
let tablinks = document.getElementsByClassName('tab_links');
let tabcontents = document.getElementsByClassName('tab_contents');

function opentab(tabname) {
  for (tablink of tablinks) {
    tablink.classList.remove('active-link');
  }
  for (tabcontent of tabcontents) {
    tabcontent.classList.remove('active-tab');
  }
  event.currentTarget.classList.add('active-link');
  document.getElementById(tabname).classList.add('active-tab');
}
Александр Мальцев
Александр Мальцев

Привет! Поправил ошибки в JavaScript-коде:

let tablinks = document.getElementsByClassName('tab_links');
let tabcontents = document.getElementsByClassName('tab_contents');

function opentab(tabname) {
  for (let tablink of tablinks) {
    tablink.classList.remove('active-link');
  }
  for (let tabcontent of tabcontents) {
    tabcontent.classList.remove('active_tab');
  }
  event.currentTarget.classList.add('active-link');
  document.getElementById(tabname).classList.add('active_tab');
}
TI_Eugene
TI_Eugene
Отличная статья — всё, что я искал, в одном месте и компактно.
Вопросы:
1. Как осуществить вариант №1 (radio button), если input и label все вместе спрятаны внутрь отдельного блока?
Типа:
<div class="tabs">
  <nav>
    <input type="radio" name="tab-btn" id="tab-btn-1" value="" checked>
    <label for="tab-btn-1">Вкладка 1</label>
    ...
  </nav>
  <div id="content-1">
Только без :has, который никем (почти) не поддерживается и без JS (понятное дело).
2. В варианте №2 (:target) при первичной загрузке страницы содержимое не отображается никакое)
Александр Мальцев
Александр Мальцев
Спасибо!
1. Можно только с использованием :has(), как-то по-другому только на CSS не получится
2. С :target этот момент можно доделать, чтобы по умолчанию отображалась, например, 1 вкладка (пример)
Дмитрий
Дмитрий
Здравствуйте Александр, а как реализовать такую задачку, я сделал страницу с алфавитом и брендами на базе бутстрап табов, при выборе вкладки открывается то или иное содержание, пример тут https://laraves.ru/baseshop/brand/, а как сделать так чтоб была возможность сразу выбрать несколько вкладок, допустим A и B и S и соответственно открыть их содержание, и также чтоб поочердно при клике можно было снимать выделения? штатно есть только «ИЛИ», а хотелось бы «И»
Александр
Александр
Доброго дня, Александр.

Благодарю вас за подробную развернутую статью на данную тему и за максимально просто изложенный материал.

У меня вопрос следующего рода: как сделать «табы в табах»
Пример: на сайте по продаже пластиковых окон нужно вывести информацию в виде:
Табы (Уровень 1): типы конструкций, всего 4 типа конструкций;
В зависимости от типа выбранной конструкции подгрузить картинку (с этим разобрался) и блок с табами «виды комплектаций», их 7 штук

Табы (Уровень 2): виды комплектаций, всего 7 видов комплектаций.

Могли бы вы такой пример подробно рассмотреть, буду вам очень признателен.
Александр Мальцев
Александр Мальцев
Привет! Благодарю за отзыв.
Сделал пример, если конечно правильно понял и сделал то что нужно (правда пришлось немного JavaScript код табов изменить): перейти.
Александр
Александр
Александр, благодарю за огромную работу и помощь! Вы мне очень помогли! Это именно то, что нужно, хочу спросить следующее как вкладкам 1.1...1.4 присвоить другой класс в CSS, чтобы потом навесить на них другие свойства CSS, тем самым, чтобы они визуально выглядели по другому?
Aleks
Aleks
Я пытаюсь добавить два слайдера через шорткод в разные табы. После перезагрузки один работает (группа из 5 картинок, опционально вывожу только 3 с возможностью их прокручивать), а при переходе в следующий таб второй — нет (отображается только одна картинка из группы в увеличенном виде и не реагирует прокрутка). Причём, как только меняется разрешение экрана (через responsive в инспекторе) оба слайдера начинают работать прекрасно (если быть точнее, то тот, который во втором табе), но при очередной перезагрузке опять один работает, второй — нет. В чём может быть причина?
Александр Мальцев
Александр Мальцев
Тут нужно разбираться со слайдерами, и скорее всего слайдер, который расположен во вкладке, содержимое которого сейчас не показывается, нужно активировать в момент перехода на неё.
vlad
vlad
Здравствуйте, допустим на сайте есть блок с карточками товаров. Как при нажатии на таб показывать не одну карточку, а несколько? пока только смог реализовать через дублировании html-кода, но это наверное такой себе вариант…
sprigan
sprigan
Добрый день, Александр

Подскажите, столкнулся с такой проблемой.
Взял пример реализации через JS.

Если кликаю на свободное место вкладки, то работает, если кликаю к примеру по тексту вкладки, то нет.
Как реализовать, чтобы по клику на любой элемент внутри родителя сработало переключение?

<img
src=«https://itchief.ru/assets/uploadify/f/8/6/f86bf8fc0c6125d9dd8f5f48a2490897s.jpg» class=«fancybox thumbnail center»>
Александр Мальцев
Александр Мальцев
Привет! Код JavaScript поправил в примере: tabs-v1
sprigan
sprigan
Большое спасибо!
Primerio
Primerio
Есть баг с табами, если рядом с названием вкладки будет картинка, про нажатие на нее таб не открывается, только если нажать на текст
Александр Мальцев
Александр Мальцев
Поправил код JavaScript в примере: tabs-v1
Alex Maker
Alex Maker
Здравствуйте, скажите что из выше перечисленного может помочь в решении моей проблемы?
Есть табы с категориями, в каждой из категорий есть табы с товаром, переключение между категориями и товарами написано на чистом Javascript, а теперь проблема. Необходимо чтобы по ссылке с другой страницы открывалась необходимая категория и товар. Дайте пример пожалуйста, я не силен в js((
Александр Мальцев
Александр Мальцев
Привет! Для этого можно, например, передавать в составе URL номер вкладки, которую нужно открыть:
Эта ссылка (https://itchief.ru/examples/lab.php?topic=javascript&file=tabs-08&tab=2) откроет вторую вкладку, а эта (https://itchief.ru/examples/lab.php?topic=javascript&file=tabs-08&tab=3) — третью.

Сам код тут будет простой, нужно получить значение GET-параметра tab и передать его значение функции которая переключает вкладки:

const tabs = $tabs('.tabs');
const urlParams = new URLSearchParams(location.search);
const tabTo = urlParams.get('tab');
if (tabTo) {
  tabs.switchTabTo(tabTo);
}
Олег
Олег
Доброго времени суток друзья.
Очень интересные и полезные примеры работы скриптов, но к сожалению для решения свой задачи ничего подходящего не нашёл.
Возможно похожее есть решение с синхронизацией табов на разных страница как на примере itchief.ru/examples/lab.php?topic=javascript&file=tabs-v3, но немного не то что надо.
Александр, может Вы как мастер сможете помочь с реализацией моей задачи.
У меня на сайте есть 2 отдельный блока div.
В одном блоке содержится информация от квадроциклах, те. Есть цена и характеристики, а во втором блоке есть табы, в которых есть информация о предоставляемых услугах, в каждом табе разная услуга.
Зада состоит в том, чтобы при клике на каждом табе справа менялась цена.
Например:
Клик по табу №1 справа менялась цена в левом блоке и так при нажатии на каждый таб. пример на картинке


Буду очень признателен за помощь.
Александр Мальцев
Александр Мальцев
Привет! Можно добавить к вкладкам data-атрибут с ценой:

<div class="tabs">
  <div class="tabs__nav">
    <a class="tabs__link tabs__link_active" href="#content-1" data-price="100">Вкладка 1</a>
    <a class="tabs__link" href="#content-2" data-price="200">Вкладка 2</a>
    <a class="tabs__link" href="#content-3" data-price="300">Вкладка 3</a>
  </div>
  <div class="tabs__content">...</div>
</div>
После этого добавить скрипт, который будет при переключении вкладки изменять цену:

const tabs = $tabs('.tabs');
function updatePrice(tabsLink) {
  const price = tabsLink.dataset.price;
  document.querySelector('.price').textContent = price;
}
updatePrice(document.querySelector('.tabs__link_active'));
document.addEventListener('tab.show', function(e) {
  updatePrice(e.detail.querySelector('.tabs__link_active'));
});
Пример: https://itchief.ru/examples/lab.php?topic=javascript&file=tabs-09
Siarhei
Siarhei
То что надо. Спасибо автору большое!
Ребят. Использую Табы с использованием JavaScript. Главный код сначала в посте. Без дополнений.

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


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

Заранее благодарю, если есть решение!
Александр Мальцев
Александр Мальцев
Пожалуйста!
Добавил в статью пример табов, содержащие YouTube видео. При переключении видео приостанавливается.
Открыть пример
Siarhei
Siarhei
Просто красавчик!
Спасибо огромное!!!
Александр Сидоров
Александр Сидоров
Добрый день Александр!

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

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

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

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

Как копать в сторону аякса — это тоже на данный момент по знаниям проблематично…
Дмитрий
Дмитрий
Здравствуйте! Подскажите как сделать несколько блоков с табами на одной странице их мне нужно 4 (https://itchief.ru/assets/uploadify/9/8/8/9889f32d8a70fb4e1dc8bd505ace4887.jpg). Пробую вариант с отображением как кнопки. У меня только две вкладки, в каждом блоке разное содержание, название вкладок одинаковое.
Александр Мальцев
Александр Мальцев
Привет! Связывание вкладок с содержимым выполняется через id, название может быть любым. Тут всё просто, проблем не должно быть. Как сделать: пример.
Дмитрий
Дмитрий
Просто огромное спасибо, все работает как надо.
ofam
ofam
Здравствуйте.
Подскажите, пожалуйста, как реализовать возможность переключения сразу нескольких табов кнопкой?
Для примера: у меня 5 блоков, в каждом по 2 вкладке. Над ними 2 кнопки, которые должны переключить сразу все табы.
Александр Мальцев
Александр Мальцев
Привет!
Можно например так (открыть пример):
<!-- Добавить к кнопкам или ссылкам атрибут 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>
Илья
Илья
А как сделать кнопку «Добавить новую вкладку»? К примеру, чтобы скопировало содержание вкладки с чистым независимым input от копируемой вкладки
Александр Мальцев
Александр Мальцев
Лучше наверно не копировать, а самостоятельно определять контент, например, с помощью функции 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));
}
Ola
Ola
Супер! как всегда просто и понятно! Спасибо!
Александр Мальцев
Александр Мальцев
Пожалуйста!
Владимир
Владимир
еще есть вопросик, при нажатии на вкладку страница прокручивается к началу вкладку сверху alutat.com.ua/ а как отменить это?
Александр Мальцев
Александр Мальцев
Так вы это реализовали в виде отдельных страниц, а не на одной странице. А новая страница по умолчанию всегда открывается сначала. Чтобы это реализовать, вам нужно дополнительно добавить скрипт на страницу, который будет её прокручивать до этого состояния.
Владимир
Владимир
Здравствуйте, Александр!

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

Хочу использовать вот эти вертикальные табы 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> открывать, но они у меня на главной будут сразу и нужно чтобы сразу была активна первая вкладка.

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

Буду признателен за ответ.
Александр Мальцев
Александр Мальцев
Здравствуйте! На сколько понимаю вы хотите без JavaScript. На CSS это можно выполнить, если только разместить содержимое вкладки, которая по умолчанию должна быть открытой, после остальных.
<div id="content-3">
  Содержимое 3...
<div>
<div id="content-2">
  Содержимое 2...
</div>
<div id="content-1">
  Содержимое 1...
</div>
А также внести необходимые изменения в CSS. Готовый пример можно посмотреть здесь.
Владимир
Владимир
супер! спасибо большое!
Nik
Nik
Доброго времени Александр! Подскажите как в данном скрипте добавить localStorage или cookie или sessionStorage, чтобы при F5 остаться на той же самой вкладке?
Александр Мальцев
Александр Мальцев
Привет! Пример как это сделать с помощью localStorage добавил в статью.
Nik
Nik
Благодарю!
Nik
Nik
А для двух табов подряд на странице не работает почему-то, код инициализации сразу всех вкладок делает нерабочим скрипт. Только если убрать один из двух табов, тогда да, сохранение в LocalStorage отрабатывает великолепно!
Nik
Nik
Разобрался, все работает!
Александр Мальцев
Александр Мальцев
Отлично!
Nik
Nik
Правда как-то очень интересно работает))) Пока еще не понял, но вроде «через раз»
Александр Мальцев
Александр Мальцев
Может что-то не учёл. Пример как это можно сделать для нескольких вкладок в статью добавил.
Nik
Nik
Сейчас проанализирую, сравню
Nik
Nik
Нашел одну причину, почему скрипт «ломало», банальная невнимательность, лишний раз обернул в дивы tabs, то, что вообще не надо было оборачивать.
Остальные примеры в статье разобрал, проверил на своем сайте, все работает как положено, кроме одного загадочного для меня явления))) Одни табы с одним контентом у меня на одной странице, другие с другим контентом на совершенно другой странице. Футер где скрипт, на всем сайте один и тот же. Табы работают, но допустим в хроме на одной странице с табами вкладка остаётся после F5 которую открыл, на другой local storage не срабатывает. В мозилле наоборот, та которая не работала в хроме, работает. «Мудрый» код скрипта покажу завтра
Nik
Nik
Код скрипта такой:
 <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>
Александр Мальцев
Александр Мальцев
Так корректно работать не будет. В 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"}
Вам нужно написать что-то подобное.
Nik
Nik
Наверно я что-то не недопонимаю, когда мы вызываем функцию $tabs('.tabs') и происходит инициализация определенного id с помощью:
var
  mytabs = {
    'tabs-1': $tabs('#tabs-1'),
    'tabs-2': $tabs('#tabs-2')
  }
такая конструкция отлично работает, если табы на одной и той же странице. но если они расположены на разных страницах, то не работает, пробовал по разному ничего пока не получается.
Александр Мальцев
Александр Мальцев
В этом случае его можно сделать более динамичным (пример обновил в статье). Теперь он будет сохранять состояния в LocalStorage и восстанавливать открытые вкладки только для тех табов, которые имеют id.
Nik
Nik
Да, теперь табы работают на любых страницах, спасибо за наглядный пример!
Vlad
Vlad
как во втором способе сделать, чтобы первая вкладка была уже активной?
Александр Мальцев
Александр Мальцев
Для этого нужно добавить к URL страницы соответствующий хэш.
Например:
// content-1 - хэш URL
https://myblog.ru/post-7#content-1
Петр
Петр
Александр помоги.
Не срабатывает указанный метод.
Необходимо перейти на определенную вкладку с другой страницы.
index.html — products.html#content-2 например
Александр Мальцев
Александр Мальцев
А вы их как выполнили? С использованием псевдокласса :target или с использованием JavaScript. Если они у вас организованы на JavaScript, то это необходимо дополнительно прописать в коде.
Петр
Петр
С использованием javascripta. В ie 11 он не работает, даже разрешая заблокированные сценарии.
Vlad
Vlad
не так подключаю что ли на вордпрессе? кроме первой вкладки не открываются.
itchief.ru/assets/uploadify/4/5/3/453a9690d5d48b71c6bbf050a7894874.jpg
Александр Мальцев
Александр Мальцев
Необходимо js-файл подключать после HTML-кода вкладок или поместить код в обработчик события DOMContentLoaded, чтобы он выполнился после загрузки DOM-документа:
document.addEventListener('DOMContentLoaded', function() {
  // ...
});
Vlad
Vlad
Здорово сработало )
Vlad
Vlad
Здравствуйте, автор! А вы платные услуги не оказываете? Мне нужно сделать табы, и внутри у каждого карусель.
Александр Мальцев
Александр Мальцев
Здравствуйте! Карусель можно взять отсюда, после этого нужно будет просто вставить карусель в каждую вкладку.
Nik
Nik
Александр подскажите а как использовать табы два раза подряд на одной странице? Те которые с использованием java script. Сделал форму авторизации/регистрации во всплывающем окне, разместил в хэдере, форма с применением табов. Соответственно размещая табы уже в теле, получается они используются два раза подряд. И не работают которые вторые, после хэдера. Пробовал менять id, не выходит. Похоже для одновременного использования скрипт должен быть другой…
Nik
Nik
Не внимательно прочёл статью до конца, все работает, все табы на странице!
var listTabs = document.querySelectorAll('.tabs');
for (var i = 0; i <= listTabs.length; i++) {
  tabs(listTabs[i]);
} 
 
Nik
Nik
Отличные табы! Уже применил для авторизации, и в личном кабинете. Все работает супер, Спасибо!
Александр Мальцев
Александр Мальцев
Рад, что понравились!