5 надежных способов определить устройство пользователя на JavaScript
Для кого эта статья:
- Фронтенд-разработчики
- Специалисты по веб-разработке
Студенты и ученики курсов по программированию и веб-разработке
Каждый фронтенд-разработчик рано или поздно сталкивается с необходимостью адаптировать пользовательский опыт под разные устройства. Смартфоны, планшеты, десктопы — все они требуют особого подхода. Однако одних только media queries порой недостаточно. Вам может понадобиться программное определение устройства, чтобы управлять логикой вашего приложения, оптимизировать производительность или предлагать пользователям разный функционал. Я подготовил 5 проверенных методов с готовыми фрагментами кода, которые можно внедрить в проект прямо сейчас. 💡
Хотите углубить свои знания в веб-разработке? На курсе Обучение веб-разработке от Skypro вы освоите не только базовые методы определения устройств пользователя, но и продвинутые техники адаптивной разработки. Наши выпускники создают интерфейсы, которые одинаково хорошо работают на всех устройствах. Курс включает реальные проекты с использованием JavaScript и современных фреймворков!
Зачем и когда нужно определять устройство пользователя
Определение устройства пользователя — это не прихоть, а необходимость в ряде сценариев. Несмотря на популярность подхода "mobile first" и адаптивного дизайна, программное определение устройства остаётся мощным инструментом для оптимизации пользовательского опыта. 📱💻
Михаил, ведущий фронтенд-разработчик
Недавно мы запускали финтех-приложение, где требовалось предлагать разный функционал для пользователей разных устройств. Мобильным пользователям мы давали доступ к упрощённой версии калькулятора кредитов, а десктопным — полную версию с расширенными опциями. Сначала мы пытались определять устройство только по ширине экрана через media queries, но столкнулись с ограничениями: пользователи десктопов с маленьким окном браузера получали мобильную версию.
После внедрения JavaScript-определения устройств на основе комбинации факторов (User-Agent + сенсорные возможности) точность определения выросла до 98%. Это привело к увеличению среднего времени сессии на 27% — пользователи получали именно тот интерфейс, который оптимален для их устройства.
Вот основные случаи, когда программное определение устройства жизненно необходимо:
- Оптимизация производительности — загрузка только тех ресурсов, которые нужны для конкретного устройства
- Разная бизнес-логика — некоторые функции могут быть доступны только на определённых устройствах
- Специфичный UX — создание разных пользовательских сценариев для мобильных и десктопных пользователей
- Аналитика и метрики — сбор данных о том, какими устройствами пользуются ваши клиенты
- Тестирование — запуск определённых тестов только на целевых устройствах
| Задача | Подходящие методы детекции | Приоритет |
|---|---|---|
| Адаптивный дизайн | CSS Media Queries (без JS) | Высокий |
| Разная логика приложения | Feature Detection + User-Agent | Высокий |
| Оптимизация ресурсов | Серверная детекция | Средний |
| Сбор аналитики | User-Agent + библиотеки | Низкий |
Теперь рассмотрим конкретные методы определения устройства пользователя и их практическую реализацию.

Метод №1: Анализ User-Agent строки для определения устройств
Самый базовый и распространённый способ — парсинг строки User-Agent из заголовка HTTP-запроса. В JavaScript это можно сделать через свойство navigator.userAgent. Этот метод имеет давнюю историю и все ещё широко используется, несмотря на определённые недостатки. 🔍
Вот простой пример кода для определения типа устройства:
function detectDevice() {
const userAgent = navigator.userAgent.toLowerCase();
const isMobile = /iphone|ipad|ipod|android|blackberry|windows phone/g.test(userAgent);
const isTablet = /(ipad|tablet|(android(?!.*mobile))|(windows(?!.*phone)(.*touch))|kindle|playbook|silk|(puffin(?!.*(IP|AP|WP))))/g.test(userAgent);
if (isTablet) return 'tablet';
if (isMobile) return 'mobile';
return 'desktop';
}
console.log(`Вы используете: ${detectDevice()}`);
Преимущества этого метода:
- Простота реализации — всего несколько строк кода
- Работает без дополнительных библиотек — нет внешних зависимостей
- Доступен на всех браузерах — высокая совместимость
Однако у этого подхода есть существенные недостатки:
- Ненадёжность — строки User-Agent могут быть подделаны или изменены
- Сложность поддержки — с появлением новых устройств регулярные выражения нужно обновлять
- Проблемы с точностью — некоторые устройства сложно однозначно классифицировать
- Устаревание — браузеры постепенно ограничивают информативность User-Agent
Александр, технический директор
Мы развиваем продукт с аудиторией более 2 миллионов пользователей. Изначально для определения устройств использовали только User-Agent. Это казалось надёжным решением, пока мы не заметили странные аномалии в аналитике — около 15% пользователей определялись некорректно.
После расследования выяснилось, что многие браузеры (особенно мобильные версии Chrome и Safari) стали "замораживать" или обобщать User-Agent строки, чтобы защитить пользователей от фингерпринтинга. Мы перешли на комбинированный подход: User-Agent + определение через функциональные возможности. Это повысило точность определения до 97% и позволило правильно настраивать интерфейс для всех пользователей.
Метод №2: Использование navigator.userAgent с готовыми библиотеками
Ручное создание регулярных выражений для всех возможных устройств — утомительная задача с высокими шансами на ошибку. Гораздо эффективнее использовать проверенные библиотеки, которые постоянно обновляются и учитывают нюансы разных устройств и браузеров. 📚
Наиболее популярные библиотеки для определения устройств:
| Название библиотеки | Размер (min+gzip) | Точность определения | Активная поддержка |
|---|---|---|---|
| device.js | ~1KB | Средняя | Умеренная |
| mobile-detect.js | ~14KB | Высокая | Активная |
| UAParser.js | ~5KB | Высокая | Активная |
| Bowser | ~4KB | Высокая | Умеренная |
Пример использования популярной библиотеки UAParser.js:
// Подключение через CDN
// <script src="https://cdnjs.cloudflare.com/ajax/libs/UAParser.js/0.7.24/ua-parser.min.js"></script>
// Или через npm
// npm install ua-parser-js
const parser = new UAParser();
const result = parser.getResult();
console.log('Устройство:', result.device.type || 'desktop');
console.log('Операционная система:', result.os.name, result.os.version);
console.log('Браузер:', result.browser.name, result.browser.version);
// Более детальное определение
function getDeviceType() {
const device = result.device.type;
if (device === 'mobile') return 'Смартфон';
if (device === 'tablet') return 'Планшет';
if (device === 'smarttv') return 'Smart TV';
if (device === 'console') return 'Игровая консоль';
return 'Компьютер';
}
console.log('Тип устройства:', getDeviceType());
Преимущества использования готовых библиотек:
- Высокая точность — команды разработчиков библиотек следят за обновлениями и новыми устройствами
- Дополнительная информация — помимо типа устройства можно получить данные о браузере, ОС и прочем
- Минимизация ошибок — код проверен тысячами разработчиков
- Экономия времени — не нужно писать и поддерживать собственный парсер
Несмотря на все преимущества, этот метод всё ещё опирается на User-Agent, что означает наследование некоторых его недостатков. Для более надёжных решений стоит комбинировать библиотеки с другими методами определения.
Метод №3: Определение устройства через размер окна и сенсорные возможности
Третий подход базируется на анализе технических возможностей устройства и размеров экрана. Этот метод позволяет определить не только категорию устройства, но и его ориентацию (портретная/альбомная), что часто необходимо для корректной адаптации интерфейса. 📏👆
Пример кода для определения устройства по размеру экрана и сенсорным возможностям:
function detectDeviceByCapabilities() {
// Определяем наличие сенсорного экрана
const hasTouchScreen = (('ontouchstart' in window) ||
(navigator.maxTouchPoints > 0) ||
(navigator.msMaxTouchPoints > 0));
// Получаем размер окна браузера
const width = window.innerWidth;
// Логика определения типа устройства
if (hasTouchScreen) {
if (width < 768) {
return 'mobile';
} else if (width < 1024) {
return 'tablet';
} else {
return 'touch desktop'; // Например, Surface Pro
}
} else {
return 'desktop';
}
}
// Проверка при изменении размера окна
window.addEventListener('resize', function() {
console.log('Текущее устройство:', detectDeviceByCapabilities());
});
console.log('Начальное определение устройства:', detectDeviceByCapabilities());
Этот метод также может отслеживать изменения ориентации экрана, что полезно для мобильных устройств:
// Определение ориентации устройства
function getOrientation() {
return window.innerWidth > window.innerHeight ? 'landscape' : 'portrait';
}
// Прослушивание изменения ориентации
window.addEventListener('resize', function() {
console.log('Текущая ориентация:', getOrientation());
});
// Можно комбинировать с предыдущим методом
window.addEventListener('resize', function() {
console.log(`${detectDeviceByCapabilities()} в ${getOrientation()} режиме`);
});
Основные преимущества этого подхода:
- Реальные характеристики — определение основано на фактических параметрах устройства, а не строках
- Динамическая адаптация — можно реагировать на изменение размера окна или ориентации
- Меньшая зависимость от User-Agent — работает даже в случаях, когда User-Agent не предоставляет достоверной информации
Недостатки метода:
- Сложность точной классификации — планшет с маленьким экраном может быть принят за мобильное устройство
- Пограничные случаи — устройства на границе категорий могут определяться по-разному
- Ресурсоёмкость — постоянное отслеживание изменений размеров может влиять на производительность
Метод №4: Feature detection вместо device detection
Вместо того чтобы сосредоточиться на определении типа устройства, во многих случаях эффективнее определять конкретные возможности браузера или устройства. Этот подход называется "определение функций" (feature detection) и является более гибким и устойчивым к изменениям. 🧩
Feature detection фокусируется на вопросе "что может устройство?", а не "что это за устройство?". Это позволяет создавать более устойчивые и гибкие приложения.
// Проверка наличия сенсорного ввода
function hasTouchCapability() {
return 'ontouchstart' in window ||
navigator.maxTouchPoints > 0 ||
navigator.msMaxTouchPoints > 0;
}
// Проверка поддержки определённых API
function checkDeviceCapabilities() {
const capabilities = {
touch: hasTouchCapability(),
geolocation: 'geolocation' in navigator,
webGL: (function() {
try {
const canvas = document.createElement('canvas');
return !!(window.WebGLRenderingContext &&
(canvas.getContext('webgl') || canvas.getContext('experimental-webgl')));
} catch(e) {
return false;
}
})(),
deviceMotion: 'DeviceMotionEvent' in window,
deviceOrientation: 'DeviceOrientationEvent' in window,
ambientLight: 'AmbientLightSensor' in window,
batteryAPI: 'getBattery' in navigator,
screenOrientation: screen.orientation ? true : false
};
return capabilities;
}
const deviceCaps = checkDeviceCapabilities();
console.log('Возможности устройства:', deviceCaps);
// Использование этой информации для адаптации интерфейса
if (deviceCaps.touch) {
console.log('Включаем интерфейс для сенсорных устройств');
// enableTouchInterface();
}
if (deviceCaps.deviceMotion) {
console.log('Это устройство поддерживает определение движения');
// enableMotionFeatures();
}
На основе определённых функций можно сделать предположение о типе устройства:
function guessDeviceType() {
const caps = checkDeviceCapabilities();
// Мобильные устройства обычно имеют сенсор движения и ориентации
if (caps.touch && (caps.deviceMotion || caps.deviceOrientation)) {
return window.innerWidth < 768 ? 'smartphone' : 'tablet';
}
// Планшеты обычно сенсорные, но не всегда имеют датчики движения
if (caps.touch && !caps.deviceMotion) {
return 'tablet or touch-desktop';
}
// Десктопы редко имеют сенсорный экран
if (!caps.touch) {
return 'desktop';
}
return 'unknown';
}
console.log('Предполагаемый тип устройства:', guessDeviceType());
Основные преимущества feature detection:
- Ориентация на возможности, а не типы — адаптация под реальные характеристики устройства
- Будущая совместимость — код не нужно обновлять при появлении новых устройств
- Прогрессивное улучшение — можно плавно деградировать функционал при отсутствии возможностей
- Более надёжные решения — нет ложных предположений на основе типа устройства
Этот подход становится особенно актуальным с появлением гибридных устройств (ноутбуки с сенсорными экранами, планшеты с клавиатурами), которые сложно однозначно отнести к определённой категории.
Метод №5: Серверная и клиентская детекция: комбинированный подход
Наиболее комплексное и надёжное решение — комбинирование серверной и клиентской детекции устройств. Этот подход устраняет недостатки отдельных методов и повышает точность определения, обеспечивая оптимальную производительность. 🔄
Схема работы комбинированного подхода:
- Первичное определение на сервере — анализ User-Agent при первом запросе
- Отправка адаптированных ресурсов — сервер отправляет только те ресурсы, которые необходимы для предполагаемого устройства
- Уточнение на стороне клиента — JavaScript проверяет реальные характеристики устройства
- Корректировка интерфейса — при необходимости происходит динамическая корректировка
- Сохранение данных — информация о правильном определении сохраняется для будущих запросов
Пример серверной части (Node.js с Express):
// Серверная детекция с использованием express и mobile-detect
const express = require('express');
const MobileDetect = require('mobile-detect');
const app = express();
app.use((req, res, next) => {
const userAgent = req.headers['user-agent'];
const md = new MobileDetect(userAgent);
// Определяем тип устройства
if (md.mobile() && !md.tablet()) {
req.deviceType = 'mobile';
} else if (md.tablet()) {
req.deviceType = 'tablet';
} else {
req.deviceType = 'desktop';
}
// Добавляем информацию в локальные переменные для шаблонов
res.locals.deviceType = req.deviceType;
next();
});
app.get('/', (req, res) => {
// Используем информацию о устройстве для отправки разного контента
switch(req.deviceType) {
case 'mobile':
res.render('mobile-index', { title: 'Мобильная версия' });
break;
case 'tablet':
res.render('tablet-index', { title: 'Версия для планшета' });
break;
default:
res.render('desktop-index', { title: 'Полная версия' });
}
});
app.listen(3000, () => {
console.log('Сервер запущен на порту 3000');
});
Клиентская часть для уточнения и корректировки:
// Получаем первичное определение от сервера
const serverDetectedDevice = document.documentElement.getAttribute('data-device-type');
// Проверяем корректность определения
function verifyDeviceType() {
const isTouchDevice = 'ontouchstart' in window || navigator.maxTouchPoints > 0;
const screenWidth = window.innerWidth;
let actualDeviceType;
if (isTouchDevice) {
if (screenWidth < 768) {
actualDeviceType = 'mobile';
} else if (screenWidth < 1024) {
actualDeviceType = 'tablet';
} else {
actualDeviceType = 'touch-desktop';
}
} else {
actualDeviceType = 'desktop';
}
// Если серверное определение неверно
if (serverDetectedDevice !== actualDeviceType) {
console.log(`Корректировка: сервер определил ${serverDetectedDevice}, фактически ${actualDeviceType}`);
// Отправляем правильные данные на сервер для будущих запросов
fetch('/api/update-device-type', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
detectedType: actualDeviceType,
userAgent: navigator.userAgent
})
});
// Корректируем UI если нужно
adjustInterface(actualDeviceType);
}
return actualDeviceType;
}
function adjustInterface(deviceType) {
// Корректируем интерфейс на основе реального типа устройства
if (deviceType === 'mobile') {
// Загружаем дополнительные мобильные компоненты если нужно
loadMobileSpecificResources();
} else if (deviceType === 'tablet') {
// Адаптируем для планшета
adjustTabletLayout();
}
}
// Запускаем проверку после загрузки страницы
document.addEventListener('DOMContentLoaded', verifyDeviceType);
Преимущества комбинированного подхода:
- Максимальная точность — ошибки одного метода компенсируются другим
- Оптимизация ресурсов — сервер изначально отправляет только необходимые файлы
- Самообучение — система может накапливать данные для улучшения первичного определения
- Гибридные устройства — эффективное определение даже для устройств, которые сложно классифицировать
Этот метод требует больше усилий для реализации, но обеспечивает наилучший баланс между производительностью и точностью определения устройств пользователей.
Выбор метода определения устройства зависит от конкретных потребностей вашего проекта. Для большинства современных веб-приложений оптимальным решением будет комбинация feature detection с элементами серверной предварительной оптимизации. Вместо жёсткой классификации устройств сосредоточьтесь на их возможностях — создавайте интерфейсы, которые адаптируются к любым условиям использования. Такой подход обеспечит долговечность вашего кода и наилучший опыт для пользователей независимо от того, какие устройства появятся в будущем.