毎度、必要になったときに調べていたiOS Safari向けWebアプリ開発の情報をまとめました。
iOS Safariの画面サイズを有効活用したい
すでにコピペで拡散している情報をまとめるだけでは能がないので、すっかり定着したレスポンシブレイアウトに逆行しつつも「Webアプリ」として画面サイズを有効活用するための一連の情報になることを目的とします。
もっとも、そういうことならすでにjQuery Mobileや類似フレームワークもいくつか存在しますが、どうしても余計なスタイル定義や不透明な処理も多いので、よりライトに必要最小限の設定に留めたいという意図もあります。
まずは判定
UserAgentで大雑把にふるい落とす
容易に偽装可能なUserAgentですが「iOS Safariではない」判定には、やはり便利です。下記で browser が “Safari” でない場合は、iOS Safari以外と考えてよいです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
var ua = window.navigator.userAgent; if ( ua.indexOf( "Intel Mac" ) !== -1 ) { browser = "Chrome-PC"; } else if ( ua.indexOf( "CriOS" ) !== -1 ) { browser = "Chrome"; } else if ( ua.indexOf( "Lunascape" ) !== -1 ) { browser = "Lunascape"; } else if ( ua.indexOf( "Mercury" ) !== -1 ) { browser = "Mercury"; } else if ( ua.indexOf( "Version" ) !== -1 && ua.indexOf( "Safari" ) !== -1 ) { browser = "Safari"; if ( ! ua.match( /iPhone|iPod|iPad/ ) ) { browser += "-PC"; } else if ( window.navigator.platform.indexOf( "Simulator" ) !== -1 ) { browser += "-Simulator"; } } else { browser = "Other"; } |
Webkitかどうかを厳密に判定する
さらに今度は、下記で engine が “Webkit” でない場合は、iOS Safari以外で断定可能です。ほぼ偽装不可能なレンダリングエンジンごとの実装(仕様)に基づいた判断ロジック(バグ等を応用したハックではない)のため、とても良い方法ではないかと思います。
1 2 3 4 5 6 7 8 9 10 |
var engine; if ( "undefined" !== typeof window.execScript ) { engine = "Trident"; } else if ( "undefined" !== typeof window.Components ) { engine = "Gecko"; } else if ( "undefined" !== typeof window.defaultstatus ) { engine = "Webkit"; } else if ( "undefined" !== typeof window.opera ) { engine = "Presto"; } |
ここまでで、SafarikかつWebkitなら、ほぼiOS Safariと見なせますが、PC Safariによる偽装を回避する必要があります。
スマホ独特のプロパティでPCを排除する
iOS Safariには「ホーム画面に設定する」という機能がありますが、この機能が有効かどうかは次のコードで判断可能です。
1 2 3 4 |
var device; if ( typeof window.navigator.standalone === "undefined" ) { device = "PC"; } |
最後にiPhone4[S]、iPhone5、iPad、iPad Retinaを切り分けます。
解像度と画面サイズでiOSデバイスを切り分ける
メディアクエリを使った方法で、個人的にはあまり釈然としませんが、この情報も偽装が容易ではないと思われるため、現実解としては使わざるを得ないと思っています。
■CSS定義
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
.dummy-device-class { display: none; position: absolute; left: -1px; top: -1px; width: 1px; height: 1px; } @media all and (orientation:portrait) and (device-aspect-ratio:40/71) { #iphone5 { display:block; } } @media all and (orientation:landscape) and (device-aspect-ratio:40/71) { #iphone5 { display:block; } } @media all and (orientation:portrait) and (device-aspect-ratio:2/3) and (-webkit-min-device-pixel-ratio:1.5) { #iphone4 { display:block; } } @media all and (orientation:landscape) and (device-aspect-ratio:2/3) and (-webkit-min-device-pixel-ratio:1.5) { #iphone4 { display:block; } } @media all and (orientation:portrait) and (device-aspect-ratio:3/4) { #ipad { display:block; } } @media all and (orientation:landscape) and (device-aspect-ratio:3/4) { #ipad { display:block; } } |
■JavaScript
1 2 3 4 5 6 7 8 |
var device; for ( var id in ["iphone4", "iphone5", "ipad"] ) { var dummyElement = '<div class="dummy-device-class" id="' + id + '"></div>'; $('html').append( dummyElement ); device = ( $("#"+id).css("display") === "block" ) ? id : ""; $("#"+id).remove(); if ( device !== "" ) break; } |
device に “iphone4”, “iphone5”, “ipad” のいずれかが代入されますが、もし “” の場合は、iOSデバイス以外です。
念のため、説明しておくと、原則は不可視となるように定義した .dummy-device-class というクラスを指定しつつ、#iphone4、#iphone5、#ipadという ID でダミー要素を追加しては、判定後すぐに削除という処理です。
メディアクエリでは、回転方向とアスペクト比、iPhone4[S]用にはさらに解像度(device-pixel-ratio)に応じて、#iphone4、#iphone5、#ipadの有効無効が振り分けられるため、$(“#”+id).css(“display”) === “block” という判定が真なら、それぞれiPhone4[S]、iPhone5、iPadになります。
上記CSS定義と、JavaScript判定を増やせば iPad Retina もここで判断することは可能ですが、横×縦の総ピクセル数で非Retinaの4倍ということもあり、あえて initial-scale(表示拡大率)の計算用に別途JavaScriptの処理に委ねます。
iOSデバイスごとに適した設定
レスポンシブレイアウトもいいのですが、確かにiPhone4[S]、iPhone5は小さいとはいえ、表現可能な解像度ではPCにそれほど劣っていません。それにもかかわらずiPhone3G[S]からの名残りなのか、横サイズを320pxで設計&実装するための情報ばかりが主流なのが残念です。
本来iOSデバイスが表現可能な解像度に設定する
原則は initial-scale=1.0 ですが、iPad Retinaは他のiOSデバイスと比べると逆に解像度が高すぎるため、場合によっては、initial-scale=0.5とする落としどころもアリではないかと思っています。
1 2 3 4 |
var initialScale = 1.0; initialScale /= window.devicePixelRatio; // 現状ではiPadの場合に、この行をコメントアウトすることでiPad Retinaを非Retinaと同じ解像度に統一可能 var viewport = '<meta name="viewport" content="initial-scale=' + initialScale + ', user-scalable=no">'; $("head").prepend( viewport ); |
あとは、アドレスバーを隠す処理、不用意にフリックで画面スクロールしてしまわないための設定、テキストや画像のコピペ対策ですが、iPhoneのLandscapeのみ、アドレスバーを隠す方法は、ありふれた情報だけでなく、少し工夫が必要です。
iPhone Landscapeのアドレスバーを確実に隠す方法
これは、ほとんどそれらしい情報は存在せず、試行錯誤でなんとか挙動として問題ないと判断に至った手法です。
重要なのは、デバイス回転で Landscape に切り替わったときと、Landscape で最大化、非最大化のリサイズが発生したときのケアです。
つまり、この処理を施さないと、アドレスバーが中途半端な位置で残ってしまう現象が発生します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
// device はすでに"iphone4", "iphone5", "ipad" のいずれかが代入されているものとする var isLandscape = ( Math.abs( orientation ) === 90 ) ? true : false; var width = $(window).width(); var height = $(window).height(); // $(window).height()では正確な値が取得できないケースの調整 if ( ( isLandscape === false && device === "iphone4" && height === 712 ) || ( isLandscape === false && device === "iphone5" && height === 888 ) || ( isLandscape === true && device === "iphone4" && height === 416 ) || ( isLandscape === true && device === "iphone5" && height === 416 ) ) { height += 120; } var scrollTimerId = setTimeout( function() { window.scrollTo(0,1); cleanTimer( scrollTimerId ); // 画面リサイズイベントをフック*重要* $(window).on("resize", function() { // body サイズを再設定する*重要* $("body").css( { 'width' : width + 'px', 'height' : height + 'px' } ); scrollTimerId = setTimeout( function() { window.scrollTo(0,1); cleanTimer( scrollTimerId ); } ); } ); } ); function cleanTimer( _id ) { if ( typeof _id !== "undefined" && _id !== null ) { clearTimeout( _id ); } } |
上記の処理を orientationchange イベントのリスナーでも呼び出します。
1 2 3 |
window.addEventListener('orientationchange', function(e) { // アドレスバーを確実に隠すコード } ); |
あとは、ごくありふれた設定です。
ごくありふれた設定の数々(ばかりでもないか!?)
不用意にフリックで画面スクロールさせない
1 2 3 |
window.addEventListener('touchstart', function(e) { document.body.ontouchmove = e.preventDefault() }, false ); |
テキストや画像のコピペ対策
1 |
* { -webkit-user-select: none; } |
WebClipモードでツールバーを非表示
1 |
<meta name="apple-mobile-web-app-capable" content="yes"> |
イマイチ実用性に欠けるがWebClipでステータスバーを透過する
1 |
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent"> |
ホーム画面に設定の際の名称を指定
1 |
<meta name="apple-mobile-web-app-title" content="hoge"> |
ホーム画面に設定の際のアイコンを指定
ただ、このタグ埋め込まなくても、ちゃんとWebサーバにGETリクエスト飛んでくるんですよね・・・
光沢処理なしは、rel=”apple-touch-icon-precomposed” です。
1 2 3 |
<link rel="apple-touch-icon" href="touch-icon-iphone.png"> <link rel="apple-touch-icon" sizes="114x114" href="touch-icon-iphone.png"> <link rel="apple-touch-icon" sizes="72x72" href="touch-icon-iphone.png"> |
WebClipモード用にスプラッシュ画像も指定できちゃうらしい
そこまでWebClip(Standalone)にこだわってるわけでもないので、試していませんm(__)m
1 2 3 4 |
<link rel="apple-touch-startup-image" sizes="1024x748" href="img/splash-screen-1024x748.png"> <link rel="apple-touch-startup-image" sizes="768x1004" href="img/splash-screen-768x1004.png"> <link rel="apple-touch-startup-image" href="img/splash-screen-320x460.png"> <link rel="apple-touch-startup-image" sizes="640x960" href="img/splash-screen-640x960.png"> |
未だに16px四方ってのも・・・と思いつつのfavicon
1 |
<link rel="shortcut icon" href="favicon.ico"> |
だいたい、こんなところかな?
追加です。
WebClipモードを意識する場合、オフラインファーストで.manifestファイルも用意したほうが良いですね。
また、その場合、WebサーバのMIME TYPE設定とHTMLタグで.manifestファイルの指定も必要です。Apacheならconfファイルか、AllowOverride設定がなされているなら .htaccess に以下を記述します。
1 |
AddType text/cache-manifest .manifest |
1 |
<html manifest="cache.manifest"> |
参考情報
とても参考になりました
[修正]iPadのSafariでwebclip(webAppモード)かどうかを判断するJavascript
mobile safariのmetaタグのサポートをまとめてみた
iOSでウェブサイトをフルスクリーン表示させる
Memo, [iOS][mobile Safari]フルスクリーンに対応させるmetaタグやスプラッシュ画像の指定
iPadでHTML5でWebアプリを作ってみました。
このあたりも選別&網羅したいと思ってます
アプリケーション キャッシュを初めて使う
window.navigator.onLine
iPhone向けSafari専用のあれこれ。
Memo, iOS 6 + Standalone mode + Full screen 指定だとGPS(Geolocation)が使えない
といった処理をjQueryプラグインでGitHubに公開
スプラッシュやアイコン設定は迷って網羅していませんが、上記の処理をGitHubに置いたので、iOS Safari限定のニーズがあるようなら、ぜひ使ってください。
jquery.strict-ios.js
iOS Safariかどうかをなるべく厳密に判定し、アドレスバーの非表示等の基本となるViewを設定するjQueryプラグイン
SourceForge.JPでいくつかjQueryプラグインを公開してみたものの、管理画面のメニュー構成がとても難解なため、今後はGitHubを利用します。まだまだ作法も勝手もわからず悪戦苦闘中ながら、gh-pagesにサブドメインをCNAMEして運用し始めました。
No comments yet. You should be kind and add one!
By submitting a comment you grant typista a perpetual license to reproduce your words and name/web site in attribution. Inappropriate and irrelevant comments will be removed at an admin’s discretion. Your email is used for verification purposes only, it will never be shared.