os-detect — определяем операционную систему в браузере, Node.js и SSR

29.03.2026
os-detect — определяем операционную систему в браузере, Node.js и SSR

os-detect — определяем операционную систему в браузере, Node.js и SSR

В проектах периодически встречаются задачи, которые требуют специфичного поведения под конкретную платформу: другой UI для мобильных, отдельные инструкции для macOS и Windows, баннеры только для iOS. Чтобы не решать это каждый раз заново, я собрал единую библиотеку.

os-detect — пакет для определения операционной системы и типа устройства. Работает в браузере, в Node.js, в SSR. Есть хуки для React и composables для Vue. Зависимостей — ноль.

Установка

bash Copy
npm install os-detect

Зачем вообще это нужно

Ситуации, когда нужно знать ОС, встречаются чаще, чем кажется:

  • Показать инструкцию по установке под нужную платформу
  • Скрыть кнопку «Скачать для iOS» на Android
  • Вывести разные горячие клавиши для Mac и Windows
  • Показать баннер «Доступно в App Store» только на iPhone и iPad
  • Отключить какую-то анимацию на мобильных устройствах

Можно каждый раз парсить navigator.userAgent вручную. Или поставить пакет и не думать об этом.

Пример на чистом JS — страница загрузки с разными ссылками под каждую платформу:

js Copy
import { getOS, isMobileDevice } from 'os-detect';

const os = getOS();

const downloadLinks = {
  windows: { label: 'Скачать для Windows', url: '/download/app.exe' },
  macos:   { label: 'Скачать для macOS',   url: '/download/app.dmg' },
  linux:   { label: 'Скачать для Linux',   url: '/download/app.AppImage' },
  ios:     { label: 'App Store',            url: 'https://apps.apple.com/...' },
  android: { label: 'Google Play',          url: 'https://play.google.com/...' },
};

const btn = document.getElementById('download-btn');

if (downloadLinks[os]) {
  btn.textContent = downloadLinks[os].label;
  btn.href = downloadLinks[os].url;
} else {
  // Неизвестная платформа — показываем все варианты
  btn.textContent = 'Выбрать версию';
  btn.href = '/download';
}

// Скрыть десктопный хедер на мобильных
if (isMobileDevice()) {
  document.getElementById('desktop-nav').style.display = 'none';
}

Пример на Vue — блок с горячими клавишами, зависящими от ОС:

vue Copy
<script setup lang="ts">
import { computed } from 'vue';
import { getOS } from 'os-detect';

const os = getOS();

const shortcuts = computed(() => {
  const isMac = os === 'macos';
  return {
    save:   isMac ? '⌘ S'      : 'Ctrl + S',
    undo:   isMac ? '⌘ Z'      : 'Ctrl + Z',
    find:   isMac ? '⌘ F'      : 'Ctrl + F',
    newTab: isMac ? '⌘ T'      : 'Ctrl + T',
  };
});
</script>

<template>
  <div class="shortcuts">
    <h3>Горячие клавиши</h3>
    <ul>
      <li>Сохранить — <kbd>{{ shortcuts.save }}</kbd></li>
      <li>Отменить — <kbd>{{ shortcuts.undo }}</kbd></li>
      <li>Поиск — <kbd>{{ shortcuts.find }}</kbd></li>
      <li>Новая вкладка — <kbd>{{ shortcuts.newTab }}</kbd></li>
    </ul>
  </div>
</template>

Базовое использование

Самая простая точка входа — функция getOS(). Возвращает строку с названием ОС:

ts Copy
import { getOS } from 'os-detect';

getOS(); // 'ios' | 'macos' | 'android' | 'windows' | 'linux' | 'chromeos' | 'unknown'

Если нужен конкретный boolean — есть отдельная функция для каждой ОС:

ts Copy
import {
  detectIsIOS,
  detectIsMacOS,
  detectIsAndroid,
  detectIsWindows,
  detectIsLinux,
  detectIsChromeOS,
} from 'os-detect';

detectIsIOS();       // true на iPhone, iPod и iPad (включая iPadOS 13+)
detectIsMacOS();     // true на macOS-десктопе
detectIsAndroid();   // true на Android-телефонах и планшетах
detectIsWindows();   // true на Windows
detectIsLinux();     // true на Linux (Android и ChromeOS исключены)
detectIsChromeOS();  // true на ChromeOS

И две вспомогательные функции для тех, кому не важна конкретная ОС:

ts Copy
import { isMobileDevice, isDesktopDevice } from 'os-detect';

isMobileDevice();   // true если iOS или Android
isDesktopDevice();  // true если macOS, Windows, Linux или ChromeOS

Результат каждого вызова кэшируется — повторные обращения бесплатны.

Тонкость с iPadOS 13+

С выходом iPadOS 13 Apple решила, что iPad должен представляться как Mac. Safari на iPad стал отправлять Macintosh в строке User-Agent — такой же, как у настоящего Mac.

Если определять ОС только по UA, detectIsMacOS() вернёт true на iPadе. Это неверно.

В os-detect эта ситуация обрабатывается через navigator.maxTouchPoints:

ts Copy
// iPad с iPadOS 13+ отправляет:
// UA: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15) ..."
// maxTouchPoints: 5

detectIsIOS();    // true  — правильно
detectIsMacOS();  // false — правильно

Проверка maxTouchPoints > 1 надёжно отличает iPadOS от настоящего Mac.

Последние версии Chrome и Edge поддерживают navigator.userAgentData — стандартный браузерный API, который возвращает платформу напрямую, без парсинга строки UA.

os-detect использует его в первую очередь и падает обратно на userAgent для Safari, Firefox и других браузеров:

Copy
navigator.userAgentData.platform  →  'Windows' | 'macOS' | 'Android' | 'Linux' | 'iOS'

Это делает определение более точным там, где API доступен.

Windows 11

Отличить Windows 11 от Windows 10 нельзя через обычный userAgent — там всё равно написано Windows NT 10.0. Для этого нужен асинхронный вызов getHighEntropyValues():

ts Copy
import { detectIsWindows11 } from 'os-detect';

const isWin11 = await detectIsWindows11(); // true | false

Windows 11 сообщает platformVersion >= 13.0.0. Если API недоступен или вызов упал — функция тихо возвращает false.

CommonJS и UMD

Для тех, кто не использует бандлер — пакет доступен через CDN:

html Copy
<script src="https://unpkg.com/os-detect/dist/index.umd.js"></script>
<script>
  if (OsDetect.detectIsIOS()) {
    document.querySelector('.app-store-btn').style.display = 'block';
  }
</script>

CommonJS:

js Copy
const { getOS, isMobileDevice } = require('os-detect');

Vue

Для Vue есть готовые composables — импортируются из os-detect/vue:

vue Copy
<script setup lang="ts">
import { useOS, useIsWindows11 } from 'os-detect/vue';

const os = useOS();               // Readonly<Ref<OS>>
const isWin11 = useIsWindows11(); // Readonly<Ref<boolean | null>>
</script>

<template>
  <div>
    <p>Ваша система: {{ os }}</p>

    <div v-if="os === 'ios'">
      <a href="https://apps.apple.com/...">Скачать в App Store</a>
    </div>

    <div v-else-if="os === 'android'">
      <a href="https://play.google.com/...">Скачать в Google Play</a>
    </div>

    <div v-if="os === 'windows'">
      <p v-if="isWin11 === null">Определяем версию Windows...</p>
      <p v-else-if="isWin11">Вы на Windows 11</p>
      <p v-else>Вы на Windows 10 или старше</p>
    </div>
  </div>
</template>

useOS() — синхронный, результат закэширован. useIsWindows11() возвращает null пока идёт асинхронная проверка, затем true или false.

React

Для React — хуки из os-detect/react:

tsx Copy
import { useOS, useIsWindows11 } from 'os-detect/react';

function DownloadButton() {
  const os = useOS();
  const isWin11 = useIsWindows11();

  if (os === 'ios') {
    return <a href="https://apps.apple.com/...">App Store</a>;
  }

  if (os === 'android') {
    return <a href="https://play.google.com/...">Google Play</a>;
  }

  if (os === 'windows') {
    return (
      <div>
        <a href="/download/windows">Скачать для Windows</a>
        {isWin11 === true && <span> (оптимизировано для Windows 11)</span>}
      </div>
    );
  }

  return <a href="/download">Скачать</a>;
}

Node.js и SSR

Пакет работает и вне браузера. В Node.js функции читают process.platform вместо navigator:

ts Copy
import { getOS, detectIsWindows, detectIsWindows11 } from 'os-detect';

// Запущено на macOS-сервере
getOS();            // 'macos'
detectIsWindows();  // false

// Запущено на Windows-машине
getOS();            // 'windows'
detectIsWindows();  // true

// Windows 11 через os.release() (build >= 22000)
const isWin11 = await detectIsWindows11();
process.platform Определяется как
darwin macOS
win32 Windows
linux Linux
android Android

Это удобно для CLI-утилит и скриптов, которые меняют поведение в зависимости от платформы разработчика.

Важно для SSR: в Next.js или Nuxt getOS() на сервере вернёт ОС сервера, а не клиента. Если нужно определить ОС пользователя — оберните вызов в useEffect (React) или onMounted (Vue), чтобы код выполнился уже в браузере.

TypeScript

Пакет написан на TypeScript, типы включены в поставку. Тип OS доступен для импорта:

ts Copy
import type { OS } from 'os-detect';

function getDownloadUrl(os: OS): string {
  switch (os) {
    case 'windows': return '/download/windows.exe';
    case 'macos':   return '/download/macos.dmg';
    case 'linux':   return '/download/linux.AppImage';
    default:        return '/download';
  }
}

Итог

os-detect решает одну задачу и решает её хорошо: определяет операционную систему там, где вы работаете — в браузере через userAgentData и userAgent, в Node.js через process.platform.

Читать далее

30.03.2026

color-value-tools 1.1.1: от конвертера форматов до полноценного инструментария для работы с цветом

color-value-tools вырос из простого конвертера цветовых форматов в полноценный инструментарий: CSS Color Level 4, перцептивная интерполяция, цветовые гармонии, симуляция дальтонизма, WCAG-доступность, генераторы и CLI — всё в одном пакете без зависимостей.

Метки
colortypescriptnpmwcagcss
31.03.2026

css-magic-gradient 1.2.0 — гармонии, палитры, WCAG по всей длине и canvas-экспорт

Версия 1.2.0 библиотеки css-magic-gradient: расширенные цветовые гармонии, генераторы тинтов и шейдов, переработанная доступность с проверкой по всем точкам градиента, CSS-переменные, экспорт в canvas и 9 новых хуков для Vue и React.

Метки
css-градиентыtypescriptreactvuewcagcolor-harmony
28.03.2026

vue-i18n-kit — локализация для Vue 3 с ICU-плюрализацией, lazy loading и CLI

Написал собственный npm-пакет для локализации Vue 3, потому что устал каждый раз копировать один и тот же бойлерплейт из проекта в проект. ICU-плюрализация, lazy loading, метаданные локалей, форматирование дат и валют, Vite-плагин и CLI — всё из коробки.

Метки
vue3i18nlocalizationnpmopen-source