※ 表示が正しくないと思う場合は、JavaScript を有効にしてください。
問題がなければ、ここにアクセスしている OS 名が表示されます。
問題がなければ、ここにアクセスしているブラウザ名が表示されます。
問題がなければ、ここに解析元のユーザーエージェント文字列が表示されます。
問題がなければ、ここにデバイス幅(最大)が表示されます。
問題がなければ、ここにウィンドウ幅が表示されます。
デスクトップの Windows 10 (64 ビット)、Chome ブラウザからアクセスした場合の表示例です(クリックで拡大できます)。
【注意点】
ここではユーザーエージェント文字列
Navigator.userAgent
により OS とブラウザを判断していますが、
「ブラウザーの識別は信頼性が低く、ユーザーエージェント文字列はユーザーが設定可能なので推奨されません。」
とされていますので、正しく検出されるとは限りません。
このあと「ユーザーエージェントから OS とブラウザを判断する」と
「ユーザーエージェントに自由な文字列を与える」で検証しています。
現時点でのテスト済みブラウザは、
です。
スマホやタブレットで開く場合は、
https://www.straightapps.com/web/js-os-and-browser.html
)
投稿 December 20, 2022
ここから先は、上記、OS、ブラウザの検出と
まずは、HTML 部です。
単純に、結果を出力するための領域を用意しているだけです。
<p id="os"> 問題がなければ、ここにアクセスしている OS 名が表示されます。 </p> <p id="browser"> 問題がなければ、ここにアクセスしているブラウザ名が表示されます。 </p> <p id="user-agent" class="gray"> 問題がなければ、ここに解析元のユーザーエージェント文字列が表示されます。 </p> <p id="screen-width"> 問題がなければ、ここにデバイス幅(最大)が表示されます。 </p> <p id="client-width"> 問題がなければ、ここにウィンドウ幅が表示されます。 </p> <p> <button onclick="updateClientWidth()" title="画面の表示領域の横幅を更新します。"> 画面の表示領域の横幅を更新 </button> </p> <script type="text/javascript" src="js/os-and-browser.js"></script>
5 つ並んでいる p タグの部分は、それぞれに id を付けた結果表示領域です。 このあと JavaScript が実行されて、結果文字列に書き換えられます。
3 つ目の p タグでは class="gray" とありますが、これはグレーで表示するための css 指定です。 次のように定義されています。
.gray { color:gray; }
一時的に class 指定の代わりに style="color:gray;" としても大丈夫です。
そのあとにある button onclick="updateClientWidth()" の部分は、 「画面の表示領域の横幅を更新」と表示しているボタンです。 onclick 指定がありますので、クリックされると JavaScript の関数 updateClientWidth() が呼び出されることになります。
title で指定した文字列は、PC などでマウスポインタを乗せたときに表示される説明文です。 そして </button> までの間に、ボタン表面に表示する文字列を記入しています。 隙間を持たせるために、両端に全角スペースを入れています。 半角スペースだと無視されてしまいますので、半角スペースを入れたい場合は と記入します。
そして最後の script で、js/os-and-browser.js を読み込んでいます。 初期化時に os や browser などの id を参照していますので、それらの定義よりあとに記述されている必要があります。
以降のセクションで、それぞれ詳細を確認していきます。
なお、ご参考までに、JavaScript ソースコードそのものを、拡張子 js を拡張子 txt に変えて、次のリンクより開けるようにしてあります。
os-and-browser.txt
※ 作成時はタブを 4 文字としていますので、環境によってはタブが 8 文字のため、コメント等がずれて見えるかも知れません。
※ 念のため書き添えますが、このソースコードをこのまま転載・公開することはご遠慮ください。
なお、本サイトのご利用に際しては、必ずプライバシーポリシー(免責事項等)をご参照ください。
投稿 December 20, 2022
ページ読み込み時に実行される JavaScript コードを追っていきます。
ユーザーエージェントとは、OS や ブラウザ(アプリ)を判定するための HTTP リクエストヘッダ文字列、だそうです。
// 「ユーザーエージェント」を取得して、小文字に変換しておきます。
var ua = window.navigator.userAgent.toLowerCase();
document.getElementById('user-agent').innerHTML = ua;
変数 ua に、window.navigator.userAgent で取得できるユーザーエージェント文字列を設定しています。 toLowerCase() 関数が付いていますので、英大文字が英小文字に変換された文字列が設定されることになります。
user-agent という id が付いた部分を書き換えて、そのまま表示してみています。
デスクトップの Windows 10 (64 ビット)、Chome ブラウザからアクセスした場合、このような文字列が返されています。
mozilla/5.0 (windows nt 10.0; win64; x64) applewebkit/537.36 (khtml, like gecko) chrome/108.0.0.0 safari/537.36
ただ、最初に注意点として書いた通り、このユーザーエージェント文字列 Navigator.userAgent は「ブラウザーの識別は信頼性が低く、ユーザーエージェント文字列はユーザーが設定可能なので推奨されません。」 とされていますので、正しく検出されるとは限りません。
OS の判定は、この文字列にどのような(特徴的な)文字列が含まれているかで判断できます。
// OS を判断します。 var strOS = "不明"; if (ua.indexOf("windows nt") !== -1) { strOS = "Windows"; } else if (ua.indexOf("android") !== -1) { strOS = "Android"; } else if (ua.indexOf("iphone") !== -1) { strOS = "iOS(iPhone)"; } // 途中省略 document.getElementById('os').innerHTML = "OS は " + strOS + " です。";
文字列の indexOf 関数 で、その文字列に指定の文字列が含まれているか、含まれていればそのインデックスを返してもらいます。 含まれていない場合は -1 が返されます。
検索したい文字列を与えて、!== -1 で比較していますので、 -1 以外が返された場合、つまり見つかった場合は if が成功します。
各 OS で文字列が異なるわけですが、しっかりまとめられたページは見つかりませんでした。
同じようにブラウザを判断します。
しかし、Windows で Chrome からアクセスしているにもかかわらず、設定された文字列の中には 「chrome」のほか、「applewebkit」や「safari」という文字列が含まれていますので、気を付けなくてはいけません。
mozilla/5.0 (windows nt 10.0; win64; x64) applewebkit/537.36 (khtml, like gecko) chrome/108.0.0.0 safari/537.36
この場合は Chrome であることがわかっていますので、safari の検索より前に chrome を検索する必要がある、ということになります。
他のブラウザではどうなるのか、を調べるのはなかなか大変ですが、とりあえず Windows のブラウザで試した結果は次の通りです。
mozilla/5.0 (windows nt 10.0; win64; x64) applewebkit/537.36 (khtml, like gecko) chrome/108.0.0.0 safari/537.36 edg/108.0.1462.54
これは Windows 10、Edge です。 「chrome」も「safari」もあり、そのあとに「edg」があります。 ということは、edg の判定は優先される必要がある、と考えられます。
mozilla/5.0 (windows nt 10.0; win64; x64; rv:108.0) gecko/20100101 firefox/108.0
Windows 10、Firefox です。 さすがに独自系のブラウザですので、ブラウザ名の部分が綺麗です。
// ブラウザを判断します。 var strBrowser = "不明"; if (ua.indexOf("edg") !== -1 || ua.indexOf("edge") !== -1 || ua.indexOf("edga") !== -1 || ua.indexOf("edgios") !== -1) { strBrowser = "Microsoft Edge"; } // 途中省略 else if (ua.indexOf("chrome") !== -1 || ua.indexOf("crios") !== -1) { strBrowser = "Google Chrome"; } else if (ua.indexOf("firefox") !== -1 || ua.indexOf("fxios") !== -1) { strBrowser = "Mozilla Firefox"; } // 途中省略 document.getElementById('browser').innerHTML = "ブラウザは " + strBrowser + " です";
寄せ集めた情報では Edge に edga と edgios とありますが、Android 版と iOS 版だと想像できます。 できる限り、あとで試します。
投稿 December 20, 2022
このユーザーエージェント文字列からの OS やブラウザ判定の信頼性が低い理由は、 誰でも簡単に書き換えてページにアクセスできるためです。 user-agent spoofing、なりすましと呼ばれているようですが、悪さはしない模様です。 そもそも自由にできる理由は、ウェブ開発時に他ブラウザでアクセスしたらどうみえるか、などのテストを簡単に実行するためだそうです。
Chromium ベースの Edge と Chrome は同じ手順で操作できるとされていますが、ここでは Chrome で操作してみます。
まずは適当なページを開きます。 確認しやすくするにはこのページで試してみて OK です。
開いているページの空白領域で右クリックし、 ポップアップされたメニューから「検証」を選択します。
表示領域内の右側に
さらに開いたメニューから「Network conditions」を選択します。
するとペインの下側に、次のような領域が表示されます。
「ネットワーク条件」を確認・設定できる画面です。
「User agent」の欄をみると、「Use browser default」にチェックが入っています。 つまり、「本来の値を使う」ということです。
「Use browser default」のチェックを外すと、その下にあるドロップダウンリストなどが利用可能状態になります。
初めてアクセスした場合は、「Custom...」のようになっているかもしれませんが、 このドロップダウンリストを開いて、試したい OS やブラウザ、どれか 1 つを選択します。
例えば iPhone iOS 13.2 の Safari の情報を設定することができます。
「Safari - iPhone iOS 13.2」を 選ぶとすぐ下に文字列が表示されました。
Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1
文字列が長いので、画面には収まっていませんから、注意が必要です。
設定可能な組み合わせが限られたリストですが、正しいユーザーエージェントが設定されるというのは助かります。 カスタム設定も可能ですので、不明な OS、不明なブラウザもテストできるようです。
「保存」ボタンなどはありませんので、選択したらすぐ適用されるようです。
そのまま(タブもペインも閉じないで)このページをリロードすると、
mozilla/5.0 (iphone; cpu iphone os 13_2_3 like mac os x) applewebkit/605.1.15 (khtml, like gecko) version/13.0.3 mobile/15e148 safari/604.1
と表示されましたので(小文字に変換しているようで英大文字は小文字になっていますが)、その値になりました。 つまり、OS は iOS(iPhone) となり、ブラウザは Safari であると判定されました。
続けて、Use browser default にチェックを入れてページをリロードすれば、本来である
mozilla/5.0 (windows nt 10.0; win64; x64) applewebkit/537.36 (khtml, like gecko) chrome/108.0.0.0 safari/537.36
となりましたので、危険性はなさそうです。
iPhone Safari を選んでいる状態で新しいタブを開き、 もう 1 つこのページを表示させてみると、Windows の Chrome になりましたので、 ネットワーク・コンディションズの有効範囲はそのタブのみ、と言えそうです。
さらに iPhone Safari になっているタブにこのページのURL を入力して開いてみると、 ペインが表示されているうちは iPhone Safari になりましたので、タブに対して有効であると言えそうです。
その状態で歯車アイコンの右にあるバツボタンでペインを閉じ、(URL 入力ではなく)ページをリロードすると、 Windows の Chrome になりましたので、ペインを閉じると設定が戻るようです。
投稿 December 20, 2022
こちらもいつまで有効なのか微妙ですが、 max-device-width を使えばデバイスの横幅が、 max-width を使えば表示領域の横幅が判断可能です。
スマホで全画面を使っている場合はおそらく両者はぴったり一致します。 スマホで 2 アプリを同時表示していたり、あるいは PC の場合は、両者の値は異なります。
HTML としては、このようになっています。
// デバイスの横幅を判断します。 document.getElementById('screen-width').innerHTML = "デバイスの横幅は " + GetDeviceWidth() + " ピクセルです。"; // 画面の表示領域の横幅を判断します。 document.getElementById('client-width').innerHTML = "画面の表示領域の横幅は " + GetClientWidth() + " ピクセルです。";
つまり、GetDeviceWidth 関数と GetClientWidth 関数 が計算した値を表示するだけです。
ちなみに、「画面の表示領域の横幅を更新」ボタンで呼び出される updateClientWidth 関数は、次のように定義されています。
function updateClientWidth() { document.getElementById('client-width').innerHTML = "画面の表示領域の横幅は " + GetClientWidth() + " ピクセルです。"; }
デバイスの横幅を計算する GetDeviceWidth 関数です。
function GetDeviceWidth() { var w = 100; var str; // まずはざっくり 100 ピクセル単位で探ります。 while (w > 0){ str = "(max-device-width: " + w + "px)"; if (window.matchMedia(str).matches) { break; } w += 100; // 安全対策 if (w > 10000){ document.getElementById('browser').innerHTML = w + " より大きい?"; return w; } }
デバイスの横幅を変数 w に設定することとし、100 で初期化しています。
文字列 str に、「(max-device-width: 100px)」のような文字列を作ります。
window.matchMedia(str).matches で、デバイスの最大幅を検査し、 これが成り立つ時、指定のピクセル数より小さい、という意味になります。
すなわち、まずは「100 ピクセルより小さい?」と聞いて小さければループ脱出、大きければ +100 してループ継続です。 これを繰り返しています。
例えば画面幅が 1024 ピクセルなら、100 より大きい、200 より大きい、300 より大きい、・・・と比較していき、 1100 より小さい、まで到達したらループを脱出します。
// 10 ピクセル単位で探ります。
var nMax = w;
w -= 100;
while (w < nMax){
str = "(max-device-width: " + w + "px)";
if (window.matchMedia(str).matches) {
break;
}
w += 10;
}
ここではまだ 100 ピクセル単位でしかわかりませんので、今度は 10 ピクセル単位で比較します。
例えば画面幅が 1024 ピクセルなら、w が 1100 で始まりますので、 調べるべき最終端の nMax には 1100 を、そして調べ始めの w には -100 した 1000 を設定しています。
先ほどと同じように、1000 で比較してそれより大きい、1010 より大きい、1020 より大きい、1030 より小さい、でループ脱出します。
// 最後は 1 ピクセル単位で探ります。
nMax = w;
w -= 10;
while (w < nMax){
str = "(max-device-width: " + w + "px)";
if (window.matchMedia(str).matches) {
break;
}
w ++;
}
return w;
}
最後に、また同じように 1 ピクセル単位で検査します。
画面幅が 1024 ピクセルなら 1030 で来ますので、1020 から検査を開始し、 1020 より大きい、1021 より大きい、1022 より大きい、1023 より大きい、1024 よりは大きくないのでループ脱出します。
よって、返される値が 1024 になる、ということです。
表示領域のの横幅を計算する GetClientWidth 関数です。
str = "(max-device-width: " + w + "px)"; の代わりに str = "(max-width: " + w + "px)"; を使用しているだけで、基本的には同じです。
つまり、非常に面倒なことをしつつ、画面サイズを決定している、ということになります。
ですので、表示領域の横幅は、特に PC では簡単に変更できてしまいますから、 変更を検出してウェブサイトのデザインをダイナミックに変更したいと思わなくもありませんが、 少なくともこの方式では負荷が大きくなりますから、検査し続ける、というのは現実的ではありません。
画面サイズの変更がイベントで通知されるようであれば、それを使えば負担が少なくて済みますが、今はまだ、そのようなイベントがあるかどうかはわかりません。
ウェブ開発に関するトピックは、「ウェブ開発トップ」にまとめられています。