ブラウザや OS などの環境が異なってもできるだけ同じように表示させるWebページの書き方をクロスブラウザと言います。JavaScript では W3C-DOM への対応が進みつつあるとは言え、ブラウザ依存の部分が多く残っているのが現状です。このページでは JavaScript でクロスブラウザを実現する方法を探ってみます。
JavaScript ではクロスブラウザを実現するために動作の違うブラウザごとに処理を分岐して記述します。ブラウザ分岐の方法はいろいろありますが、次の2つの方法を紹介します。
完全なクロスブラウザを実現する事は事実上不可能です。当然ながらサポートするブラウザの範囲を広げれば記述はより複雑なものになります。どの程度までサポートさせるかは製作者の判断でしょう。しかし、未対応ブラウザでもできればエラーを発生させないような対策は考えるべきでしょう。
navigator オブジェクトのプロパティが返す値に含まれる文字列から OS、ブラウザ、バージョンを判別し、処理を分岐する方法です。細かい分岐が可能ですが、ブラウザによってはnavigator オブジェクトのプロパティが返す値を自由に変更できるものもあり、あまり確実な方法とは言えません。
まずはブラウザによって navigator オブジェクトのプロパティはどのような値を返すかを実際に見てみましょう。
以下の表は私の環境でいくつかのブラウザの navigator.appName と navigator.userAgent を調べた結果です(OS は Windows 98)。
ブラウザ名 | navigator.appName |
---|---|
Internet Explorer 6.0 | Microsoft Internet Explorer |
Netscape 4.7 | Netscape |
Netscape 7.1 | Netscape |
Mozilla 1.6 | Netscape |
Opera 7.23(Operaに設定) | Opera |
Opera 7.23(MSIE 6.0に設定) | Microsoft Internet Explorer |
Opera 7.23(Mozilla 5.0に設定) | Netscape |
ブラウザ名 | navigator.userAgent |
---|---|
Internet Explorer 6.0 | Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; H010818) |
Netscape 4.7 | Mozilla/4.7 [ja] (Win98; U) |
Netscape 7.1 | Mozilla/5.0 (Windows; U; Win98; ja-JP; rv:1.4) Gecko/20030624 Netscape/7.1 (ax) |
Mozilla 1.6 | Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.6) Gecko/20040113 |
Opera 7.23(Operaに設定) | Opera/7.23 (Windows 98; U) [ja] |
Opera 7.23(MSIE 6.0に設定) | Mozilla/4.0 (compatible; MSIE 6.0; Windows 98) Opera 7.23 [ja] |
Opera 7.23(Mozilla 5.0に設定) | Mozilla/5.0 (Windows 98; U) Opera 7.23 [ja] |
※ Opera はブラウザの識別設定によって navigatorオブジェクトのプロパティが返す値を変更する事ができます。
ブラウザの判別は上記のようにして取得した navigator.appName や navigator.userAgent を使って以下のような判別が可能です。
if(navigator.appName=="Netscape"){ // Netscape(Mozillaを含む)用の命令を記述 } if(navigator.appName=="Microsoft Internet Explorer"){ // Internet Explorer 用の命令を記述 } if(navigator.userAgent.indexOf("MSIE")!=-1){ // Internet Explorer 用の命令を記述 } if(navigator.userAgent.indexOf("Gecko")!=-1){ // Netscape 6 以上または Mozilla 用の命令を記述 // ※ この方法では Safari も含まれてしまう } if(navigator.userAgent.indexOf("Gecko/")!=-1){ // Netscape 6 以上または Mozilla 用の命令を記述 // ※ Safari を除外 } if(navigator.userAgent.indexOf("Opera")!=-1){ // Opera 用の命令を記述 } if(navigator.userAgent.indexOf("Safari")!=-1){ // Safari 用の命令を記述 }
【注意】この方法によるブラウザ分岐はあまり確実ではありません。その理由はブラウザによっては navigator オブジェクトのプロパティの値が必ずしもそのブラウザを正しく反映しているものとは限らないからです。いくつかのブラウザは判別のし方によっては Internet Explorer や Netscape に間違って判定される恐れがあるようです。例えば以下のようなブラウザです。
※ Opera は navigatorオブジェクトのプロパティが返す値をブラウザの識別設定によって変更する事ができます。設定によっては Internet Explorer や Netscape であるかのような値を返します。(navigator オブジェクトのプロパティ値を参照)
※ Macintosh 用ブラウザの Safari は userAgent の文字列の中に「Gecko」を含んでいて、appName は「Netscape」を返すそうです。
これら2つのブラウザのようにあらかじめその情報を知っていればこれらの判定を Internet Explorer や Netscape より先に行えば問題は回避できますが、実際にはこのようなブラウザは他にもあるということです。すべてのブラウザの情報を把握するのは事実上不可能です。
次の例はあなたの使用ブラウザを表示しています。
var brName; var aName=navigator.appName; uAgent=navigator.userAgent; if(uAgent.indexOf("Opera")!=-1) brName="Opera"; else if(uAgent.indexOf("Safari")!=-1) brName="Safari"; else if(uAgent.indexOf("MSIE")!=-1) brName="Internet Explorer"; else if(aName=="Netscape"){ if(uAgent.indexOf("Gecko")!=-1) brName="Mozilla系(Netscape 6以上など)"; else brName="Netscape(バージョン4以下)"; } else brName=aName; document.write("あなたのブラウザは"+brName+"のようです。");
ブラウザバージョンを取得する方法は navigator.appVersion というプロパティが用意されていますが、そのままではほとんどのブラウザで本当のブラウザバージョンを取得する事はできないようです。
本当のバージョンを調べるにはブラウザごとに navigator.userAgent や navigator.appVersion の文字列の中から本当のバージョンを示す部分を抜き出さなければなりません。(各プロパティの値はnavigator オブジェクトのプロパティ値を参照ください。)
例えば Internet Explorer のバージョンを検出するには次のようにします。
uAgent=navigator.userAgent; if(uAgent.indexOf("MSIE")!=-1){ // userAgent の文字列から「MSIE 数値;」の数値の部分を切り抜く strTop=uAgent.indexOf("MSIE")+5; strEnd=uAgent.indexOf(";", strTop); version=uAgent.substring(strTop, strEnd); }
Mozilla系(Netscape 6以上など)の場合には「rv:数値」で表示されているMozillaのバージョンで分岐した方が良いかもしれません。Mozillaのバージョンは Netscape 6 は rv:0.x 以下で Netscape 7以上は rv:1.0x以上のようです。(Netscape 6.0などの古いバージョンは「rv:数値」がないものがあるようです。)
uAgent=navigator.userAgent; if(uAgent.indexOf("Gecko/")!=-1){ // userAgent の文字列から「rv:数値」の数値の部分を切り抜く if(uAgent.indexOf("rv:")!=-1){ strTop=uAgent.indexOf("rv:")+3; strEnd=uAgent.indexOf(")", strTop); version=uAgent.substring(strTop, strEnd); else version=""; // かなり古いバージョン }
次の例はもしもあなたの使用ブラウザが Internet Explorer, Mozilla系, Opera の場合にバージョンによって異なるメッセージを出します。
var uAgent=navigator.userAgent; var strTop, version, mes; if(uAgent.indexOf("Opera")!=-1){ // Operaの判定 strTop=uAgent.indexOf("Opera")+6; version=uAgent.substring(strTop, strTop+1); if(version>=7) // バージョン7より上か下か mes="Opera 7以上"; else mes="Opera 6以下"; } else if(uAgent.indexOf("MSIE")!=-1){ // IEの判定 strTop=uAgent.indexOf("MSIE")+5; version=uAgent.substring(strTop, strTop+1); if(version>=6) // バージョン6より上か下か mes="Internet Explorer 6以上"; else mes="Internet Explorer 5.x以下"; } else if(uAgent.indexOf("Gecko/")!=-1){ // Mozilla系(N6以上など)の判定 if(uAgent.indexOf("rv:")!=-1){ strTop=uAgent.indexOf("rv:")+3; version=uAgent.substring(strTop, strTop+1); if(version>=1) // バージョン1.0より上か下か mes="Mozilla系(ver1.0以上 / Netscape 7以上など)"; else mes="Mozilla系(ver0.9x以下 / Netscape 6など)"; } else mes="Mozilla系(ver0.9x以下 / Netscape 6など)"; } else // その他のブラウザ mes="その他"; document.write("あなたのブラウザは"+mes+"ですね。");
OS を判別するには navigator.platform を使って判別する事ができますが、ここでは古いブラウザでも有効な navigator.userAgent を調べる方法を紹介します。
if(navigator.userAgent.indexOf("Win")!=-1){ // Windows 用の命令を記述 } if(navigator.userAgent.indexOf("Mac")!=-1){ // Macintosh 用の命令を記述 } if(navigator.userAgent.indexOf("X11")!=-1){ // UNIX系 用の命令を記述 }
オブジェクトの有無によって処理を分岐する方法です。ブラウザはオブジェクトをサポートしていれば命令を実行し、サポートしていなければ実行しません。この分岐方法はより確実でブラウザによる対応をあらかじめ知っている必要もありません。通常はこの方法を用いるべきでしょう。
オブジェクトやそのオブジェクトがもつプロパティやメソッドなどの有無によって処理を分岐する方法です。ブラウザがそれらをサポートしていれば命令を実行し、サポートしていなければ実行しません。
※ 条件式にメソッドを記述する場合も「( )」(かっこ)は記述しません。
例えば次の例は window.print() という記述がサポートされているかどうかを確かめて実行しています。
if(window.print) // サポートされている場合 window.print(); else // 未サポートの場合 alert("印刷してください。");
この方法を使えばブラウザ独自の記述を利用しておおざっぱにブラウザごとに処理を分岐することができます。以下ではよく使われるものをいくつか挙げてみました。
if(document.layers){ // document.layers に対応しているブラウザ用の命令を記述 // (N4) } if(document.all){ // document.all に対応しているブラウザ用の命令を記述 // (IE4以上, Opera, その他?) } if(document.getElementById){ // document.getElementByIdに対応しているブラウザ用の命令を記述 // (W3C-DOM対応ブラウザ、IE5以上, N6以上(Mozilla), Opera など) } if(window.opera){ // window.operaに対応しているブラウザ用の命令を記述 // (Opera) } if(document.styleSheets){ // document.styleSheetsに対応しているブラウザ用の命令を記述 // (IE4以上, N6以上(Mozilla), その他?) }
※ Opera についてはバージョン6以降を考慮するとします。Opera 6 ではブラウザの識別設定を「MSIE」に設定した時のみ document.all に対応しているようです。
上記のような1つの条件式だけでの判別は必ずしも的確であるとは限りません。例えば document.getElementById に対応しているブラウザすべてが同じようにW3C-DOMに対応しているわけではありません。例えば Opera 6 の場合にはごく限定的にしかW3C-DOMでの記述を実行できないようです。このような場合は以下のように条件を増やすとより厳格に判別されるでしょう。
if(document.getElementById && document.childNodes){ // W3C-DOM対応ブラウザ(より厳格に)用の命令を記述 // (IE5以上, N6以上(Mozilla), Opera 7以上など) }
次の例はあなたの使用ブラウザを大まかに判別しています。
var br; if(window.opera) br="Opera"; else if(document.all){ if(document.getElementById) br="IE5以上"; else br="IE4"; } else if(document.getElementById) br="Mozilla系(N6以上など)"; else if(document.layers) br="N4"; else br="その他"; document.write("あなたのブラウザは"+br+"ですね?");
また、条件式にプロパティを記述する場合には上のような方法では空文字や数値の「0」などを返してうまくいかない場合があります。このような場合には以下のような方法が考えられます。
if(typeof(obj.innerHTML)!="undefined") obj.innerHTML="innerHTMLが使えます。"; else alert("innerHTMLは使えません。");
※ typeof() は引数の型を調べる関数で上のように使用するとサポートしていれば「object」,「function」,「string」,「number」などを、サポートしていなければ「undefined」を返します。ただし、サポートしている場合でもブラウザによって返す文字列が異なる場合があるので注意が必要です。