인셔셔RSS 관심 있는 블로그, 뉴스, 기술 정보를 효율적으로 추적하고 읽으세요
원문 읽기 InertiaRSS에서 열기

추천 피드

博客园 - 司徒正美
V
V2EX
T
Tailwind CSS Blog
有赞技术团队
有赞技术团队
aimingoo的专栏
aimingoo的专栏
Apple Machine Learning Research
Apple Machine Learning Research
IT之家
IT之家
Blog — PlanetScale
Blog — PlanetScale
A
About on SuperTechFans
月光博客
月光博客
T
The Blog of Author Tim Ferriss
宝玉的分享
宝玉的分享
Martin Fowler
Martin Fowler
博客园 - 聂微东
The GitHub Blog
The GitHub Blog
V
Visual Studio Blog
WordPress大学
WordPress大学
酷 壳 – CoolShell
酷 壳 – CoolShell
Engineering at Meta
Engineering at Meta
GbyAI
GbyAI

阮一峰的网络日志

科技爱好者周刊(第 396 期):互联网通信的替代方案 科技爱好者周刊(第 396 期):互联网通信的替代方案 - 阮一峰的网络日志 科技爱好者周刊(第 395 期):软件开发的第三种方式 科技爱好者周刊(第 395 期):软件开发的第三种方式 - 阮一峰的网络日志 科技爱好者周刊(第 393 期):脑腐状态 科技爱好者周刊(第 392 期):axios 投毒与好莱坞式骗术 科技爱好者周刊(第 391 期):AI 的贫富分化 科技爱好者周刊(第 390 期):没有语料,大模型就是智障 套壳中国大模型撑起500亿美元估值?扒一扒 Cursor 的"套壳"疑云 科技爱好者周刊(第 389 期):未来如何招聘程序员 科技爱好者周刊(第 388 期):测试是新的护城河 零安装的"云养虾":ArkClaw 使用指南 科技爱好者周刊(第 387 期):你是领先的 科技爱好者周刊(第 386 期):当外卖员接入 AI 字节全家桶 Seed 2.0 + TRAE 玩转 Skill 科技爱好者周刊(第 385 期):马斯克害怕中国车企吗? 智谱旗舰 GLM-5 实测:对比 Opus 4.6 和 GPT-5.3-Codex 科技爱好者周刊(第 384 期):为什么软件股下跌 科技爱好者周刊(第 383 期):你是第几级 AI 编程 Kimi 的一体化,Manus 的分层 科技爱好者周刊(第 382 期):独立软件的黄昏 AI native Workspace 也许是智能体的下一阶段 科技爱好者周刊(第 381 期):中国 AI 大模型领导者在想什么 科技爱好者周刊(第 380 期):为什么人们拥抱"不对称收益" 科技爱好者周刊(第 379 期):《硅谷钢铁侠》摘录 我如何用 AI 处理历史遗留代码:MiniMax M2.1 升级体验 科技爱好者周刊(第 378 期):预测是新的互联网热点 科技爱好者周刊(第 377 期):14万美元的贫困线 科技爱好者周刊(第 376 期):太空数据中心的争议 科技爱好者周刊(第 375 期):一扇门的 Bug 终于有人做了 Subagent,TRAE 国内版 SOLO 模式来了 科技爱好者周刊(第 374 期):6GHz 的问题 VS Code 使用国产大模型 MiniMax M2 教程 科技爱好者周刊(第 373 期):数据模型是新产品的核心 国产大模型接入 Claude Code 教程:以 Doubao-Seed-Code 为例 科技爱好者周刊(第 372 期):软件界面如何设计 大模型比拼:MiniMax M2 vs GLM 4.6 vs Claude Sonnet 4.5 科技爱好者周刊(第 371 期):一个乐观主义者的专访 科技爱好者周刊(第 370 期):正确的代码高亮 错误处理:异常好于状态码 科技爱好者周刊(第 369 期):Tim 与罗永浩的对谈 科技爱好者周刊(第 368 期):不要这样管理软件团队 一天之内,智谱和 Anthropic 都发了最强编程模型 科技爱好者周刊(第 367 期):Nano Banana 的几个妙用 科技爱好者周刊(第 366 期):旧金山疯狂的 AI 广告 科技爱好者周刊(第 365 期):流量变现正在崩塌 科技爱好者周刊(第 364 期):最难还原的魔方 科技爱好者周刊(第 363 期):最好懂的神经网络解释 科技爱好者周刊(第 362 期):GitHub 工程师谈系统设计 科技爱好者周刊(第 361 期):暗网 Tor 安全吗?
JavaScript에서 모바일 브라우저를 감지하는 다섯 가지 방법
阮一峰 · 2021-09-29 · via 阮一峰的网络日志

때때로, 프론트엔드 웹페이지는 사용자가 모바일 브라우저를 사용하는지 데스크톱 브라우저를 사용하는지 알아야 합니다.

이 글은 StackOverflow을 기반으로 JavaScript로 모바일 브라우저를 감지하는 다섯 가지 방법을 정리했습니다.

1. navigator.userAgent

가장 간단한 방법은 브라우저의 user agent 문자열을 분석하는 것입니다. 이 문자열에는 장치 정보가 포함되어 있습니다.

JS는 navigator.userAgent 속성을 통해 이 문자열을 가져오며, 그 안에 mobiandroidiphone과 같은 키워드가 포함되어 있으면 모바일 장치로 인식할 수 있습니다.


if (/Mobi|Android|iPhone/i.test(navigator.userAgent)) {
  // 当前设备是移动设备
}

// 另一种写法
if (
  navigator.userAgent.match(/Mobi/i) ||
  navigator.userAgent.match(/Android/i) ||
  navigator.userAgent.match(/iPhone/i)
) {
  // 当前设备是移动设备
}

이 방법의 장점은 간단하고 편리하지만, 단점은 신뢰할 수 없다. 사용자가 이 문자열을 변경하여 스마트폰 브라우저를 데스크톱 브라우저처럼伪装할 수 있기 때문이다.

Chromium 계열 브라우저에는 navigator.userAgentData 속성도 있는데, 이 역시 유사한 기능을 가진다. 차이점은 user agent 문자열을 객체로 파싱하여, 그 객체의 mobile 속성이 사용자가 모바일 기기를 사용하는지 여부를 나타내는 불리언 값을 반환한다는 점이다.


const isMobile = navigator.userAgentData.mobile; 

주의해야 할 점은, 애플의 Safari 브라우저와 Firefox 브라우저는 이 속성을 지원하지 않는다. 구체적인 상황은 Caniuse 웹사이트 에서 확인할 수 있다.

또한, 이미 폐지된 navigator.platform 속성 도 있는데, 모든 브라우저가 이를 지원하므로 사용할 수도 있다. 이는 사용자의 운영체제를 나타내는 문자열을 반환한다.


if (/Android|iPhone|iPad|iPod/i.test(navigator.platform)) {
  // 当前设备是移动设备
}

이, window.screen, window.innerWidth

다른 방법은 화면 너비를 통해 모바일인지 확인하는 것입니다.

window.screen 객체는 사용자 기기의 화면 정보를 반환하며, 이 객체의 width 속성은 화면 너비(픽셀 단위)입니다.


if (window.screen.width < 500) {
  // 当前设备是移动设备 
}

위 예제에서 화면 너비가 window.screen.width 500 픽셀보다 작으면 모바일로 인식합니다.

이 방법의 단점은 모바일이 가로 모드로 사용될 경우 인식하지 못한다는 점입니다.

다른 속성인 window.innerWidth는 브라우저 창 안의 웹페이지가 보이는 부분의 너비를 반환하며, 다양한 너비에서 웹페이지의 스타일을 지정하는 데 적합합니다.


const getBrowserWidth = function() {
  if (window.innerWidth < 768) {
    return "xs";
  } else if (window.innerWidth < 991) {
    return "sm";
  } else if (window.innerWidth < 1199) {
    return "md";
  } else {
    return "lg";
  }
};

삼, window.orientation

세 번째 방법은 화면 방향 감지입니다. 스마트폰 화면은 언제든 방향을 변경할 수 있지만(가로 또는 세로), 데스크톱 기기는 그럴 수 없습니다.

window.orientation 속성은 현재 화면 방향을 얻기 위해 사용되며, 이 속성은 모바일 기기에만 있습니다. 데스크톱 기기는 undefined 값을 반환합니다.


if (typeof window.orientation !== 'undefined') {
  // 当前设备是移动设备 
}

주의해야 할 점은 iPhone의 Safari 브라우저가 이 속성을 지원하지 않는다는 것입니다.

4. touch 이벤트

네 번째 방법은, 스마트폰 브라우저의 DOM 요소가 ontouchstart 속성을 통해 touch 이벤트에 리스너 함수를 지정할 수 있다는 것입니다. 데스크톱 기기에는 이 속성이 없습니다.


function isMobile() { 
  return ('ontouchstart' in document.documentElement); 
}

// 另一种写法
function isMobile() {
  try {
    document.createEvent("TouchEvent"); return true;
  } catch(e) {
    return false; 
  }
}

5. window.matchMedia()

마지막 방법은 CSS를 결합하여 판단하는 것입니다.

CSS는 미디어 쿼리를 통해 웹페이지에 반응형 스타일을 지정합니다. 만약 스마트폰을 대상으로 한 미디어 쿼리 문장이 적용되었다면, 현재 기기가 모바일 기기라고 할 수 있습니다.

window.matchMedia()메서드는 CSS의 미디어 쿼리 문장을 인자로 받아서 이 문장이 적용되었는지 여부를 판단합니다.


let isMobile = window.matchMedia("only screen and (max-width: 760px)").matches;

위 예제에서, window.matchMedia()의 인자는 CSS 쿼리 문장으로, 화면 너비가 700픽셀 이하인 기기에만 적용됨을 의미합니다. 이는 객체를 반환하며, 해당 객체의 matches 속성이 불리언 값입니다. true가 __JHSNS_SEG_fe5633f9_46__이면, 쿼리가 적용되었으며 현재 기기가 스마트폰임을 의미합니다.

스크린 너비를 통해 판단하는 것 외에도, 포인터의 정밀도를 통해 판단할 수 있습니다.


let isMobile = window.matchMedia("(pointer:coarse)").matches;

위 예제에서, CSS 문장pointer:coarse는 현재 장치의 포인터가 정확하지 않음을 나타냅니다. 스마트폰은 마우스를 지원하지 않고 탭을 지원만 하므로 이 조건에 맞습니다.

는 일부 장치는 여러 가지 포인터를 지원합니다. 예를 들어 마우스와 탭을 동시에 지원합니다. pointer:coarse는 주 포인터를 판단하는 데만 사용되며, 또한 any-pointer 명령어는 모든 포인터를 판단합니다.


let isMobile = window.matchMedia("(any-pointer:coarse)").matches;

예제에서, any-pointer:coarse는 모든 포인터 중 하나라도 정확하지 않으면 조건에 맞음을 의미합니다.

6. 도구 패키지

위의 방법 외에도 다른 사람이 작성한 도구 패키지를 사용할 수 있습니다. 여기서는 react-device-detect를 추천합니다. 이는 다양한 수준의 장치 감지를 지원합니다.


import {isMobile} from 'react-device-detect';

if (isMobile) {
  // 当前设备是移动设备
}

(끝)