MENU

スマホやタブレットでスクリーンの縦・横を判定する方法と、画面回転時にどんなイベントが発火するのかを整理し、どの方法で向きを判定してどのイベントに処理を登録すればよいのか、その組み合わせを考察していこうと思います。

ちゃんと調べてみて初めて分かったのですが、iOSとAndroidで挙動が違ったり、それぞれのバージョンやブラウザでも色々異なる点があり、かなり複雑でややこしいです。

それらの挙動の違いもまとめていきます。(私が調べたることができた範囲ですが)

 

目次

縦横の判定方法

まずは、スクリーンの向きを判定し、縦向きの場合と横向きの場合で処理を分ける方法をメモ。

向きの切り替え時やロード時などに自由に呼び出せるように、関数を定義しておきます。

パターン1 : window.orientationで判定する

window.orientationを使用すると、画面の向きが通常の向き(正面に設定されている向き)から時計回りにどれだけ回転しているかを取得できる。

値は 0, 90 , 180 , -90 の4パターン。スマホを縦向きに反転させてもブラウザは逆には向かないので、180は考慮しなくて大丈夫。

function orientCheck(){
  var orientation = window.orientation;
  if (orientation === 0){

    //  縦画面時の処理  //

  } else {

    //  横画面時の処理  //

  }
};

問題点 : Androidの場合、window.orientationで取得できる値は縦長と横長のどちらを「正面」として扱っているかによって異なる。
(横を「正面」としている端末は(たぶん)少数なので、そこまで気にしなくてよさそう)

パターン2 : screen.orientationで判定する

window.orientationでは読み取れなかった正面の設定まで考慮できるように、、 Screen Orientation APIというものが導入され始めているみたいです。

  • Chromでは、 screen.orientation.type
  • Firefoxでは、 screen.mozOrientation.type
  • IEでは、 screen.msOrientation.type

で、現在の向きと、それが正面設定かどうかが文字列で取得できます。

  • portrait-primary : 縦長が正面とされている端末で縦長になっている。
  • portrait-secondary : 横長が正面とされている端末で縦長になっている。
  • landscape-primary : 横長が正面とされている端末で横長になっている。
  • landscape-secondary: 縦長が正面とされている端末で横長になっている。

つまり、正面設定にかかわらず、 portrait-○○であれば縦向きlandscape-○○であれば横向き

function orientCheck(){
  var orientation = screen.orientation || screen.mozOrientation || screen.msOrientation;
  if (orientation.type === "portrait-primary" || orientation.type === "portrait-secondary") {
  
    //縦向き

  } else {
  
    //横向き

  }
};

問題点 : まだ開発段階。iOS版Safariやchromで未対応。

パターン3 : 画面サイズの比較で判定する

単純に画面サイズの縦と横を比較する方法です。

function orientCheck(){
  if (window.innerHeight > window.innerWidth) {

    //縦向き

  } else {

    //横向き

  }
};

回転時のイベント発火方法

次に、画面の向きによって変えたい処理をどのイベントに登録させるかです。

orientationchangeイベントと、 resizeイベントの2パターンがあります。

パターン1 : orientationchangeイベントに登録する場合

3種類の記述方法を紹介しておきます。

$(window).on("orientationchange", function() {
  orientCheck();
});

または、

window.onorientationchange = orientCheck;

または、

window.addEventListener("orientationchange", function() {
    orientCheck();
});

パターン2 : resizeイベントに登録する場合

$(window).on("resize", function() {

  orientCheck();

});

問題点 : スマホのブラウザではスクロールしてもurlバーが引っ込んだり出てきたりするときに発動してしまうので、「 横幅が変わったときにだけ」という条件分岐が必要。また、回転時に複数回発火してしまう。

組み合わせの方での問題点のまとめ

向きの判定方法と、登録するイベントの組み合わせ方によって、それぞれ不具合が出てきますので、そのパターンをまとめていきます。

*Screen Orientation APIをメインにして画面の向きを判定できないことは明白であるので、こちらは除きます。

画面サイズの比較 ×  orientationchangeイベント

  • Androidはorientationchangeイベント→画面回転→resizeイベント、といった順序で処理が行われるので、orientationchangeイベント時に画面サイズを取得しても回転前のもの。
  • iOS10でも同様に、oientationchangeイベント時に画面サイズを取得しても回転前のものだった。(それ以前はバージョンによって変わるっぽい)

画面サイズの比較 ×  resizeイベント

  • Androidの場合、フォーム入力時など、ソフトウェアキーボードが表示されるときにもリサイズが発生してしまい、縦長画面にもかかわらず横長と判定できてしまうケースがある。

window.orientation ×  resizeイベント

  • iOS8,9ではresizeイベント時にはまだwindow.orientationの値が更新されない。(iOS10では大丈夫だった)
  • Androidの古いバージョンでも同様。(Android7.0では大丈夫だった)

Androidがどのバージョンまでこうなのかは詳しくわかりません。 こちらの記事は2017年のものですが4.4.2を使用しており、同様の状態です。

window.orientation × orientationchangeイベント

  • 組み合わせによる不具合はないっぽい。(iOS10とAndroid7.0で実機確認済み)
  • window.orientation自体が問題点として抱える、Androidでの正面問題のみ。

結論

window.orientationで向きの判定を行い、orientationchangeイベント発火時に処理を行う方法が一番無難っぽい。

どうしてもAndroidでの正面問題もカバーしたい場合、Andoroidの場合のみScreen Orientation APIを使用してページのロード時に正面設定を確認しておき、条件分岐させればOKかと思います。

記述方法はいくらでもありますが、例として書いてみるとこんな感じでしょうか。

$(function(){
  var isReverse = false;  //正面が逆かどうかのフラグ
  if( navigator.userAgent.indexOf('Android') > 0) {
    var orientation = screen.orientation || screen.mozOrientation || screen.msOrientation;
    if (orientation.type === "portrait-secondary" || orientation.type === "landscape-primary") {
      isReverse = true;
    }
  }

  $(window).on("orientationchange", function() {
    if(isReverse){
      orientCheckReverse();
    }else{
      orientCheck();
    }
  });
});


//通常用
function orientCheck(){
  var orientation = window.orientation;
  if(orientation === 0){

    //  縦画面時の処理  //

  } else {

    //  横画面時の処理  //

  }
};

//正面逆の場合用
function orientCheckReverse(){
  var orientation = window.orientation;
  if(orientation === 0){

    //  横画面時の処理  //

  } else {

    //  縦画面時の処理  //

  }
};

おまけ:向きによってcssの読み込みを変える

cssを読み込むlinkタグ  ですが、次のような使い方もできるみたいです。

*動作状況など、詳しいことは何も調べてないです。

<!-- 縦の場合に読み込むスタイルシート -->
<link rel="stylesheet" media="all and (orientation:portrait)" href="portrait.css">
<!-- 横の場合に読み込むスタイルシート -->
<link rel="stylesheet" media="all and (orientation:landscape)" href="landscape.css">
- Thank you for reading this to the end. -
TOPへ Top