JavaScriptでブラウザとOSを判定する2つの方法

# はじめに
JavaScriptでのブラウザやOS判定系の記事は結構あるが、古い方法で現在は通用しなかったりモバイルには対応していなかったりする。
なので本記事では2019年8月の時点で主要なブラウザとOSを判定する2つの方法を紹介する。

## ブラウザ、OSを判定する2つの方法
JavaScriptでブラウザ、OSを判定する方法は主に2つある。

1. [window.navigator.userAgent](https://developer.mozilla.org/ja/docs/Web/API/NavigatorID/userAgent)を使ったブラウザとOSの判定JavaScriptを自分で書く。
2. オープンソースライブラリの[platform.js](https://github.com/bestiejs/platform.js)を使用する。

# 判定JavaScriptの自作
[window.navigator.userAgent](https://developer.mozilla.org/ja/docs/Web/API/NavigatorID/userAgent)(UA)の文字列からブラウザ、OSを判定するJavaScriptを自作する。

<details><summary>参考：なぜuserAgentで判定するのか?</summary><div>
ブラウザ、OS毎に文字列が異なるからである。
例えばブラウザがFirefoxなら`Firefox`、OSがOS Xなら`Mac OS X`のように、ブラウザやOSを示す文字列が入っている。
なので、これらの文字列が含まれているか否かでブラウザ、OS判定するのが楽である。

そうは言ったが実はuserAgentでのブラウザ、OSの判定は[MDN](https://developer.mozilla.org/ja/docs/Web/API/NavigatorID/userAgent)では推奨されていない。

>ユーザエージェントを表す文字列を検出することに基づいたブラウザ識別は、**信頼できないものであり**、また、**推奨されません**。なぜなら、ユーザエージェントを表す文字列は、ユーザによって変更することができるからです。

しかし、大多数のユーザーはuserAgentの変更なんてしないので本記事に限らずブラウザ、OSの判定では原則userAgentを用いる。

ただしChromeのUAに`Safari`の文字列が入っているように、**特定のブラウザのUAに別のブラウザの文字列が入っていることが多々あるので注意する事。**(~~大体IEが悪い~~)
また、特定のOSやブラウザのアップデートで**ブラウザの文字列が変化することもあるので注意する事。**(~~IEが最初にやらかした~~)

<details><summary>備考：UA内でブラウザを示す文字列の変遷</summary><div>

- Chrome
 - iOSでは`Chrome`の代わりに`CriOS`の文字列が含まれる
- Mozilla Firefox
 - iOSでは`Firefox`の代わりに`FxiOS`の文字列が含まれる
- Opera
 - バージョン12までは`Opera`、バージョン15以降は`OPR`の文字列が含まれる
- Internet Explorer
 - バージョン11以降は`MSIE`の文字列が無い
- Microsoft Edge
 - Androidでは`EdgA`、iOSでは`EdgiOS`、その他OSでは`Edge`の文字列が含まれる
 - 将来リリースされるChromiumベースの再構築版では、OSに関わらず`Edg`の文字列が含まれるようになるらしい

</div></details>
</div></details>

## ブラウザ判定のJavaScript
JS中の`console.log`は適宜別の処理に置き換えること。

```js
var ua = window.navigator.userAgent.toLowerCase();

if(ua.indexOf("edge") !== -1 || ua.indexOf("edga") !== -1 || ua.indexOf("edgios") !== -1) {
  console.log("「Microsoft Edge」をお使いですね!");
} else if (ua.indexOf("opera") !== -1 || ua.indexOf("opr") !== -1) {
  console.log("「Opera」をお使いですね!");
} else if (ua.indexOf("samsungbrowser") !== -1) {
  console.log("「Samsung Internet Browser」をお使いですね!");
} else if (ua.indexOf("ucbrowser") !== -1) {
  console.log("「UC Browser」をお使いですね!");
} else if(ua.indexOf("chrome") !== -1 || ua.indexOf("crios") !== -1) {
  console.log("「Google Chrome」をお使いですね!");
} else if(ua.indexOf("firefox") !== -1 || ua.indexOf("fxios") !== -1) {
  console.log("「Mozilla Firefox」をお使いですね!");
} else if(ua.indexOf("safari") !== -1) {
  console.log("「Safari」をお使いですね!");
} else if (ua.indexOf("msie") !== -1 || ua.indexOf("trident") !== -1) {
  console.log("「Internet Explorer」をお使いですね!");
} else {
  console.log("何をお使いなのですか?");
}

```

## OS判定のJavaScript
JS中の`console.log`は適宜別の処理に置き換えること。

```js
var ua = window.navigator.userAgent.toLowerCase();

if(ua.indexOf("windows nt") !== -1) {
  console.log("「Microsoft Windows」をお使いですね!");
} else if(ua.indexOf("android") !== -1) {
  console.log("「Android」をお使いですね!");
} else if(ua.indexOf("iphone") !== -1 || ua.indexOf("ipad") !== -1) {
  console.log("「iOS」をお使いですね!");
} else if(ua.indexOf("mac os x") !== -1) {
  console.log("「macOS」をお使いですね!");
} else {
  console.log("何をお使いなのですか?");
}

```

## ブラウザ、OS判定の使用例
ユーザーのブラウザとOSの情報をテキストに表示するコードの例を以下に示す。
<p class="codepen" data-height="265" data-theme-id="0" data-default-tab="js,result" data-user="td12734" data-slug-hash="MWgzPjE" style="height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="OS and Browser determine">
  <span>See the Pen <a href="https://codepen.io/td12734/pen/MWgzPjE/">
  OS and Browser determine</a> by T.D (<a href="https://codepen.io/td12734">@td12734</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>

# platform.js
[GitHub](https://github.com/bestiejs/platform.js)上で開発されている、オープンソース(MITライセンス)のライブラリである。

## 使い方
1. 適当なディレクトリで`git clone https://github.com/bestiejs/platform.js.git`するなどして*`platform.js`*(リポジトリ)を入手する。
2. [*platform.js*/**platform.js**](https://github.com/bestiejs/platform.js/blob/master/platform.js)(リポジトリ内のjsファイル)をサーバーなどにアップロードする。
3. htmlやjsから**`platform.js`**(jsファイル)を読み込む。

### 使用例
右のコメントはMacのFirefoxで実行した場合の文字列を記載してある。
`platform.os`はtoStringしないとobjectが返ってくるので注意。
詳細な使い方は[README.md](https://github.com/bestiejs/platform.js/blob/master/README.md)を参照すること。

```html
<script src="platform.js"></script>
<script>
console.log(platform.name); //Firefox
console.log(platform.version); //69.0
console.log(platform.os.toString()); //OS X 10.14
console.log(platform.layout); //Gecko
</script>

```

## ブラウザ判定
`script src`は環境に応じて変更すること。

```html
<script src="platform.js"></script>
<script>
var br = platform.name.toLowerCase();

if(br.indexOf("chrome") !== -1) {
  console.log("「Google Chrome」をお使いですね!");
} else if(br.indexOf("safari") !== -1) {
  console.log("「Safari」をお使いですね!");
} else if(br.indexOf("firefox") !== -1) {
  console.log("「Mozilla Firefox」をお使いですね!");
} else if (br.indexOf("ucbrowser") !== -1) { //まだ未対応(プルリクにある)
  console.log("「UC Browser」をお使いですね!");
} else if (br.indexOf("samsung") !== -1) {
  console.log("「Samsung Internet Browser」をお使いですね!");
} else if (br.indexOf("opera") !== -1) {
  console.log("「Opera」をお使いですね!");
} else if (br.indexOf("ie") !== -1) {
  console.log("「Internet Explorer」をお使いですね!");
} else if(br.indexOf("edge") !== -1) {
  console.log("「Microsoft Edge」をお使いですね!");
} else {
  console.log("何をお使いなのですか?");
}
</script>

```

## OS判定
`script src`は環境に応じて変更すること。

```html
<script src="platform.js"></script>
<script>
var os = platform.os.toString().toLowerCase();

if(os.indexOf("windows") !== -1) {
  console.log("「Microsoft Windows」をお使いですね!");
} else if(os.indexOf("android") !== -1) {
  console.log("「Android」をお使いですね!");
} else if(os.indexOf("ios") !== -1) {
  console.log("「iOS」をお使いですね!");
} else if(os.indexOf("mac os x") !== -1) {
  console.log("「macOS」をお使いですね!");
} else {
  console.log("何をお使いなのですか?");
}
</script>

```

# ブラウザ、OS判定についての説明
ここではなぜ上記の判定コードになったのか説明する。

## 判定スクリプトはどのような要件を満たすべきか?
環境によって要件は異なるだろうが、ここでは以下の条件を全て満たす判定スクリプトの作成を目指す。

- 2019年9月時点で主要なOSを判定可能
- 2019年9月時点で主要なブラウザをどの主要なOSで開いた場合でも判定可能

今回はシェアが1%以上あるものは主要なものと定義し、判定対象のOSやブラウザとする。

## ブラウザ判定
### 判定対象のブラウザ一覧
2019年8月の時点でシェアが1%以上あるブラウザは以下の通り。([Browser Market Share Worldwide](https://gs.statcounter.com/browser-market-share)参照)
ただし、Android標準ブラウザは除く。

- Google Chrome
- Safari
- Mozilla Firefox
- UC Browser
- Samsung Internet Browser
- Opera
- Internet Explorer
- Microsoft Edge

### 判定の順番

- Chrome,iOS版のFirefoxには`Safari`の文字列が含まれるのでSafariより先に判定
- Edge,Opera,Samsung Internet Browser,UC Browserには`Chrome`の文字列が含まれるのでChromeより先に判定

## OS判定
### 判定対象のOS覧
2019年8月の時点でシェアが1%以上あるブラウザは以下の通り。([Operating System Market Share Worldwide](https://gs.statcounter.com/os-market-share)参照)

- Android
- Microsoft Windows
- iOS
- macOS(OS X)

### 判定の順番

- iosには`mac os x`の文字列が含まれるのでmac osより先に判定

# 判定方法についての考察
上記で2つの判定方法を紹介したが、それぞれにどのような長所があるか、どういう時に使い分けるべきかなどを考察する。

## 長所と短所

### 判定JavaScriptの自作の長短
***長所***

- 判定したいブラウザ、OSのみに絞って判定可能
- 判定スクリプトの軽量化が容易

***短所***

- ブラウザを示す文字列が変化しても即座に対応する事が難しい
- 判定対象外のOSやブラウザのUAが来た場合、誤った結果を返す可能性が高い
- 判定が正確かどうか制作側でテストする必要がある
- ブラウザ判定とOS判定を別個に作る必要がある

### platform.jsの長短
***長所***

- オープンソースなので使用のハードルが低い
- ブラウザ名だけでなく、ブラウザバージョンやOSなどの情報も容易に取得可能
- GitHub上で開発されているので、もしバグが生じても即座に修正される可能性が高い

***短所***

- platform.jsの読み込み処理を書く必要がある
- 2019年9月時点で約40kbとそれなりにサイズが大きいので、トラフィックによってはユーザーのページ読み込み速度に影響が出る可能性がある

## どの場面でどっちを使うべきか
***判定JavaScriptの自作***
ゲーム攻略サイトや広告など、アクセス数が非常に多く、読み込みの高速化が要求されるサイトはこっちが良さそう。

- ページ読み込み速度を最優先にしたいとき
- 特定のブラウザのみ判定したい場合など、そこまで正確性を求めないとき
- 判定スクリプトの作成、保守に割ける人員が居るとき
- サイトの仕様上、外部JSを読み込めないとき

***platform.js***
大体のサイトはこっちが良さそう。

- 判定スクリプトを書きたくないとき
- 判定スクリプトの作成、保守に割ける人員が居ないとき
- 判定の正確性を重視したいとき
- サイトのアクセス数がそれほど多くない時

# 参考記事
[使用してるブラウザを判定したい](https://qiita.com/sakuraya/items/33f93e19438d0694a91d)

- ブラウザ判定でかなり長い間お世話になった

[UserAgentからOS/ブラウザなどの調べかたのまとめ](https://qiita.com/nightyknite/items/b2590a69f2e0135756dc)

- 最新のUA事情を知る時にお世話になっている