Overflow первого уровня, брейкпоинты, гамбургер и интеграция с VGSidebar.
Примеры используют VGApp и OKAUX 1.0.2. Подключите стили обоих пакетов
и выполняйте JavaScript после появления разметки. У VGNav нет автоматического
поиска всех меню: для каждого корня нужен один вызов VGNav.init().
Одно меню — два представления
При ширине окна меньше 992 px (md в VGNav) появляется гамбургер. Боковая панель содержит отдельную вертикальную навигацию: VGNav не клонирует пункты автоматически. Кнопка «Открыть панель» позволяет проверить её и на десктопе.
Открыть панель
Панель закрывается крестиком, по фону или Escape.
Показать код
<nav id="nav-demo-responsive" class="vg-nav nav-demo" data-nav-demo aria-label="Адаптивное меню">
<ul class="vg-nav-wrapper">
<li><a href="#nav-responsive-result">Обзор</a></li>
<li><a href="#nav-responsive-result">Документы</a></li>
</ul>
</nav>
<button type="button" class="btn btn-surface btn-sm" data-vg-toggle="sidebar"
data-vg-target="#nav-demo-sidebar">Открыть панель</button>
<p id="nav-responsive-result" class="nav-demo-result">Панель закрывается крестиком, по фону или Escape.</p>
<div id="nav-demo-sidebar" class="vg-sidebar right nav-demo-sidebar">
<div class="vg-sidebar-header">
<div class="vg-sidebar-header--title">Разделы проекта</div>
<button type="button" class="vg-btn-close" data-vg-dismiss="sidebar"
data-vg-target="#nav-demo-sidebar" aria-label="Закрыть меню"></button>
</div>
<div class="vg-sidebar-body">
<nav id="nav-demo-mobile" class="vg-nav nav-demo" data-nav-demo aria-label="Меню в боковой панели">
<ul class="vg-nav-wrapper">
<li><a href="#nav-responsive-result" data-vg-dismiss="sidebar"
data-vg-target="#nav-demo-sidebar">Обзор</a></li>
<li><a href="#nav-responsive-result" data-vg-dismiss="sidebar"
data-vg-target="#nav-demo-sidebar">Документы</a></li>
</ul>
</nav>
</div>
</div>
/**
* Описание: рабочий пример VGNav — responsive.
* Возможности: демонстрирует адаптивный гамбургер и интеграцию с VGSidebar.
*/
import { VGNav, VGSidebar } from 'vgapp';
function initNavDemo() {
const root = document.querySelector('#nav-demo-responsive');
if (!root || VGNav.getInstance(root)) return;
// Панель должна быть вне stacking context секций страницы, на уровне backdrop.
const sidebar = document.querySelector('#nav-demo-sidebar');
document.body.append(sidebar);
VGSidebar.getOrCreateInstance(sidebar);
VGNav.init(root, {
breakpoint: 'md',
hover: false,
hamburger: { title: 'Разделы', target: '#nav-demo-sidebar' }
});
VGNav.init(document.querySelector('#nav-demo-mobile'), {
breakpoint: false,
placement: 'vertical',
hover: false,
hamburger: { enable: false }
});
}
initNavDemo();
/* Композиция примеров; поведение dropdown остаётся в VGNav. Токены — OKAUX. */
.vg-nav.nav-demo {
--vg-nav-item-padding: .75rem 1rem;
--vg-nav-item-white-space: normal;
--vg-nav-drop-width: min(16rem, calc(100vw - 3rem));
--vg-nav-drop-border-radius: .75rem;
--vg-nav-drop-item-bg-hover: var(--vg-background-tertiary);
--vg-nav-drop-item-color-hover: var(--vg-text-primary);
--vg-nav-drop-mega-min-height: 0;
--vg-nav-drop-mega-border-radius: .75rem;
--vg-nav-drop-mega-width: min(30rem, calc(100vw - 3rem));
min-width: 0;
}
.nav-demo > .vg-nav-wrapper {
flex-wrap: wrap;
}
.nav-demo.vg-nav-overflow-enabled > .vg-nav-wrapper {
flex-wrap: nowrap;
}
.nav-demo.vg-nav-overflow-enabled {
--vg-nav-item-white-space: nowrap;
}
.nav-demo-overflow-frame {
width: 100%;
max-width: 100%;
transition: width .25s ease;
}
.nav-demo-overflow-frame.is-narrow {
width: min(22rem, 100%);
}
.nav-demo-overflow-frame .vg-nav {
width: 100%;
}
/* Резерв места под dropdown, чтобы он не перекрывал кнопку раскрытия кода. */
.nav-demo--dropdown {
min-height: 14rem;
}
.vg-nav.nav-demo--directions {
--vg-nav-drop-width: min(13rem, calc(100vw - 3rem));
min-height: 22rem;
}
.nav-demo--directions > .vg-nav-wrapper {
justify-content: flex-end;
}
.nav-demo-directions {
white-space: pre-line;
}
@media (max-width: 600px) {
.vg-nav.nav-demo--directions {
min-height: 30rem;
}
}
.nav-demo .vg-nav-drop-list {
margin: 0;
padding: 0;
list-style: none;
}
.nav-demo--scroll {
--vg-nav-drop-max-height: 12rem;
min-height: 17rem;
}
.nav-demo-mega-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(min(100%, 10rem), 1fr));
gap: 1rem;
}
.nav-demo-mega-grid a {
display: block;
padding: .5rem 0;
}
.nav-demo-result {
display: block;
margin-top: 1rem;
padding: .75rem;
border: 1px solid var(--vg-border-default);
border-radius: .5rem;
background: var(--vg-background-secondary);
color: var(--vg-text-primary);
overflow-wrap: anywhere;
}
.nav-demo-actions {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: .75rem;
margin-bottom: 1rem;
}
.nav-demo-sidebar {
--vg-sidebar-horizontal-width: min(22rem, 100vw);
--vg-sidebar-padding: 1.25rem;
}
.nav-demo-log {
max-height: 12rem;
overflow-y: auto;
white-space: pre-wrap;
}
Автоматический перенос по ширине
VGNav следит за шириной собственного контейнера. Переключайте ширину: последние пункты перемещаются в dropdown с тремя вертикальными точками и возвращаются в исходном порядке.
Широкий контейнер
Узкий контейнер
Сузьте контейнер: последние пункты перейдут под иконку с тремя точками.
Показать код
<div class="nav-demo-actions">
<button class="btn btn-sm" type="button" data-nav-overflow-width="wide">Широкий контейнер</button>
<button class="btn btn-sm" type="button" data-nav-overflow-width="narrow">Узкий контейнер</button>
</div>
<div id="nav-demo-overflow-auto-frame" class="nav-demo-overflow-frame">
<nav id="nav-demo-overflow-auto" class="vg-nav nav-demo nav-demo--dropdown" data-nav-demo
aria-label="Автоматический overflow меню">
<ul class="vg-nav-wrapper">
<li><a href="#nav-overflow-auto-result">Главная</a></li>
<li><a href="#nav-overflow-auto-result">О компании</a></li>
<li><a href="#nav-overflow-auto-result">Каталог</a></li>
<li><a href="#nav-overflow-auto-result">Доставка</a></li>
<li><a href="#nav-overflow-auto-result">Гарантия</a></li>
<li><a href="#nav-overflow-auto-result">Контакты</a></li>
</ul>
</nav>
</div>
<p id="nav-overflow-auto-result" class="nav-demo-result">Сузьте контейнер: последние пункты перейдут под иконку с тремя точками.</p>
/**
* Описание: пример автоматического overflow горизонтального VGNav по ширине контейнера.
* Возможности: переключает ширину контейнера и показывает перенос и возврат пунктов первого уровня.
*/
import { VGNav } from 'vgapp';
function initNavDemo() {
const root = document.querySelector('#nav-demo-overflow-auto');
const frame = document.querySelector('#nav-demo-overflow-auto-frame');
if (!root || !frame || VGNav.getInstance(root)) return;
VGNav.init(root, {
breakpoint: false,
hover: false,
hamburger: { enable: false },
overflow: { enable: true },
});
frame.closest('.module-demo-example')?.querySelectorAll('[data-nav-overflow-width]').forEach((button) => {
button.addEventListener('click', () => {
frame.classList.toggle('is-narrow', button.dataset.navOverflowWidth === 'narrow');
});
});
}
initNavDemo();
/* Композиция примеров; поведение dropdown остаётся в VGNav. Токены — OKAUX. */
.vg-nav.nav-demo {
--vg-nav-item-padding: .75rem 1rem;
--vg-nav-item-white-space: normal;
--vg-nav-drop-width: min(16rem, calc(100vw - 3rem));
--vg-nav-drop-border-radius: .75rem;
--vg-nav-drop-item-bg-hover: var(--vg-background-tertiary);
--vg-nav-drop-item-color-hover: var(--vg-text-primary);
--vg-nav-drop-mega-min-height: 0;
--vg-nav-drop-mega-border-radius: .75rem;
--vg-nav-drop-mega-width: min(30rem, calc(100vw - 3rem));
min-width: 0;
}
.nav-demo > .vg-nav-wrapper {
flex-wrap: wrap;
}
.nav-demo.vg-nav-overflow-enabled > .vg-nav-wrapper {
flex-wrap: nowrap;
}
.nav-demo.vg-nav-overflow-enabled {
--vg-nav-item-white-space: nowrap;
}
.nav-demo-overflow-frame {
width: 100%;
max-width: 100%;
transition: width .25s ease;
}
.nav-demo-overflow-frame.is-narrow {
width: min(22rem, 100%);
}
.nav-demo-overflow-frame .vg-nav {
width: 100%;
}
/* Резерв места под dropdown, чтобы он не перекрывал кнопку раскрытия кода. */
.nav-demo--dropdown {
min-height: 14rem;
}
.vg-nav.nav-demo--directions {
--vg-nav-drop-width: min(13rem, calc(100vw - 3rem));
min-height: 22rem;
}
.nav-demo--directions > .vg-nav-wrapper {
justify-content: flex-end;
}
.nav-demo-directions {
white-space: pre-line;
}
@media (max-width: 600px) {
.vg-nav.nav-demo--directions {
min-height: 30rem;
}
}
.nav-demo .vg-nav-drop-list {
margin: 0;
padding: 0;
list-style: none;
}
.nav-demo--scroll {
--vg-nav-drop-max-height: 12rem;
min-height: 17rem;
}
.nav-demo-mega-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(min(100%, 10rem), 1fr));
gap: 1rem;
}
.nav-demo-mega-grid a {
display: block;
padding: .5rem 0;
}
.nav-demo-result {
display: block;
margin-top: 1rem;
padding: .75rem;
border: 1px solid var(--vg-border-default);
border-radius: .5rem;
background: var(--vg-background-secondary);
color: var(--vg-text-primary);
overflow-wrap: anywhere;
}
.nav-demo-actions {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: .75rem;
margin-bottom: 1rem;
}
.nav-demo-sidebar {
--vg-sidebar-horizontal-width: min(22rem, 100vw);
--vg-sidebar-padding: 1.25rem;
}
.nav-demo-log {
max-height: 12rem;
overflow-y: auto;
white-space: pre-wrap;
}
Ограничение количества пунктов
overflow.count: 3 оставляет снаружи максимум три исходных пункта независимо от свободного места. Значение 0 отключает ограничение количества, но сохраняет автоматический перенос по ширине.
Даже на широком контейнере снаружи остаются максимум три исходных пункта.
Показать код
<nav id="nav-demo-overflow-count" class="vg-nav nav-demo nav-demo--dropdown" data-nav-demo
aria-label="Меню с ограничением количества пунктов">
<ul class="vg-nav-wrapper">
<li><a href="#nav-overflow-count-result">Обзор</a></li>
<li><a href="#nav-overflow-count-result">Проекты</a></li>
<li><a href="#nav-overflow-count-result">Команда</a></li>
<li><a href="#nav-overflow-count-result">Документы</a></li>
<li><a href="#nav-overflow-count-result">История</a></li>
<li><a href="#nav-overflow-count-result">Настройки</a></li>
</ul>
</nav>
<p id="nav-overflow-count-result" class="nav-demo-result">Даже на широком контейнере снаружи остаются максимум три исходных пункта.</p>
/**
* Описание: пример ограничения числа видимых пунктов горизонтального VGNav.
* Возможности: демонстрирует overflow.count независимо от свободной ширины контейнера.
*/
import { VGNav } from 'vgapp';
function initNavDemo() {
const root = document.querySelector('#nav-demo-overflow-count');
if (!root || VGNav.getInstance(root)) return;
VGNav.init(root, {
breakpoint: false,
hover: false,
hamburger: { enable: false },
overflow: {
enable: true,
count: 3,
},
});
}
initNavDemo();
/* Композиция примеров; поведение dropdown остаётся в VGNav. Токены — OKAUX. */
.vg-nav.nav-demo {
--vg-nav-item-padding: .75rem 1rem;
--vg-nav-item-white-space: normal;
--vg-nav-drop-width: min(16rem, calc(100vw - 3rem));
--vg-nav-drop-border-radius: .75rem;
--vg-nav-drop-item-bg-hover: var(--vg-background-tertiary);
--vg-nav-drop-item-color-hover: var(--vg-text-primary);
--vg-nav-drop-mega-min-height: 0;
--vg-nav-drop-mega-border-radius: .75rem;
--vg-nav-drop-mega-width: min(30rem, calc(100vw - 3rem));
min-width: 0;
}
.nav-demo > .vg-nav-wrapper {
flex-wrap: wrap;
}
.nav-demo.vg-nav-overflow-enabled > .vg-nav-wrapper {
flex-wrap: nowrap;
}
.nav-demo.vg-nav-overflow-enabled {
--vg-nav-item-white-space: nowrap;
}
.nav-demo-overflow-frame {
width: 100%;
max-width: 100%;
transition: width .25s ease;
}
.nav-demo-overflow-frame.is-narrow {
width: min(22rem, 100%);
}
.nav-demo-overflow-frame .vg-nav {
width: 100%;
}
/* Резерв места под dropdown, чтобы он не перекрывал кнопку раскрытия кода. */
.nav-demo--dropdown {
min-height: 14rem;
}
.vg-nav.nav-demo--directions {
--vg-nav-drop-width: min(13rem, calc(100vw - 3rem));
min-height: 22rem;
}
.nav-demo--directions > .vg-nav-wrapper {
justify-content: flex-end;
}
.nav-demo-directions {
white-space: pre-line;
}
@media (max-width: 600px) {
.vg-nav.nav-demo--directions {
min-height: 30rem;
}
}
.nav-demo .vg-nav-drop-list {
margin: 0;
padding: 0;
list-style: none;
}
.nav-demo--scroll {
--vg-nav-drop-max-height: 12rem;
min-height: 17rem;
}
.nav-demo-mega-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(min(100%, 10rem), 1fr));
gap: 1rem;
}
.nav-demo-mega-grid a {
display: block;
padding: .5rem 0;
}
.nav-demo-result {
display: block;
margin-top: 1rem;
padding: .75rem;
border: 1px solid var(--vg-border-default);
border-radius: .5rem;
background: var(--vg-background-secondary);
color: var(--vg-text-primary);
overflow-wrap: anywhere;
}
.nav-demo-actions {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: .75rem;
margin-bottom: 1rem;
}
.nav-demo-sidebar {
--vg-sidebar-horizontal-width: min(22rem, 100vw);
--vg-sidebar-padding: 1.25rem;
}
.nav-demo-log {
max-height: 12rem;
overflow-y: auto;
white-space: pre-wrap;
}
Закреплённый и вложенный пункты
Атрибут data-vg-nav-overflow="keep" запрещает перенос пункта. Обычный dropdown первого уровня можно перенести: внутри меню с точками он продолжает открываться как вложенный уровень.
«Главная» закреплена снаружи. Откройте точки, затем пункт «Сервисы» — его вложенный dropdown сохранён.
Показать код
<nav id="nav-demo-overflow-nested" class="vg-nav nav-demo nav-demo--dropdown" data-nav-demo
aria-label="Overflow с вложенным меню">
<ul class="vg-nav-wrapper">
<li data-vg-nav-overflow="keep"><a href="#nav-overflow-nested-result">Главная</a></li>
<li><a href="#nav-overflow-nested-result">Новости</a></li>
<li class="dropdown">
<a href="#nav-overflow-nested-result">Сервисы</a>
<div class="dropdown-content">
<ul class="vg-nav-drop-list">
<li><a href="#nav-overflow-nested-result">Аналитика</a></li>
<li><a href="#nav-overflow-nested-result">Интеграции</a></li>
<li><a href="#nav-overflow-nested-result">Автоматизация</a></li>
</ul>
</div>
</li>
<li><a href="#nav-overflow-nested-result">Поддержка</a></li>
</ul>
</nav>
<p id="nav-overflow-nested-result" class="nav-demo-result">«Главная» закреплена снаружи. Откройте точки, затем пункт «Сервисы» — его вложенный dropdown сохранён.</p>
/**
* Описание: пример overflow с закреплённым пунктом и вложенным dropdown VGNav.
* Возможности: демонстрирует data-vg-nav-overflow="keep" и сохранение вложенного уровня после переноса.
*/
import { VGNav } from 'vgapp';
function initNavDemo() {
const root = document.querySelector('#nav-demo-overflow-nested');
if (!root || VGNav.getInstance(root)) return;
VGNav.init(root, {
breakpoint: false,
hover: false,
hamburger: { enable: false },
overflow: {
enable: true,
count: 2,
},
});
}
initNavDemo();
/* Композиция примеров; поведение dropdown остаётся в VGNav. Токены — OKAUX. */
.vg-nav.nav-demo {
--vg-nav-item-padding: .75rem 1rem;
--vg-nav-item-white-space: normal;
--vg-nav-drop-width: min(16rem, calc(100vw - 3rem));
--vg-nav-drop-border-radius: .75rem;
--vg-nav-drop-item-bg-hover: var(--vg-background-tertiary);
--vg-nav-drop-item-color-hover: var(--vg-text-primary);
--vg-nav-drop-mega-min-height: 0;
--vg-nav-drop-mega-border-radius: .75rem;
--vg-nav-drop-mega-width: min(30rem, calc(100vw - 3rem));
min-width: 0;
}
.nav-demo > .vg-nav-wrapper {
flex-wrap: wrap;
}
.nav-demo.vg-nav-overflow-enabled > .vg-nav-wrapper {
flex-wrap: nowrap;
}
.nav-demo.vg-nav-overflow-enabled {
--vg-nav-item-white-space: nowrap;
}
.nav-demo-overflow-frame {
width: 100%;
max-width: 100%;
transition: width .25s ease;
}
.nav-demo-overflow-frame.is-narrow {
width: min(22rem, 100%);
}
.nav-demo-overflow-frame .vg-nav {
width: 100%;
}
/* Резерв места под dropdown, чтобы он не перекрывал кнопку раскрытия кода. */
.nav-demo--dropdown {
min-height: 14rem;
}
.vg-nav.nav-demo--directions {
--vg-nav-drop-width: min(13rem, calc(100vw - 3rem));
min-height: 22rem;
}
.nav-demo--directions > .vg-nav-wrapper {
justify-content: flex-end;
}
.nav-demo-directions {
white-space: pre-line;
}
@media (max-width: 600px) {
.vg-nav.nav-demo--directions {
min-height: 30rem;
}
}
.nav-demo .vg-nav-drop-list {
margin: 0;
padding: 0;
list-style: none;
}
.nav-demo--scroll {
--vg-nav-drop-max-height: 12rem;
min-height: 17rem;
}
.nav-demo-mega-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(min(100%, 10rem), 1fr));
gap: 1rem;
}
.nav-demo-mega-grid a {
display: block;
padding: .5rem 0;
}
.nav-demo-result {
display: block;
margin-top: 1rem;
padding: .75rem;
border: 1px solid var(--vg-border-default);
border-radius: .5rem;
background: var(--vg-background-secondary);
color: var(--vg-text-primary);
overflow-wrap: anywhere;
}
.nav-demo-actions {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: .75rem;
margin-bottom: 1rem;
}
.nav-demo-sidebar {
--vg-sidebar-horizontal-width: min(22rem, 100vw);
--vg-sidebar-padding: 1.25rem;
}
.nav-demo-log {
max-height: 12rem;
overflow-y: auto;
white-space: pre-wrap;
}
Брейкпоинты VGNav
Это ширина окна, не контейнера и не одноимённые брейкпоинты OKAUX.
xs / sm / md 576 / 768 / 992 px.
lg / xl / xxl / xxxl 1200 / 1400 / 1600 / 1800 px. По умолчанию — lg.
breakpoint: false Меню остаётся развёрнутым на любой ширине.
hamburger.always: true Всегда скрывает основной список и показывает гамбургер.
hamburger.enable: false Запрещает создание гамбургера, но не отключает брейкпоинт. Для постоянно видимого меню задайте также breakpoint: false.
hamburger.target Селектор существующего VGSidebar. Для независимых меню задавайте разные id панелей.
Слой панели Размещайте VGSidebar непосредственно в body, вне stacking context секций. В примере это делает JavaScript, чтобы заголовок и кнопка закрытия оставались над backdrop.