スキップしてメイン コンテンツに移動

些細な日常

JavaScriptでブラウザとOSを判別してソースコードの振り分けに使う

僕が提供するBlogger用テンプレートのImaginaryへの質問で、デザインが壊れて何とかして欲しいというのがあって原因の一つにブラウザがある。サイト作成のHTMLやCSSやJavaScriptのコードの一部に未対応だったり、場合によってアップデートでバグが起きて急に反映しなくなったりもする。

ブラウザの問題はいつか対応して来ると期待されるかぎり、待つしかないけれども、その間、テンプレートが壊れているのはどうにも耐えられないとなるとコードを変えるか多少の違和感ならばブラウザを除外してやり過ごせる。

今回、JavaScriptで訪問者のブラウザをOSと共にデバイス毎に判別して一部のコードを除外する方法を調べたので、纏めておきたい。

JavaScriptでブラウザとOSを判別する

JavaScriptでブラウザが何かを取得する方法としてユーザーエージェントクライアントヒント APIのNavigator.userAgentDataプロパティを使う。

注意:判別したいブラウザが対応してなければ(Can I Use…旧来のNavigator.userAgentプロパティを使う。

ユーザーエージェントクライアントヒント API (User-Agent Client Hints API) は、クライアントヒントを拡張し、 User-Agent レスポンスおよびリクエストヘッダー、および JavaScript API によってブラウザーとプラットフォーム情報を公開する方法を提供します。

ユーザーエージェントクライアントヒント API|MDN|Mozilla

サイトを閲覧中のユーザーエージェントのブラウザとOS(プラットフォーム)の名前を取得して判別することができる。

構文はwindow.navigator.userAgentData、またはwindowを省略してnavigator.userAgentDataにプロパティやメソッドを使ってユーザーエージェントクライアントヒント APIのオブジェクトのインスタンスを取得できる。

現在の閲覧中のユーザーエージェントクライアントヒントの内容

※Navigator.userAgentDataプロパティで取得して表示している。

ブラウザの判別に役立つ三つのインスタンスプロパティ

Navigator.userAgentData.brands
ブラウザ名とヴァージョンを格納した配列を返す。
  • brand:ブラウザ名
  • version:ヴァージョン
Navigator.userAgentData.mobile
モバイルかどうかの真偽値(ブーリアン)を返す。
Navigator.userAgentData.platform
OS名を返す。

ブラウザ名やOS名の文字列を使って条件文のifなどにかけてコードを振り分ける。

ブラウザ名に含まれる文字列の例

  • Microsoft Edge
  • Google Chrome
  • Opera

いつか対応すればSafariやFirefoxなどの文字列も使えるだろう。

OS名に含まれる文字列の例

  • Mac OS X
  • Windows NT
  • Linux
  • iPhone
  • Android

ブラウザ名だけの条件で振り分けるプログラム

ブラウザ名だけで振り分けるならばif文でNavigator.userAgentData.brandsから取得したブラウザ名が判別したいものに当て嵌まるかどうかをinclude()メソッドにかけて調べる。

やってみるとブラウザ名の配列のどこに一般的なブラウザ名が入るかが一定ではないようなので――閲覧するブラウザやヴァージョンによって順番が異なる場合がある――Navigator.userAgentData.brandsに関して条件文にfind()メソッドを使って判別したいブラウザ名があれば見付かるところまで調べると良いと思う。

Chromeを判別するサンプルのソースコード

const browserbrands = navigator.userAgentData.brands;
if (browserbrands.find(elm => elm.brand.includes("Google Chrome"))) {
// Chromeで使用したいソースコード
} else {
// Chrome以外で使用したいソースコード
}

Navigator.userAgentData.brandsの配列をfind()メソッドにかけて個々の要素のどこかに判別したいブラウザ名が含まれているかどうかでソースコードを振り分けることができる。

ブラウザ名とOSの条件で振り分けるプログラム

ブラウザ名とOS名で振り分けるならば先ずはNavigator.userAgentDataから取得したブラウザ名だけの振り分けを行って当て嵌まるときと当て嵌まらないときのそれぞれにやはりNavigator.userAgentDataから取得したOS名が含まれるかどうかのincludes()メソッドを使ったif文を入れ子にして調べる。

WindowsのChromeを判別するサンプルのソースコード

const browserbrands = navigator.userAgentData.brands, browserplatform = navigator.userAgentData.platform;
if (browserbrands.find(elm => elm.brand.includes("Google Chrome"))) {
if (browserplatform.includes("Windows")) {
// WindowsのChromeで使用したいソースコード
} else {
// Windows以外のChromeで使用したいソースコード
}} else {
if (browserplatform.includes("Windows")) {
// WindowsのChrome以外で使用したいソースコード
} else {
// Windows以外のChrome以外で使用したいソースコード
}}

同じ名前のブラウザをパソコンとスマホで振り分けるならばOS名だけではなく、mobileインスタンスプロパティの真偽値を振り分けの条件に使っても良いと思う。

Navigator.userAgentDataプロパティは安全性を得るためはSSL暗号化通信のHTTPS接続での閲覧が前提とする場合がある。試すと通常のHTTP接続ではブラウザ名やOS名を取得できなかったので、近年は殆ど見かけないけど、HTTPS接続以外も含めるならば旧来のNavigator.userAgentプロパティを使わなくてはならない。

userAgentDataと旧来の方法の使い分けのソースコード

現在、主要なブラウザの一部がNavigator.userAgentDataプロパティに対応してないので、旧来のNavigator.userAgentプロパティを使わなくてはならないので、両方に対応するためのプログラムを紹介する。

if (navigator.userAgentData) {
// 新しいNavigator.userAgentDataプロパティによる処理
} else {
// 古いNavigator.userAgentプロパティによる処理
}

if文に「navigator.userAgentData」を入れるとブラウザがNavigator.userAgentDataプロパティに対応しているかどうかを判定できる。

Chromeは古い方のNavigator.userAgentプロパティで得られる内容をを削減するといっていて今年の四月には完了する。

情報量削減後の User-Agent には、リクエストを送信したパソコンまたはモバイルのブラウザのブランドとメジャー バージョン、プラットフォームが含まれます。それ以外のデータを利用する場合は、User-Agent Client Hints を使用して、ユーザーのデバイスや状態に関する特定の情報をリクエストします。

User-Agent の情報量削減|Chrome Developers|Google Developers

ブラウザの振り分けに関して大丈夫だけど、他のブラウザがどうなるかは分からないし、個人情報を守るための信頼性が確保される新しい方のNavigator.userAgentDataプロパティへ移行する流れがあるので、サイト作成でも使わないと不十分な場合が出て来ないとはかぎらない。

以前はブラウザ名やOS名を、直接、取得する方法がなくて代替案としてNavigator.userAgentプロパティが用いられた。

訪問者のユーザーエージェントを取得することができてブラウザ名やOS名も含まれているからブラウザをデバイス毎に判別することに使えた。

信頼性が完全なものではないからブラウザを確実に判別したい場合は使わないように注意しなくてはならない。

メモ: 仕様書では、ブラウザーがこのフィールドを介して提供する情報をできるだけ少なくすることを求めています。このプロパティの値は、同じブラウザーの将来のバージョンでも同じままであると仮定してはいけません。まったく使用しないようにしたり、ブラウザーの現在のバージョンと過去のバージョンのためだけに使用するようにしてください。新しいブラウザーは、古いブラウザーと同じ UA、またはその一部を使い始めるかもしれません。ブラウザーエージェントが本当にこのプロパティによって広告されたものであるという保証は本当にありません。

また、ブラウザーのユーザーはこのフィールドの値を変更することができることを覚えておいてください (UA なりすまし)。

Navigator.userAgent|MDN|Mozilla

ユーザーエージェントの内容はいつも同じとはかぎらないことと訪問者が変更できることから信頼性がない。

サイトのデザインを、暫くの間、少しだけ止めるくらいならば使っても構わないのではないかと思う。

Navigator.userAgentプロパティの使い方

構文はwindow.navigator.useragent、またはwindowを省略してnavigator.useragentで、ユーザーエージェントを取得することができる。

現在の閲覧中のユーザーエージェントの内容

※Navigator.userAgentプロパティで取得して表示している。

ユーザーエージェントにブラウザやOSの名前が含まれているからそうした文字列があるかないかを調べるとブラウザをデバイス毎に判別できてコードの振り分けに使える。

if文でNavigator.userAgentプロパティで取得したユーザーエージェントをincludes()メソッドにかけてブラウザ名が含まれるかどうかを判別する。

ユーザーエージェントのブラウザ名は必ずしも一定ではないから文字列の英語の大文字と小文字をどちらかに統一した方が使い易いので、大文字に纏めるtoUpperCase()メソッドか小文字に纏めるtoLowerCase()メソッドもやっておく方が良いと思う。

ブラウザ名はNavigator.userAgentDataのbrandの「Microsoft Edge」の「Microsoft」や「Google Chrome」の「Google」のようなメーカー名も付くとはかぎらないので、ブラウザ名だけで、条件付ける。

加えて主要なブラウザではEdgeが「Edg」になったり、ブラウザ名を、そのまま、使っても判別できない場合には変更する必要がある。

どう振り分けるかはNavigator.userAgentDataプロパティの場合と同じで、条件がブラウザ名だけならばif文を、そのまま、使ってブラウ名とOS名などの複数ならぱ入れ子にして使う。

Chromeを判別するサンプルのソースコード

const uainfo = navigator.userAgent.toLowerCase();
if (uainfo.includes("chrome")) {
// Chromeで使用したいソースコード
} else {
// Chrome以外で使用したいソースコード
}

WindowsのChromeを判別するサンプルのソースコード

const uainfo = navigator.userAgent.toLowerCase();
if (uainfo.includes("chrome")) {
if (uainfo.includes("windows")) {
// WindowsのChromeで使用したいソースコード
} else {
// Windows以外のChromeで使用したいソースコード
}} else {
if (uainfo.includes("windows")) {
// WindowsのChrome以外で使用したいソースコード
} else {
// Windows以外のChrome以外で使用したいソースコード
}}

ユーザーエージェントは変更される可能性があるけど、現時点で異なるブラウザで同じ文字列が含まれる場合があり、EdgeのユーザーエージェントにChromeとSafari、ChromeのユーザーエージェントにSafarが含まれるし、異なるOSで同じ文字列が含まれる場合があり、AndroidのユーザーエージェントにLinuxが含まれる状況だから振り分けの仕方に注意を要する。

複数のブラウザ名やOS名の文字列を含むものを振り分けたいときは他のものの振り分けに含まれないようにする。

複数のブラウザ名を持つユーザーエージェントの振り分けの例

const uainfo = navigator.userAgent.toLowerCase();
if (uainfo.includes("edg")) {
// で使用したいソースコード
} else if (uainfo.includes("chrome")) {
// Chromeで使用したいソースコード
} else if (uainfo.includes("safari")) {
// Safariで使用したいソースコード
} else {
// EdgeとChromeとSafari以外で使用したいソースコード
}

複数のOS名を持つユーザーエージェントの振り分けの例

const uainfo = navigator.userAgent.toLowerCase();
if (uainfo.includes("android")) {
// Androidで使用したいソースコード
} else if (uainfo.includes("linux")) {
// Linuxで使用したいソースコード
}

if文で複数のブラウザやOS名の文字列を含むものを先に振り分けてからその他のものをelse ifや入れ子で後から振り分ければ混ざることはない。

参考サイト

コメント

最近の投稿

日付: 

冬の防寒対策として最も温めるべき首と手首と足首

イメージ

人気の投稿

平田監督の白井球審の誤審への抗議はパワハラへの強力な対処法に他ならない

イメージ

日本プロ野球で 佐々木朗希が完全試合を実現して 次の試合も八回まで無安打と無失点の状況で、次の試合はどうかと注目した4月24日の対オリックスバファローズ戦は初回の先頭打者の初球にヒットを打たれて五回に二失点を喫して連続の無安打と無失点が両方とも途絶えてしまった。 しかし予想外...

宜保愛子は本物の霊能力者だと考えられる三つの真実

イメージ

昭和から平成にかけてテレビや雑誌で何度も大きく取り上げられて物凄く活躍した霊能力者の 宜保愛子 がいた。何気なく昔のテレビ番組を観ていたら霊視は嘘だったと思えない内容で、本当にびっくりした。昔、そんなに引き付けられて観ていたわけではないし、改めて霊能力が本当かどうかを確かめようと...

伊良部秀輝が自殺した原因はミッドライフクライシスによる鬱と飲酒だと考える

イメージ

プロ野球選手の 伊良部秀輝 が自殺したと知ってショックを受けたことがあった。もう十年以上前になる。2011年の夏、享年四十二と早過ぎたのに加えて大好きな投手の一人だったので、とても残念に感じた。 目次 伊良部秀輝が大好きだった記憶 負けても自分のスタイルを貫き通した 野球への...

後藤浩輝と抑鬱傾向による突発的な自殺

イメージ

中央競馬でトップ騎手の一人だった 後藤浩輝 が亡くなっていると気付いた。二千十五年だからまだ二年前の死だった。競馬ファンならば誰でも知っているくらい有名なはずだけれどもテレビのバラエティー番組でも見かけていたと思う。個人的には ダービースタリオン (ゲーム)に熱中していて後藤浩輝...