Гайды

Как определить сенсорный экран в JavaScript и CSS — и почему ontouchstart врёт

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

Самый популярный ответ на этот вопрос — 'ontouchstart' in window. Он ошибается в обе стороны.

На ноутбуке с сенсорным экраном он скажет «тач», хотя человек весь день работает мышкой. А на iPad Safari по умолчанию притворяется компьютером Mac: в его user agent написано Macintosh. Проверка по user agent скажет «десктоп» — и человек получит меню, которое открывается только наведением.

Хорошая новость: правильный способ короче неправильного. Разберём по шагам.

Шаг 1. Реши, что тебе на самом деле нужно

«Это тач-устройство?» — почти всегда не тот вопрос. На самом деле тебя волнует одно из двух:

  1. Умеет ли устройство наводить? Если нет — эффекты на :hover и всплывающие подсказки не сработают.
  2. Насколько точный указатель? Палец — грубый, мышь — точная. Для пальца нужны кнопки крупнее.

Под каждый вопрос в браузере есть свой точный инструмент.

Шаг 2. Прячь hover-эффекты за проверкой в CSS

Вместо того чтобы угадывать тип устройства, спроси браузер напрямую:

/* эффект при наведении — только там, где наведение реально есть */
@media (hover: hover) and (pointer: fine) {
  .card:hover {
    transform: translateY(-4px);
  }
}

hover: hover — основной указатель умеет наводить. pointer: fine — он точный, как мышь. На телефоне правило просто не включится. И больше не будет «залипшего» hover, который на мобильном срабатывает от касания и не уходит.

Если у тебя на hover держится что-то важное — например, подсказка, — разбор есть в статье почему подсказка не показывается на телефоне.

Есть и обратный приём: на устройствах без наведения покажи то, что обычно прячется под hover. Например, кнопки «редактировать» и «удалить» у карточки:

@media (hover: none) {
  .card .actions { opacity: 1; }
}

На компьютере они появляются при наведении, а на телефоне видны всегда. Палец до них дотянется.

Шаг 3. Увеличь цели касания для пальца

@media (pointer: coarse) {
  button, a.nav-link {
    min-height: 44px;
    min-width: 44px;
  }
}

pointer: coarse — основной указатель грубый, то есть палец. 44 точки — минимальный размер кнопки из рекомендаций Apple для iPhone. Меньше — и человек промахивается.

Шаг 4. Если нужно в JavaScript — используй те же запросы

Те же условия доступны из кода через matchMedia:

const coarse = window.matchMedia("(pointer: coarse)");

if (coarse.matches) {
  enableSwipeGallery();
}

coarse.addEventListener("change", (e) => {
  // планшет подключили к клавиатуре с тачпадом — основной указатель сменился
  e.matches ? enableSwipeGallery() : disableSwipeGallery();
});

Обрати внимание на change. Устройство может сменить основной указатель прямо во время работы: планшет пристегнули к клавиатуре с тачпадом. Проверка один раз при загрузке это пропустит.

Шаг 5. Нужно «есть ли тач вообще» — бери any-pointer

pointer и hover смотрят только на основной указатель. Если важно, есть ли хоть один сенсор среди всех, есть приставка any-:

const hasAnyTouch = window.matchMedia("(any-pointer: coarse)").matches;

На ноутбуке с сенсорным экраном: pointer: fine (главное — тачпад или мышь), но any-pointer: coarse (сенсор тоже есть). Вот это и есть честный ответ на исходный вопрос. Для iPad есть ещё navigator.maxTouchPoints > 0 — он вернёт число касаний, даже когда user agent притворяется Mac.

Шаг 6. Как именно нажали — смотри в событии

Иногда важно не «что за устройство», а «чем сделали это нажатие». Для этого есть Pointer Events:

button.addEventListener("pointerdown", (e) => {
  console.log(e.pointerType); // "mouse", "touch" или "pen"
});

Одно событие на все три способа ввода. Не нужно вешать отдельно click и touchstart — и ловить двойные срабатывания.

Шаг 7. Проверь на живом устройстве

В Chrome DevTools открой режим устройства (Ctrl+Shift+M) и выбери телефон — он эмулирует касания. Но эмулятор не покажет настоящий размер пальца. Открой сайт с телефона в той же сети Wi-Fi и потыкай в кнопки сам.

Что получится

  • На телефоне нет залипших hover-эффектов, кнопки удобного размера.
  • На ноутбуке с сенсором интерфейс остаётся «мышиным», но не ломается от касаний.
  • iPad получает мобильное поведение, хотя называет себя Mac.

Остальные детали мобильной вёрстки — в статье как сделать сайт удобным на телефоне.

Можно ли просто проверить ширину экрана?

Ширина говорит о размере, а не о способе ввода. Планшет в альбомной ориентации шире многих ноутбуков, а на узком окне десктопа есть мышь. Для раскладки бери ширину, для поведения — hover и pointer.

Работает ли это во всех браузерах?

Да, hover, pointer, any-pointer и Pointer Events поддерживают все современные браузеры, включая Safari на iPhone. Полифилы не нужны.

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

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

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

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

Все статьи →