Как создать горизонтальное меню с прокруткой для сайта?

Как создать горизонтальное меню с прокруткой для сайта?
Содержание:
  1. Создание разметки
  2. Написание CSS кода меню
  3. Улучшения для меню с горизонтальной прокруткой
  4. Комментарии

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

Горизонтальное меню с прокруткой выполним на чистом CSS. JavaScript будем использовать только для добавления к нему различных улучшений.

Создание разметки

HTML-структура меню:

HTML
<div class="nav-scroller">
  <nav class="nav-scroller__items">
    <a class="nav-scroller__item" href="#">Start</a>
    <a class="nav-scroller__item" href="#">Icons</a>
    <a class="nav-scroller__item" href="#">Docs</a>
    <a class="nav-scroller__item" href="#">Support</a>
    <a class="nav-scroller__item" href="#">Plans</a>
    <a class="nav-scroller__item" href="#">Blog</a>
    <a class="nav-scroller__item" href="#">Sign in</a>
  </nav>
</div>

Вид горизонтального меню с прокруткой без стилей:

Вид горизонтального меню с прокруткой без стилей

Написание CSS кода меню

1. Зададим стили для .nav-scroller, .nav-scroller__items и .nav-scroller__item:

CSS
.nav-scroller {
  overflow-y: hidden;
  background-color: #fff;
  box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);
}
.nav-scroller__items {
  display: flex;
  flex-wrap: nowrap;
  overflow-x: auto;
  white-space: nowrap;
}
.nav-scroller__item {
  color: #424242;
  display: flex;
  padding: 0.5rem 1.25rem;
  text-decoration: none;
}

Список используемых свойств:

  • overflow-y: hidden - скрываем контент, который будет выходить за нижнюю границу элемента .nav-scroller;
  • background-color: #fff - устанавливаем цвета фона .nav-scroller;
  • box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075) - добавляем тень к .nav-scroller;
  • display: flex - делаем элемент flex-контейнером;
  • overflow-x: auto - разрешаем прокрутку по горизонтали, она будет доступна при необходимости;
  • white-space: nowrap - запрещаем переносить текст на новую строку, даже если он не помещается в ней;

На этом этапе меню будет иметь следующий вид:

Вид горизонтального меню с прокруткой без стилей

2. Добавим правую границу ко всем элементам кроме последнего:

CSS
.nav-scroller__item:not(:last-child) {
  border-right: 1px solid #eee;
}
Добавим правую границу ко всем пунктам Горизонтального меню кроме последнего

3. Выделим другим цветом фона активный пункт меню:

CSS
.nav-scroller__item_active {
  background-color: #fff59d;
}

Указание активного пункта меню будем выполнять посредством добавления к нему класса nav-scroller__item_active.

Выделение активного пункта меню другим цветом фона

4. Добавим стили, которые будут изменять фон пункта меню при наведении на него курсора:

CSS
/* для всех пунктов кроме активного */
.nav-scroller__item:not(.nav-scroller__item_active):hover {
  background-color: #f5f5f5;
}
/* для активного пункта */
.nav-scroller__item_active:hover {
  background-color: #fff176;
}
Изменение фона элемента меню при наведении на него курсора

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

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

Меню с горизонтальной прокруткой на устройствах с маленьким экраном

Посмотреть

Улучшения для меню с горизонтальной прокруткой

1. Выравнивание активного пункта по центру

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

JavaScript
document.addEventListener('DOMContentLoaded', () => {
  const $navItems = document.querySelector('.nav-scroller__items');
  const $navItemActive = $navItems.querySelector('.nav-scroller__item_active');
  if (!$navItemActive) {
    return;
  }  
  const navItemsRect = $navItems.getBoundingClientRect();
  const navItemActiveRect = $navItemActive.getBoundingClientRect();
  const navItemsLeft = navItemActiveRect.left - navItemsRect.left + (navItemActiveRect.width - navItemsRect.width) / 2;
  $navItems.scrollLeft = navItemsLeft;
});

Этот скрипт после готовности DOM дерева будет автоматически прокручивать меню так, чтобы элемент с классом nav-scroller__item_active оказывался если это возможно по центру.

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

Посмотреть

2. Прокручивания меню с помощью удерживания кнопки мыши

В этом улучшении уберём полосу прокрутки и подключим микро-библиотеку Dragscroll. Эта библиотека поможет нам очень просто добавить возможность прокрутки меню посредством удерживания кнопки мыши (стиль «перетащить и отпустить» или «щелкнуть и удерживать»).

Для этого в CSS добавим следующий код:

CSS
.nav-scroller__items::-webkit-scrollbar {
  display: none;
}

Это правило выключит отображение полосы прокрутки.

После этого на страницу подключим файл dragscroll.js:

HTML
<script defer src="js/dragscroll.js"></script>

Добавим класс dragscroll к прокручиваемому элементу:

HTML
<div class="nav-scroller">
  <nav class="nav-scroller__items dragscroll">
    <a class="nav-scroller__item" href="#">Start</a>
    <a class="nav-scroller__item" href="#">Icons</a>
    <a class="nav-scroller__item" href="#">Docs</a>
    <a class="nav-scroller__item nav-scroller__item_active" href="#">Support</a>
    <a class="nav-scroller__item" href="#">Plans</a>
    <a class="nav-scroller__item" href="#">Blog</a>
    <a class="nav-scroller__item" href="#">Sign in</a>
  </nav>
</div>
Горизонтальное меню, которого можно прокручивать с помощью удерживания кнопки мыши

Посмотреть

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

Vooddy
Vooddy

Здравствуйте, я не разобрался как написать текст внутри блока. Что бы при нажатии на блок открывался нужный текст или фото? Как на этом сайте: laraves.ru/autoshop/news/

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

Здравствуйте! Так укажите в href нужный адрес страницы или картинки.

Vooddy
Vooddy

Я это делаю. Там адрес сайта надо указать как я понимаю. А он у меня указывается как путь диска, где лежат все файлы, и я знаю, как его изменить.

Vooddy
Vooddy

Вот мой адрес сайта:

file:///D:/%D0%9A%D1%83%D1%80%D1%81%D0%BE%D0%B2%D0%B0%D1%8F.%20%D0%A1%D0%B0%D0%B9%D1%82/Kendo%20%D0%BD%D0%B0%20%D1%81%D0%BE%D0%B1%D0%BB%D0%B0%D0%B9%D0%BD%D0%B5/kendo%20%D0%BF%D1%80%D0%BE%D0%B1%D0%BD%D1%8B%D0%B9.html
Vooddy
Vooddy

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

Vooddy
Vooddy

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

<ul class="nav-scroller">
  <nav class="nav-scroller__items">
    <div>
      <a class="nav-scroller__item" href="About the Company" title="О компании"> О
        компании</a>
    </div>
    <div>
      <a class="nav-scroller__item" href="services" title="Услуги"> Услуги</a>
    </div>
    <div>
      <a class="nav-scroller__item" href="aktsii" title="Акции"> Акции</a>
    </div>
    <div>
      <a class="nav-scroller__item" href="gallery" title="Галлерея">Галлерея</a>
    </div>
    <div>
      <a class="nav-scroller__item" href="responses" title="Отзывы">Отзывы</a>
    </div>
    <div>
      <a class="nav-scroller__item" href="kontakty" title="Контакты">Контакты</a>
    </div>
    <div>
      <a class="nav-scroller__item" href="private office" title="Личный кабинет">Личный
        кабинет</a>
    </div>
    <div>
      <a class="nav-scroller__item" href="tel:+73512101212" title="Телефон ОП Кэндо">8 (351)
        210-12-12</a>
    </div>
    <div>
      <a class="nav-scroller__item" href="order a call" title="Заказать звонок">Заказать
        звонок</a>
    </div>
  </nav>
</ul>
Александр Мальцев
Александр Мальцев

На сколько понимаю, вы разрабатываете сайт без использования сервера. В этом случае нужно указывать относительные пути к файлам (для страниц не забывайте добавлять расширение html):

<a class="nav-scroller__item" href="services.html" title="Услуги">Услуги</a>
Rashid Gizzatov
Rashid Gizzatov
Добрый день! А как сделать активный пункт по центру при прокрутки страницы со соответствием показа определенного блока id?
sergejj
sergejj
Александр все работает, кроме ( Выравнивание активного пункта по центру ) подскажите в чем проблема может быть?
Александр Мальцев
Александр Мальцев
Код JavaScript добавили? В консоли есть какие-то ошибки?
sergejj
sergejj
Вот сам скрипт itchief.ru/assets/uploadify/f/1/b/f1bdf1a4bf3fe46925b60ee1cb440813.png в теге а после в вставлен код itchief.ru/assets/uploadify/3/a/1/3a1e4426f4bb577dc79a26a39e32cc3e.png Должно работать?
sergejj
sergejj
ошибок нет
Александр Мальцев
Александр Мальцев
Не знаю, если есть ссылка на страницу, то пришлите на email. Посмотрю.
sergejj
sergejj
а какая ваша почта, в профиль я в ваш зайти не могу.
Александр Мальцев
Александр Мальцев
В нижней части сайта: alexander@itchief.ru
Дмитрий
Дмитрий
Спасибо! Как убрать ошибку? ругается на код что выше для центрирования активного класса
Uncaught TypeError: Cannot read properties of null (reading 'getBoundingClientRect')
    at HTMLDocument.<anonymous> (main.js:464)
Александр Мальцев
Александр Мальцев
Возникает когда нет активного класса? Поправил этот момент: обновил код в статье и примерах.
Дмитрий
Дмитрий
Нет, сразу ошибка возникала, спасибо за код, он решил проблему, а на jquery можно это сделать?
Александр Мальцев
Александр Мальцев
На jQuery будет так (пример):
var $navItems = $('.nav-scroller__items');
var $navItemActive = $navItems.find('.nav-scroller__item_active');
if (!$navItemActive.length) {
  return;
}
$navItems.scrollLeft($navItemActive.position().left - $navItems.position().left + ($navItemActive.outerWidth() - $navItems.outerWidth()) / 2);
Дмитрий
Дмитрий
здорово спасибо, еще важный момент, а как сделать чтоб по переходу для внутренних страниц, класс оставлялся активным? допустим я в отдельной новости, тогда класс у раздела news теряется, а хотелось бы чтоб раздел оставался активным, пример у меня тут laraves.ru/autoshop/news/
Александр Мальцев
Александр Мальцев
Лучше это конечно реализовать на стороне сервера.
Если нужно на клиенте, то для этого достаточно написать следующий скрипт:
var pathname = location.pathname;
if (pathname.indexOf('/autoshop/news/') === 0) {
  $('[href="https://laraves.ru/autoshop/news/"]').parent().addClass('nav-scroller__item_active');
}
Дмитрий
Дмитрий
ок спасибо!
Kuka1012
Kuka1012
Вы как решили проблему? Вижу на вашем сайте все отлично работает уже неделю мучаюсь с этой меню