Хлебные крошки (breadcrumbs)

Навигационная цепочка «Главная / Каталог / Товар» с семантическим HTML, ARIA и микроразметкой Schema.org.

Задача

Нужен компонент хлебных крошек для навигации по вложенной структуре страниц. Должен быть доступным, SEO-friendly и генерироваться динамически из массива данных.

Решение

<!-- Статический вариант -->
<nav class="breadcrumbs" aria-label="Навигация по сайту">
  <ol class="breadcrumbs__list" itemscope itemtype="https://schema.org/BreadcrumbList">
    <li class="breadcrumbs__item" itemprop="itemListElement" itemscope itemtype="https://schema.org/ListItem">
      <a class="breadcrumbs__link" href="/" itemprop="item">
        <span itemprop="name">Главная</span>
      </a>
      <meta itemprop="position" content="1" />
    </li>

    <li class="breadcrumbs__item" itemprop="itemListElement" itemscope itemtype="https://schema.org/ListItem">
      <a class="breadcrumbs__link" href="/catalog/" itemprop="item">
        <span itemprop="name">Каталог</span>
      </a>
      <meta itemprop="position" content="2" />
    </li>

    <li class="breadcrumbs__item breadcrumbs__item--current"
        itemprop="itemListElement" itemscope itemtype="https://schema.org/ListItem"
        aria-current="page">
      <span itemprop="name">Ноутбук Pro 15</span>
      <meta itemprop="position" content="3" />
    </li>
  </ol>
</nav>
.breadcrumbs__list {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 4px;
  list-style: none;
  padding: 0;
  margin: 0;
  font-size: 0.875rem;
}

.breadcrumbs__link {
  color: #3b82f6;
  text-decoration: none;
}
.breadcrumbs__link:hover { text-decoration: underline; }

/* Разделитель через CSS content */
.breadcrumbs__item:not(:last-child)::after {
  content: '/';
  margin-left: 4px;
  color: #94a3b8;
}

.breadcrumbs__item--current {
  color: #64748b;
}

JavaScript — динамическая генерация из массива:

function renderBreadcrumbs(container, crumbs) {
  const nav = document.createElement('nav');
  nav.setAttribute('aria-label', 'Навигация по сайту');

  const ol = document.createElement('ol');
  ol.className = 'breadcrumbs__list';

  crumbs.forEach((crumb, index) => {
    const li = document.createElement('li');
    li.className = 'breadcrumbs__item';
    const isLast = index === crumbs.length - 1;

    if (isLast) {
      li.classList.add('breadcrumbs__item--current');
      li.setAttribute('aria-current', 'page');
      li.textContent = crumb.label;
    } else {
      const a = document.createElement('a');
      a.className = 'breadcrumbs__link';
      a.href = crumb.href;
      a.textContent = crumb.label;
      li.appendChild(a);
    }
    ol.appendChild(li);
  });

  nav.appendChild(ol);
  container.innerHTML = '';
  container.appendChild(nav);
}

// Использование
renderBreadcrumbs(document.getElementById('breadcrumbs'), [
  { label: 'Главная',  href: '/' },
  { label: 'Каталог', href: '/catalog/' },
  { label: 'Ноутбук Pro 15' },
]);

Ключевые моменты

  • <nav> + aria-label — screen reader объявит «Навигация по сайту».
  • <ol> (ordered list) — хлебные крошки имеют порядок, не <ul>.
  • aria-current="page" на последнем элементе — означает «текущая страница».
  • Schema.org BreadcrumbList — Google показывает крошки прямо в результатах поиска (rich snippets).

Варианты

  • SVG-разделитель вместо /: content: url("chevron.svg") или > через content: '›'.
  • В React/Next.js — генерируй из useRouter.pathname разбивкой на сегменты пути.

Связанные рецепты / темы