Пустая ссылка — тег <a> без адреса или с заглушкой:
<a href="#">Каталог</a>
<a>Услуги</a>
<a href="javascript:void(0)" onclick="openMenu()">Меню</a>
Внешне это выглядит как обычная ссылка, но перехода никуда не происходит.
Откуда берутся
Раскрывающиеся меню. Пункт верхнего уровня служит переключателем подменю и не ведёт на страницу.
Кнопки, сделанные ссылками. «Показать ещё», «Открыть форму», «Закрыть» — это действия, а не переходы, но верстают их часто тегом <a>.
Недоделанная разработка. Раздел ещё не готов, ссылку оставили пустой «до лучших времён».
Якоря без цели. href="#" в надежде «прокрутить наверх», без соответствующего элемента на странице.
Чем плохо
Робот теряет маршрут. Пункт меню, который выглядит как раздел, но не является ссылкой, не ведёт робота никуда. Если подменю раскрывается скриптом, то и вложенные страницы могут остаться ненайденными (про перелинковку).
Прыжок наверх. href="#" при нажатии прокручивает страницу в начало — раздражающее поведение, особенно на длинных страницах, где человек уже пролистал до середины.
Клавиатурная навигация ломается. Пустая ссылка получает фокус при переходе по Tab, но нажатие ничего не делает. Для человека, работающего без мыши, это тупик.
Скринридер объявляет ссылку без адреса — пользователь слышит «ссылка Каталог» и не может по ней перейти.
Как делать правильно
Элемент выполняет действие — это кнопка:
<button type="button" onclick="openMenu()">Меню</button>
Кнопку можно стилизовать как угодно, включая «как ссылку». Зато она правильно работает с клавиатуры, корректно объявляется скринридером и не сбивает робота.
Пункт меню с подменю — ведёт на страницу раздела:
<a href="/catalog/">Каталог</a>
Раздел-страница почти всегда полезна: это и посадочная под запрос, и точка входа для робота. Если её действительно нет — используйте кнопку, а не пустую ссылку.
Раздел ещё не готов — уберите ссылку до запуска, а не оставляйте заглушку.
Прокрутка наверх — кнопка со скриптом, а не href="#".
Как проверить
- Пункт аудита «Пустые ссылки» считает ссылки без
hrefи сhref="#". - В консоли браузера:
document.querySelectorAll('a:not([href]), a[href="#"], a[href^="javascript:"]')
.forEach(a => console.log(a.textContent.trim()));
Пройдите по результатам и решите для каждой: это должна быть кнопка или у неё есть настоящий адрес.