Как сделать меню-гамбургер без JavaScript
Короткий ответ
Скрытый флажок хранит состояние «открыто», label им управляет, а :has() показывает меню:
<style>
.nav { padding: 8px; background: navy; color: white; }
.nav input { position: absolute; opacity: 0; }
.nav label { cursor: pointer; font-size: 24px; }
.nav input:focus-visible + label { outline: 2px solid orange; }
.nav .links { display: none; flex-direction: column; gap: 6px; padding-top: 8px; }
.nav:has(input:checked) .links { display: flex; }
.nav a { color: white; }
</style>
<nav class="nav">
<input type="checkbox" id="burger" aria-label="Menu"><label for="burger">☰</label>
<div class="links"><a href="https://example.com">Home</a><a href="https://example.com">Shop</a><a href="https://example.com">About</a></div>
</nav>Только на телефоне
На широком экране кнопка не нужна — меню показывают всегда:
@media (min-width: 700px) {
.nav label { display: none; }
.nav .links { display: flex; flex-direction: row; }
}Вариант с popover
Атрибут popover даёт меню поверх страницы, закрытие по Esc и клику снаружи, а кнопка с popovertarget сообщает экранным дикторам, открыто меню или нет:
<button popovertarget="side" aria-label="Menu">☰</button>
<nav id="side" popover style="margin: 0; height: 100%; padding: 16px;"><a href="https://example.com">Home</a><br><a href="https://example.com">Shop</a></nav>Частая ошибка
Прячут флажок через display: none: тогда меню не открыть с клавиатуры. Скрывайте его визуально, как в первом примере, и дайте ему aria-label, ведь значок «☰» ничего не скажет экранному диктору.
Функции из этого ответа
- <input type="checkbox"> — Флажок (`checkbox`) — независимый выбор «да/нет»; переключатель (`radio`) — один вариант из группы.
- :has() — Выбирает элемент, внутри которого есть что-то подходящее под селектор в скобках, — «селектор родителя».
- :checked — Срабатывает у отмеченного флажка или переключателя и у выбранного `<option>`.
- <label> — Подпись к полю формы.