なぜスマホ表示が崩れる?User Agent解析の落とし穴と正しい対処法
#development
導入:スマホ実機だけで起きる謎のバグ

「博士!助けてくれ! Chromeの検証ツールでは完璧にスマホ表示できてるのに、実機で見るとレイアウトが崩壊するんだぜ!」

「ふむ、それはWeb開発あるあるじゃな。『検証ツール』はあくまでエミュレーション。実機とはUser Agent(UA)やレンダリングエンジンが微妙に異なるのじゃ。」

「特にiPhone(iOS)とAndroidのブラウザで挙動が違うこと、よくあるわよね。UAを使って無理やり判定しようとしてない?」

「ギクッ! 『if (ua.indexOf("iPhone") > 0)』みたいなコード書きまくってるぜ…」
1. User Agent文字列の「闇」:なぜこれほど複雑なのか?

「歴史的経緯により、ブラウザのUser Agent文字列は『嘘』の塊となっておる。例えばChromeのUAには『Mozilla』『AppleWebKit』『Safari』という単語が含まれておるし、Safariにも『Chrome』が含まれることがある。」
典型的なUser Agentの例(Windows Chrome)
Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36
「全部のブラウザが『Mozilla/5.0』から始まっている時点でカオスよね。これは昔、Firefox(Mozilla)互換であることを示すためにつけられた名残なの。」
ここが危険!UA判定の落とし穴
- 単純な文字列検索(indexOf)は誤判定の元
- iPadOSはデフォルトで「Macintosh(デスクトップ)」として振る舞う
- InstagramやLINEなどのアプリ内ブラウザ(In-App Browser)は特殊なUAを持つ
2. 実務での正しいアプローチ:UA判定 vs 機能判定

「現代のWeb開発では、特定のブラウザを狙い撃ちする『UA判定』よりも、その機能が使えるかをチェックする『機能判定(Feature Detection)』が推奨されておる。」
Bad Pattern: UAでブラウザを判定して処理を分ける
// 💀 非推奨:メンテナンス地獄の始まり
if (navigator.userAgent.indexOf('Chrome') != -1) {
// Chrome用の処理...
} else if (navigator.userAgent.indexOf('Safari') != -1) {
// Safari用の処理...
}Good Pattern: 機能を判定する
// ✅ 推奨:機能が使えるかどうかで判断
if ('share' in navigator) {
// Web Share APIが使える(スマホなど)
navigator.share({...});
} else {
// 使えない場合のフォールバック(SNSシェアボタン表示など)
}3. それでもUA解析が必要なシーンと対策

「でも博士、アナリティクスで『どのスマホからアクセスが多いか』を知りたい時は、機能判定じゃわからないよな?」

「そうね。アクセス解析や、OSごとの重大なバグ(iOSの特定バージョンだけでCSSが崩れるなど)を回避する時には、やっぱりUA解析が必要になるわ。」
確実なUA解析を行うには、自前で正規表現を書くのではなく、信頼できるライブラリやツールを使用するのが鉄則です。 当サイトのUser Agent解析ツールを使えば、現在のブラウザがどう認識されているか一発で確認できます。
4. プロが教える「一歩先の」テクニカルTips

「最近は『User-Agent Client Hints』という新しい仕組みも登場しておる。これはUA文字列よりも構造化された情報が取得できる、次世代の標準じゃ。」
🚨 現場の注意点:iOSのバージョン依存バグ
iPhoneのSafariは、iOSのバージョンアップで突如として仕様が変わることがあります(vh単位の計算、フレックスボックスの挙動など)。 「iPhoneだから」と一括りにせず、「iOS 15.x」「iOS 16.x」のようにバージョン単位で挙動を確認する癖をつけましょう。 実機検証が難しい場合は、BrowserStackなどのクラウド検証サービスも検討してください。
「完璧なクロスブラウザ対応は果てしない道のりじゃが、まずは自分の環境(UA)を知ることから始めよう。 怪しい挙動に出会ったら、まずはUAを確認して、特定のブラウザ固有の問題ではないか疑ってみるのじゃ!」