День 20 | Верстаем табы (Tabs) на чистом JS
45 минЧто такое табы?
Табы (вкладки) — это способ организовать контент в компактном виде. Показывается только одна вкладка, остальные скрыты. Пользователь может переключаться между вкладками, кликая на их заголовки.
Где используются табы?
- Описания товаров (характеристики, отзывы, доставка)
- Программы курсов (модуль 1, модуль 2, и т.д.)
- Настройки (общие, безопасность, уведомления)
- Любой контент, который нужно организовать по категориям
HTML структура табов
<div class="tabs">
<div class="tabs__header">
<button class="tab-btn active" data-tab="tab1">Вкладка 1</button>
<button class="tab-btn" data-tab="tab2">Вкладка 2</button>
<button class="tab-btn" data-tab="tab3">Вкладка 3</button>
</div>
<div class="tabs__content">
<div class="tab-panel active" id="tab1">
<h3>Содержимое вкладки 1</h3>
<p>Это контент первой вкладки.</p>
</div>
<div class="tab-panel" id="tab2">
<h3>Содержимое вкладки 2</h3>
<p>Это контент второй вкладки.</p>
</div>
<div class="tab-panel" id="tab3">
<h3>Содержимое вкладки 3</h3>
<p>Это контент третьей вкладки.</p>
</div>
</div>
</div>
Разберём структуру:
tabs__header— контейнер для кнопок-вкладокtab-btn— кнопка вкладкиdata-tab="tab1"— связь кнопки с панелью контента (значение должно совпадать с id панели)tab-panel— панель с контентом вкладкиid="tab1"— идентификатор панели (должен совпадать с data-tab кнопки)active— класс для активной вкладки и панели
Разбор JavaScript кода табов
Конструктор класса Tabs
constructor(container) {
this.container = container;
this.buttons = container.querySelectorAll('.tab-btn');
this.panels = container.querySelectorAll('.tab-panel');
this.init();
}
Что происходит:
- Сохраняем контейнер табов
- Находим все кнопки вкладок внутри контейнера
- Находим все панели контента
- Вызываем метод инициализации
Метод init()
init() {
this.buttons.forEach(button => {
button.addEventListener('click', () => {
const targetTab = button.getAttribute('data-tab');
this.switchTab(targetTab);
});
});
}
Разберём построчно:
this.buttons.forEach(...)— проходим по всем кнопкамbutton.addEventListener('click', ...)— добавляем обработчик клика на каждую кнопкуconst targetTab = button.getAttribute('data-tab')— получаем значение атрибута data-tab (например, "tab1")this.switchTab(targetTab)— вызываем метод переключения, передавая ID вкладки
Метод switchTab()
switchTab(tabId) {
// Убираем активные классы
this.buttons.forEach(btn => btn.classList.remove('active'));
this.panels.forEach(panel => panel.classList.remove('active'));
// Добавляем активные классы
const activeButton = this.container.querySelector(`[data-tab=\"${tabId}\"]`);
const activePanel = document.getElementById(tabId);
if (activeButton && activePanel) {
activeButton.classList.add('active');
activePanel.classList.add('active');
}
}
Разберём логику:
- Убираем активные классы:
- Проходим по всем кнопкам и убираем класс
active - Проходим по всем панелям и убираем класс
active
- Проходим по всем кнопкам и убираем класс
- Находим нужные элементы:
this.container.querySelector(`[data-tab=\"${tabId}\"]`)— находим кнопку с нужным data-tab- Обратные кавычки `` — шаблонные строки (template literals)
${tabId}— вставка переменной в строку- Результат:
[data-tab="tab1"]— селектор атрибута
document.getElementById(tabId)— находим панель по ID
- Проверка и активация:
if (activeButton && activePanel)— проверяем, что оба элемента найдены- Если найдены — добавляем класс
active
Что такое шаблонные строки? Шаблонные строки (template literals) позволяют вставлять переменные в строки:
// Обычная строка (конкатенация)
const str = "Привет, " + name + "!";
// Шаблонная строка (удобнее)
const str = `Привет, ${name}!`;
Практическое задание
- Создайте структуру табов в HTML
- Стилизуйте кнопки и панели контента
- Напишите класс Tabs для управления переключением
- Добавьте плавную анимацию при переключении
- Сделайте табы адаптивными для мобильных (можно сделать выпадающий список)
- Добавьте возможность переключения табов с клавиатуры (стрелки влево/вправо)
Что дальше?
Отлично! Табы готовы. В следующем уроке мы создадим аккордеон — раскрывающиеся блоки, которые идеально подходят для FAQ секций.