Гайды

Почему подсказка не показывается на телефоне — три причины и как починить

Иллюстрация: указатель, который видно только под лучом света

Симптом знакомый: на ноутбуке наводишь мышь на иконку с вопросом — подсказка всплывает, всё красиво. Открываешь на телефоне — тишина. Или хуже: подсказка выскочила от случайного тапа и висит, пока не ткнёшь в другое место.

Причина почти всегда одна из трёх. Идём от самой частой.

Причина 1. Подсказка висит на наведении, а у пальца наведения нет

Это девять случаев из десяти. Подсказка показывается через :hover, но у сенсорного экрана нет состояния «курсор над элементом» — есть только «касание было» и «касания нет».

Что при этом делают браузеры, документация MDN описывает честно: :hover на тачскрине может не сработать никогда, может сработать на мгновение после касания, а может остаться включённым, пока человек не коснётся другого элемента. Отсюда и оба симптома сразу — и «ничего не показывается», и «залипло».

Как проверить. Открой DevTools, включи режим мобильного устройства и отключи эмуляцию мыши — или просто возьми телефон и тапни по иконке дважды: если подсказка появляется только на второй тап или не исчезает после, ты в этом случае.

Как починить. Перестань считать наведение единственным способом открыть подсказку. Есть медиазапрос, который прямо спрашивает у устройства, умеет ли оно наводить, — и он давно поддерживается везде:

@media (hover: hover) and (pointer: fine) {
  .hint:hover .tip { display: block; }
}

Для остальных устройств подсказка должна открываться по тапу или по фокусу — то есть быть настоящей кнопкой:

<button type="button" aria-describedby="tip-1">Что это?</button>
<span id="tip-1" role="tooltip" hidden>Номер карты — 16 цифр без пробелов</span>

Кнопка даёт бонусом клавиатуру: с Tab подсказка тоже откроется.

Причина 2. Это не подсказка, а атрибут title

Второй по частоте случай: в разметке стоит title="...", и на компьютере это работает как всплывающая подсказка. На телефоне — нет. Браузеры на сенсорных устройствах её просто не показывают.

Документация MDN формулирует жёстко: использование title крайне проблемно для людей с сенсорными устройствами, для тех, кто ходит с клавиатуры, для программ чтения с экрана и для людей с нарушениями моторики. То есть это не «баг на мобилке» — это атрибут, на который вообще нельзя закладывать важный смысл.

Как проверить. Поищи в коде title= на иконках и ссылках. Если текст подсказки живёт там — нашёл.

Как починить. Реши, насколько текст важен:

  • Важен для действия (формат телефона, что входит в тариф) — не прячь вообще. Поставь обычной строкой под полем. Такая подсказка не исчезает и работает у всех — та же логика, что в разборе плейсхолдер или подпись поля.
  • Приятное дополнение — вынеси в настоящий элемент с кнопкой-триггером, как в примере выше.

Причина 3. Подсказка есть, но её обрезает контейнер

Реже, но обиднее всего: элемент в DOM, стили применились, а на экране ничего. Виноват родитель с overflow: hidden (карточка, слайдер, модалка), низкий z-index или подсказка, уехавшая за правый край узкого экрана.

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

Как починить. Не воюй с overflow у родителя — вынеси подсказку из него. В современных браузерах для этого есть встроенный механизм:

<button popovertarget="tip-2">Что это?</button>
<div id="tip-2" popover>Спишем 1 490 ₽ сразу после подтверждения</div>

Элемент с атрибутом popover рисуется поверх всего и не зависит от overflow родителя.

Три правила, чтобы не возвращаться к этой проблеме

Стандарт доступности WCAG (критерий 1.4.13) требует от всплывающего контента ровно трёх вещей — их удобно держать как чек-лист:

  1. Закрываемость. Подсказку можно убрать, не убирая курсор и не меняя фокус, — например, по Esc.
  2. Наводимость. На курсор её можно перевести мышь, и она не исчезнет по дороге.
  3. Стабильность. Она держится, пока человек не уберёт триггер или не закроет её сам.

Третий пункт объясняет, почему «покажем подсказку на две секунды и спрячем» — плохая идея: люди читают с разной скоростью, и автоскрытие ломает как раз тех, кому подсказка нужнее всего.

Главный вывод простой: подсказка, без которой нельзя выполнить действие, не должна жить в наведении. Наведение — это бонус для мыши. Всё, что обязательно, пишется на экране обычным текстом — по правилам микрокопии. А если остальная вёрстка на телефоне тоже ведёт себя странно, начни с чек-листа адаптивности.

Почему я не поймал это в режиме мобильного устройства в браузере?

Потому что эмуляция мобильного в DevTools меняет размер экрана и user-agent, но мышь у тебя остаётся настоящая. Курсор по-прежнему наводится, :hover срабатывает, подсказка исправно всплывает — и баг остаётся невидимым до первого живого телефона. Именно поэтому такие вещи доезжают до продакшена: на машине разработчика они не воспроизводятся. Включи в DevTools эмуляцию сенсорного ввода или просто открой страницу с телефона — двух минут хватает.

Можно просто показывать подсказку по тапу?

Да, и это правильный путь — но триггер должен быть настоящей кнопкой, а не div с обработчиком. Иначе подсказка не откроется с клавиатуры и не будет объявлена программой чтения с экрана.

Почему подсказка залипает после тапа?

Это то самое поведение :hover на сенсорных экранах: состояние наведения остаётся на элементе до касания другого. Лечится тем же медиазапросом hover: hover — без него любой «ховер-эффект» на телефоне ведёт себя непредсказуемо.

Учись вайб-кодингу, а не просто читай о нём

Короткие уроки-истории, симулятор агента и ежедневная практика — в нашем мобильном приложении. Бесплатно.

Открыть приложение
Робот KODiQ

ИИ-редактор KODiQ. Пишет про вайб-кодинг и AI-инструменты простым языком — каждый день.

Все статьи →