ショートカットの案内を表示するのに Mac, iPhone, iPad なら ⌘
それ以外は Ctrl
を表示したい。という要望でクラアンと側で OS の判定をしたメモ
navigator.userAgent / navigator.platform を使う
MDN のドキュメントには navigator.userAgent
, navigator.platform
共に信頼性が低いと書かれてるけど、クライアント側で判定しようとしたら現実的にこれらで判別するしかなさそう。
NavigatorID.userAgent
ユーザーエージェント文字列の検出に基づくブラウザーの識別は信頼性が低く、ユーザーエージェント文字列はユーザーが設定可能なので推奨されません。
cf. NavigatorID.userAgent - Web API | MDN
Mac OS 10.15.7 googleChrome での場合はこんな感じ
const getUserAgent = () => { return (navigator && navigator.userAgent) || false; }; console.log(getUserAgent()); // Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) // AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36
NavigatorID.platform
ブラウザーのプラットフォームを表す文字列を返します。仕様書ではブラウザーが常に空文字列を返すことを許可していますので、信頼できる答えを得るためにこのプロパティを頼らないようにしてください。
cf. NavigatorID.platform - Web API | MDN
navigator.platform
は OS の情報だけ
const getPlatform = () => { return (navigator && navigator.platform) || false; }; console.log(getPlatform()); // MacIntel
OS を判定する
navigator.userAgent
も navigator.platform
も文字列なので、そこに特定の文字が含まれるかで判定すればいいので、indexOf
か String.includes
を使えばOK
String.includes
は IE が未対応で polyfill が必要になりそうなので対応ブラウザに IE が含まれるなら indexOf を使うのが良いかも)
navigator.userAgent
と navigator.platform
とで微妙に含まれる文字が異なるっぽいのでどちらを使うかで別々の判定リストを作成するのが良さそう
navigator.userAgent を使って判定
const OS_LIST = { 'Windows': 'windows nt', 'MacOS': 'mac os', 'iPhone': 'iphone', 'ipad': 'iPad', 'Android': 'android', 'Linux': 'linux', }; const getUserAgent = () => { return (navigator && navigator.userAgent) || false; };
indexOf を使って判定
const checkIncludeText = (target) => (obj) => { let result = false; Object.entries(obj).some(([key, value]) => { if ( target.indexOf(value) !== -1 ) { result = key; return true; } return false; }); return result; }; const checkOS = () => { const ua = getUserAgent(); let os = 'unknown'; if (!ua) return os; return checkIncludeText(OS_LIST)(ua.toLowerCase()); }; checkOS(); // => MacOS
includes を使って判定
オブジェクトを回して判定するメソッドの中身を変えればOK
const checkIncludeText = (target) => (obj) => { let result = false; Object.entries(obj).some(([key, value]) => { if ( target.includes(value) ) { result = key; return true; } return false; }); return result; }; const checkOS = () => { const ua = getUserAgent(); let os = 'unknown'; if (!ua) return os; return checkIncludeText(OS_LIST)(ua.toLowerCase()); }; checkOS(); // => MacOS
navigator.platform を使って判定
navigator.platform
は userAgent
に含まれる文字と微妙に異なるっぽいので、こちらを使って判定する場合は別のリストを作成しておけばOK
const OS_LIST = { 'MacOS': 'mac', 'iPhone': 'iphone', 'ipad': 'iPad', 'Windows': 'windows', 'Android': 'android', 'Linux': 'linux', }; const getPlatform = () => { return (navigator && navigator.platform) || false; };
indexOf を使って判定
const checkIncludeText = (target) => (obj) => { let result = false; Object.entries(obj).some(([key, value]) => { if ( target.indexOf(value) !== -1 ) { result = key; return true; } return false; }); return result; }; const checkOS = () => { const platform = getPlatform(); let os = 'unknown'; if (!platform) return os; return checkIncludeText(OS_LIST)(platform.toLowerCase()); }; checkOS(); // => MacOS
includes を使って判定
const checkIncludeText = (target) => (obj) => { let result = false; Object.entries(obj).some(([key, value]) => { if ( target.includes(value) ) { result = key; return true; } return false; }); return result; }; const checkOS = () => { const platform = getPlatform(); let os = 'unknown'; if (!platform) return os; return checkIncludeText(OS_LIST)(platform.toLowerCase()); }; checkOS(); // => MacOS
複数での判定は test を使うのが良さそう
indexOf
, includes
は単一のテキストが含まれているかでしか判定できないので、Mac || iPhone || iPad
のような複数にマッチさせたい場合は正規表現を使える test()
を使うのが良さそうです。
e.g. Mac, iPhone, iPad かどうか判定したい
const IS_MAC_OR_IOS_REGEXP = /mac|iphone|ipad/; const getUserAgent = () => { return (navigator && navigator.userAgent) || false; }; const getPlatform = () => { return (navigator && navigator.platform) || false; }; // userAgent で判定 IS_MAC_OR_IOS_REGEXP.test(getUserAgent()); // => true or false // platform で判定 IS_MAC_OR_IOS_REGEXP.test(getPlatform()); // => true or false const isMac = () => { return IS_MAC_OR_IOS_REGEXP.test(getPlatform()); } const save = `${isMac() ? '⌘' : 'Ctrl'} + s`;
example
See the Pen Check OS by userAgent & platform by KIKIKI (@kikiki_kiki) on CodePen.
感想
navigator.userAgent
も navigator.platform
も変更が可能なので完璧な判定ができるわけではないですが、変更してる人は自分の意志なことが多いだろうしフロントで判別するならこんな感じでいいんじゃないかな〜ってイメージです。ブラウザは無視して OS だけ判定するなら navigator.platform
の方がシンプルな文字列が返ってくるので扱いやすそうな印象を持ちました。
単一の判定なら indexOf()
か includes()
を使って複数での判定なら test()
を使うのが良さそうです。
まぁ自前で実装せずに判定できる信頼性のあるライブラリ入れちゃうのが簡単で良いと思いますが。(なんでこの記事書いたんでしょうねw)
おわり。
[参考]
- NavigatorID.userAgent - Web API | MDN
- NavigatorID.platform - Web API | MDN
- String.prototype.includes() - JavaScript | MDN
- RegExp.prototype.test() - JavaScript | MDN
- Object.entries() - JavaScript | MDN
- GitHub - bestiejs/platform.js: A platform detection library.

上伊那ぼたん、酔へる姿は百合の花 2 (2) (ヤングチャンピオン・コミックス)
- 作者:塀
- 発売日: 2020/12/18
- メディア: コミック