iPhoneXのセーフ エリア対応について

iPhoneXに対応するためには、Xcode9系でビルドする必要があるため、MonacaでiPhoneXに対応するためには、Cordova7.1用のプロジェクトを利用する必要があります。

~~この記事の公開時点では、Monacaで提供しているCordova7.1プロジェクトは、iPhoneXに対応するスプラッシュ画像を登録することができないため、残念ながらiPhoneXを全画面で利用することができません。~~

現在、MonacaクラウドIDEでは、iPhoneXに対応するスプラッシュ画像を登録することが可能になっています。

対象プロジェクトの `設定` > `iOSアプリ設定` > `オートリサイズモード` から、iPhoneXに対応するスプラッシュ画像を登録することができます。

# セーフ エリア

iPhoneXでは、画面の中に `セーフ エリア` という領域があります。
このセーフ エリアの設定は、アプリ側で対応する必要があります。

今回は、Monacaで提供しているCordova7.1プロジェクトのセーフ エリアへの対応例をあげてみたいと思います。

# viewport-fit=cover を利用する

MonacaがiPhoneXに対応していない現状で、Cordova7.1プロジェクトをビルドし、iPhoneXで表示させた場合、上下に余白が表示されます。

この余白に対応する場合は、viewport設定に `viewport-fit=cover` を追加します。

```html:設定例
<meta name="viewport" content="viewport-fit=cover, width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
```

viewport-fit=coverを追加することで上下の余白に対応することができます。

これから説明する設定は、このviewport-fit=coverを追加した状態での設定になります。


# constant(safe-area-inset-xxx) を利用する


セーフ エリア対策として、下記の設定が用意されています。

- constant(safe-area-inset-top);
- constant(safe-area-inset-bottom);
- constant(safe-area-inset-left);
- constant(safe-area-inset-right);


この設定をcssのpadding-xxxに設定することで、セーフ エリアへのpaddingやmargin設定を行なってくれます。

```css:設定例
<style>
  html {
    padding-top: constant(safe-area-inset-top);
    padding-bottom: constant(safe-area-inset-bottom);
    padding-left: constant(safe-area-inset-left);
    padding-right: constant(safe-area-inset-right);
  }
</style>
```

# env(safe-area-inset-xxx) を利用する

iOS11.2からconstantではなく `env` を使用するようになりました。
そのため、iOS11.2系を使用している場合は、constantでは動作しなくなります。

使い方は、constantと同じです。

```css:設定例
<style>
  html {
    padding-top: env(safe-area-inset-top);
    padding-bottom: env(safe-area-inset-bottom);
    padding-left: env(safe-area-inset-left);
    padding-right: env(safe-area-inset-right);
  }
</style>
```

# iOS11系に対応する

iOSのバージョンによって、safe-area-inset-xxxの設定方法が変わるため、対応が必要になります。
現在のところは、両方を記述することで対応できるようです。

```css:設定例
<style>
  html {
    padding-top: constant(safe-area-inset-top);
    padding-bottom: constant(safe-area-inset-bottom);
    padding-left: constant(safe-area-inset-left);
    padding-right: constant(safe-area-inset-right);

    padding-top: env(safe-area-inset-top);
    padding-bottom: env(safe-area-inset-bottom);
    padding-left: env(safe-area-inset-left);
    padding-right: env(safe-area-inset-right);
  }
</style>
```

# UIWebViewへの対応

constantやenvを正常に動作させるためには、WKWebView環境が必要になるようです。
残念なことに、Cordova7.1プロジェクトで利用されているWebViewは、UIWebViewになります。

そのため、Cordova7.1プロジェクトでconstantやenvを設定しても、正常に動作してくれません。
Cordova7.1プロジェクトでセーフ エリアに対応させるためには、直接数値を設定する必要があります。

```css:設定例
<style>
  html {
    padding-top: 44px;
    padding-bottom: 34px;
    padding-left: 0px;
    padding-right: 0px;
  }
</style>
```

また、このセーフ エリアは、portraitとlandscapeでpadding-bottomのサイズが変わります。
サイズは、下記になります。

- portraitの場合：34px
- landscapeの場合：21px

そのため、portraitとlandscapeで設定を変更させる必要があります。


# メディアクエリを利用する

UIWebView環境でportraitとlandscapeのセーフ エリアに対応させる場合は、メディアクエリを利用する方法があります。

メディアクエリで、portraitとlandscapeの設定を行い、JavaScriptで動的に反映させることで対応することができます。

```html:設定例
<script>
  document.addEventListener('DOMContentLoaded', function() {
    if (isIPhoneX()) {
      document.documentElement.className = "iphonex";
    }
  }, false);
  
  function isIPhoneX() {
    return isIPhone() && (window.screen.width === 375 && window.screen.height === 812 || window.screen.width === 812 && window.screen.height === 375);
  }
  
  function isIPhone() {
    return !!(navigator.userAgent.match(/iPhone/i));
  }
</script>

<style>
  @media screen and (orientation: portrait) {
    .iphonex {
      padding-top: 44px;
      padding-bottom: 34px;
      padding-left: 0px;
      padding-right: 0px;
    }
  }

  @media screen and (orientation: landscape) {
    .iphonex {
      padding-top: 0px;
      padding-bottom: 21px;
      padding-left: 44px;
      padding-right: 44px;
    }
  }
</style>
```

iPhoneXの識別は、navigator.userAgentの値と画面サイズで行なっています。


# おわりに

MonacaのCordova7.1プロジェクトをiPhoneXのセーフ エリアに対応させるためには、CSSやJavaScriptでの対応が必要になります。

MonacaでのiPhoneXセーフ モード対応の参考になれば幸いです。