Avatar ·

Какой href использовать для JavaScript-ссылок: "#" или "javascript:void(0)"?

Всем привет! Я начинающий фронтенд-разработчик и столкнулся с дилеммой. Когда я делаю ссылки, которые должны выполнять JavaScript-код, а не переходить по URL, я не знаю, что писать в атрибуте `href`. Раньше я просто писал `href="#"`, но заметил, что страница прокручивается вверх, хотя я возвращаю `false` из обработчика. Недавно увидел код, где используют `href="javascript:void(0)"`. Но мне это кажется странным — смешивать JavaScript с HTML. Вот пример моей текущей реализации: ```html Нажми меня Нажми меня Нажми меня ``` Проблемы, с которыми я столкнулся: 1. С `href="#"` — если забыть `return false`, страница прыгает вверх. 2. С `javascript:void(0)` — в адресной строке иногда появляется `javascript:void(0)`, и кнопка "Назад" не работает. 3. Без `href` — ссылка не выглядит как ссылка (нет подчёркивания, курсор не меняется). Какой вариант правильный? Может, есть ещё какие-то лучшие практики? И влияет ли это на производительность или доступность (accessibility)? Буду благодарен за подробное объяснение с примерами! <<>>

Краткий ответ: используйте href="javascript:void(0)" или, что ещё лучше, отказывайтесь от href в пользу кнопок

Давайте разберём каждый вариант и выясним, какой из них действительно правильный с точки зрения современных стандартов, производительности и доступности.

Почему href="#" — плохой вариант

Это самый распространённый, но и самый проблемный подход. Проблемы:

  • Прокрутка вверх: Даже с return false легко забыть его добавить. Если обработчик выбросит исключение, прокрутка всё равно произойдёт.
  • Изменение URL: Добавляет # в адресную строку, что ломает историю браузера.
  • Семантическая проблема: # означает якорь (ссылку на фрагмент страницы), а не "ничего не делать".

Почему javascript:void(0) лучше, но не идеально

Этот вариант решает проблему прокрутки и не требует return false:

<a href="javascript:void(0)" onclick="myFunction();">Нажми меня</a>

Плюсы:

  • Не происходит прокрутка
  • Не меняется URL
  • Работает даже если JavaScript отключён (просто ничего не происходит)

Минусы:

  • Нарушение разделения контента и поведения: JavaScript в HTML — это антипаттерн. Если пользователь скопирует ссылку, в буфере окажется странный URL.
  • Проблемы с доступностью: Скринридеры могут неправильно интерпретировать такую ссылку.
  • Производительность: Браузер должен выполнить void(0) как JavaScript-код, что добавляет микро-задержку (хотя на практике это незаметно).

Лучшая практика (современный подход)

Вариант A: Используйте <button> вместо <a>

Если элемент выполняет действие (открыть модалку, отправить форму, запустить анимацию) — это кнопка, а не ссылка. Ссылка нужна для навигации.

<button type="button" onclick="myFunction();">Нажми меня</button>

Плюсы:

  • Семантически правильно (скринридеры скажут "кнопка")
  • Не требует href
  • Можно стилизовать как ссылку через CSS
  • Работает с клавиатуры (Tab, Enter/Space)

Вариант B: Если обязательно нужна ссылка — используйте href="javascript:void(0)" + event.preventDefault()

<a href="javascript:void(0)" id="myLink">Нажми меня</a>

<script>
  document.getElementById('myLink').addEventListener('click', function(e) {
    e.preventDefault(); // На всякий случай
    myFunction();
  });
</script>

Этот подход:

  • Сохраняет внешний вид ссылки
  • Не требует return false в HTML
  • Разделяет HTML и JavaScript

Производительность и доступность

Производительность: Разница между # и javascript:void(0) настолько мала, что вы её никогда не заметите. Гораздо важнее правильно структурировать код.

Доступность:

  • <button> — лучший выбор для действий
  • Если используете <a>, добавьте role="button" и tabindex="0" при необходимости
  • Всегда используйте addEventListener вместо onclick в HTML

Итоговая рекомендация

  1. Для действий (открыть/закрыть, отправить, выполнить JS): используйте <button type="button">
  2. Для навигации (переход на другую страницу или якорь): используйте <a href="...">
  3. Если нужна ссылка с JS-действием: <a href="javascript:void(0)"> + addEventListener
  4. Никогда не используйте href="#" для JavaScript-ссылок
<<>>

Альтернативный подход: обработка события на уровне родителя (делегирование)

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

<div id="linksContainer">
  <a href="javascript:void(0)" class="js-action" data-action="openModal">Открыть модалку</a>
  <a href="javascript:void(0)" class="js-action" data-action="saveData">Сохранить</a>
  <a href="javascript:void(0)" class="js-action" data-action="deleteItem">Удалить</a>
</div>

<script>
  document.getElementById('linksContainer').addEventListener('click', function(e) {
    const link = e.target.closest('.js-action');
    if (!link) return;
    
    e.preventDefault();
    
    const action = link.dataset.action;
    switch(action) {
      case 'openModal': openModal(); break;
      case 'saveData': saveData(); break;
      case 'deleteItem': deleteItem(); break;
    }
  });
</script>

Преимущества этого подхода:

  • Один обработчик вместо множества — экономия памяти
  • Автоматически работает для новых ссылок, добавленных через JavaScript
  • Код чище и легче поддерживать
  • Можно легко добавить дополнительную логику (логирование, аналитику) в одном месте

Важный нюанс: Даже при делегировании href="javascript:void(0)" остаётся хорошим выбором, потому что:

  • Ссылка визуально остаётся ссылкой
  • При случайном клике (если JavaScript ещё не загрузился) ничего не произойдёт
  • Не ломает историю браузера

Этот подход особенно рекомендуется, если вы используете современные фреймворки (React, Vue, Angular), где управление событиями часто происходит на уровне компонентов.