新人が、ほぼ一人で、PC専用だったWebサービスをタブレット/スマホ対応した話

# はじめに
- 私について
    - プログラム初心者（半年くらい）
    - HTML、JS、CSSが、ググりながらある程度書けるくらい。

- サービスについて
    - 法人向けのERPシステム
    - 人を検索や、人を参照などをするサービス（他にもありますがメインはコレ）
    - HTML、CSS、JS、Java、Tomcat、Nginx、OracleRDBで動いているらしい
    - PCブラウザでしか、動作も検証もしたことが無い
    - 一応マテリアルデザインを参考に作られている

- したこと
    - 前述のサービスの主要画面をスマホ、タブレットで使用できるようにする

- 条件
    - スマホは機能落ちは許容できる
    - タブレットの機能落ちはダメ

- 開発期間
    - 4か月


# タブレット/スマホ対応するうえで、検討したことと結論
### 対応するOS、ブラウザについて
まずはじめに決めたことが、対応するOSとブラウザをどうするのかです。
テストするための実機も必要になることから、会社での稟議～調達のタイムラグも見て、早めに決めた。

いろいろ検討した結果、2020年1月現在、下記が対応するうえで決めたサポート対象

| 端末       | OS       |バージョン|ブラウザ |
|:-----------------|:-----------------|:------------------|:------------------|
| スマホ             | iOS             |iOS12,13|Safari,Chrome |
|              | Android             |Android8,9|Chrome |
| タブレット             | iOS             |iOS12,iPadOS13|Safari,Chrome |
|| Android             |Android8,9|Chrome |

**決定するうえで決め手となったポイント（優先順）**
1. 会社のポリシー上、最新から3バージョン前までサポート
2. そもそも販売され、シェアがあるか
3. ERPシステムのため法人として使用されているか

**1について**

これは会社に属している以上守るべきポリシーなので、その前提は守りました。
しかし、これを守ると、Android8~10,iOS11~13が必要になり、すべてテストすると、
`(iOSの3バージョン * 2ブラウザ) + (Androidの3バージョン * 1ブラウザ) = 9パータン` と、
テストだけでもかなりの工数が必要になることが分かったため、不要なものを除いてテストを削減するために2以降のシェアの調査を行いました。

**2について**

- iOS11はすべての端末が12にバージョンアップでき、OSのシェアもほとんどないことから、除外
- Android10に関しては、最新バージョンが出たばかりであり、対応する端末もほとんどないことから、除外

**3について**

一般的なシェアに比べて比べて、あまり公表されてないこともあり難航しましたが、
au,docomo,softbankの法人向けの販売ページから、販売されている製品一覧、導入の紹介ページを確認して、ある程度のシェアを確認しました。
それとは別にユーザー企業に、どのような端末を使用しているのかのヒアリングを行い、
Android10とiOS11を除いたもので問題ないと判断し、
`(iOSの2バージョン * 2ブラウザ) + (Androidの2バージョン * 1ブラウザ) = 6パータン`
の最低限のテストで対応すると決定しました。

※Android10に関しては、ゆくゆくシェアが伸びて端末が増えたタイミングでテストを実施することに。


### デザインをどうするのか
今回対応するサービスは、幸いにもERPシステム独特の古いデザインではなく、
[マテリアルデザイン](https://material.io/)での実装がされていたため、
そのデザインを踏襲し、スマホ・タブレット対応することに決定。


### スマホ、タブレットにどう対応させるのか

そもそもタブレット対応や、スマホ対応させるためのノウハウがほとんど社内になかったため、
（先輩にも教えてもらいながら）一から調べ、下記の案が出てきました。


|No.|案|メリット|デメリット|
|:--:|:--|:--|:--|
|1|新たに画面を一から作り、URLから分ける|・一から実装できるため、スマホに最適な画面で作り直せる<br><br>・PC側で機能改善が入った場合にスマホ側は影響を受けない。|・実装コストが大|
|2|UserAgentで判定させ、同一URLだが表示するHTML/CSSを分ける|・実装コストは中<br><br>・余分なDOMをクライアント側で読み込まないので、速度が速くなることを見込める|・HTML/CSSから作る必要がある。|
|3|RWD対応させ、CSSのメディアクエリで画面サイズに応じて表示を変える|・実装コストは低|・PCでの修正が、スマホ/タブレットに意図せず影響を与える可能性がある。|

上記の案の中から

**スマホ対応** に関しては、
1については、明らかに工数が足りず、
スマホに関しては、使用想定される機能が限られてくることもあり、
余分なDOMを読み込まないや、速度が速くなることを見込み、**2**の案を採用しました。

**タブレット対応** に関しては、
当初は、スマホと同様に2の案で考えていましたが、iPadOS13をSafariをしようすると、
UserAgentでiPadであることを判定できなくなることが判明・・・

参考:[iOS13とiPadOSに備える（フロントエンド）](https://qiita.com/zprodev/items/7e133e801e88ae966dc5#ipados%E3%81%AF%E3%83%87%E3%83%95%E3%82%A9%E3%83%AB%E3%83%88%E3%81%AEuseragent%E3%81%8Cmacos%E3%81%A8%E5%90%8C%E3%81%98%E3%81%AB%E3%81%AA%E3%82%8B)


確かに、私物のiPadPro(iPadOS13)で確認すると、UserAgent上からiPadの記載が無い・・・
<img width="700" alt="iPadOS13.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/626180/e75da674-e008-02c5-894d-2ceb2e47e217.png">

上記の事があり、他にもどうにか方法が無いものかと調べましたが、
他にも皆さん調べつくしているようで、UserAgentでの分岐は諦め、
PCから機能落ちもせず、CSSのメディアクエリだけで対応できる **3** のレスポンシブデザイン対応で実施することに。
（無理やりJSで判定させ、その情報で分岐させることも考えたが、シンプルに画面サイズだけで対応させたほうがコストが安く、今後の実装メリットが高いと判断した。）

# 実装方針

**スマホはUserAgentによりHTML,CSSを切り替える**

Java側でUserAgentの判定をかませ、iPhone,Androidのスマホであれば、
スマホ対応した、html/CSSをControllerで返すようにした。

**タブレットはPCと同一のHTMLを使用し、現状のCSSにレスポンシブ対応したCSSを追加で読み込ませる**

追加で読み込ませたCSSの中に、画面サイズに応じて、スタイルを記載した。

```css
@media screen and (max-width: 1279px) and (min-width: 960px) {
    /*タブレット画面が横向きの時*/
}

@media screen and (max-width: 959px) {
    /*タブレット画面が縦向きの時*/
}
```
参考：[【新定番】レスポンシブデザインのブレイクポイントの正解はこれだった[2019最新版]](https://hashimotosan.hatenablog.jp/entry/2019/05/28/164834)

# 実装で当たった問題点と、どう解決したか

方針が決まったので、各画面を実装していくのみになりました。
実装途中で、いろいろな問題にぶち当たりました。その一例と、解決した方法を記載します。

## 躓いた点①：PCのサイズを基本に作られているため、文字が大きく見える。

PCの画面を前提に作られているため、font-sizeが基本14pxとなっていた。
そのため、下記の3つのサイズに統一し、大きすぎる、小さすぎるをなくした。

基本は `12px`
**強調** は `14px`
*補足* は `10px`

## 躓いた点②：マウス操作前提に作られているため、操作しずらい

マウス操作を前提に作られた画面のため、複数の問題点を抱えていた。

- はみ出る文字をマウスホバーで出現するツールチップで表現していたため、タッチ操作だとうまく動かない（表現）できない。

```css
.hoge {
    overflow: hidden;
    white-space: no-wrap; 
    text-overflow: ellipsis;
}
```
を使うのではなく、下を使い、折り返してすべて表示する。

```css
.hoge {
    overflow: visible;
    white-space: normal; 
    text-overflow: clip;
}
```

- アイコンのみで表現していたボタンが、何のボタンかわからない。

PCでも起こりうるUI的な問題だが、PCではボタンにホバーした際にツールチップでボタンの名前を説明していた。
そのため、あまり問題にはならない状態だったが、タッチ操作だとツールチップが出せないためボタンの判別がつきにくい。
結局これの最適な解決策は見つかっていない・・・

- ボタンが小さいため、指でのタッチで押せないときがある。

ボタンのサイズが比較的小さく、そのままタッチ画面に表示して操作すると、
隣のボタンを押してしまうなど、操作性が悪い状態だった。

```css
/*修正前
*marginが多用されていた
*/
.hoge {
    margin: 8px;
}
```

```css
/*修正後
*paddingに変更して、さらに倍のサイズに変更
*/
.hoge {
   padding: 16px
}
```

## 躓いた点③：iOS12で滑らかにスクロールできない。
iOS13,iPadOS13の場合には問題ないが、
iOS12の場合に、スクロールがカクカクして、操作性が非常に悪い状態になっていた。

```css
.hoge {
    overflow: scroll;
    /*下記のスタイルをつけることで、慣性スクロール（滑らかなスクロール）となる。*/
    -webkit-overflow-scrolling: touch;
}
```


## 躓いた点④：PDFの埋め込みがうまく表示されない
`embed` を使用してページの一部にPdfファイルを埋め込むと、
iOSではPDFファイルの1ページのみが表示されて、残りのページを見ることが出来ない事象が起きた。
（Androidでは表示ができず、ページ真ん中にダウンロードボタンが表示される。）

```html
<!-- うまく表示されない -->
<div id="pdf-preview-body">
    <embed src="/documents/hoge.pdf">
</div>
```

下記を参考に、PDF.jsのライブラリを使用すれば、埋め込み形式のPDFをプレビューすることが出来る
参考：[PDF.jsを設置する](https://qiita.com/nissuk/items/01d0490e19dff6e19a03)

```html
<!-- これでPDFファイルの埋め込みプレビューできる -->
<div id="pdf-preview-body">
    <iframe src = "/folder/viewer.html？file = /documents/hoge.pdf" id="pdfjs"></iframe>
</div>
```

PDF.jsのダウンロードボタンを消す必要があるのであれば下記を使用する。
iframeを使用しているため、外で使っているCSSに書いても動作せず、ライブラリ内のCSSに直接記載すれば消すことが出来たが、
ライブラリ内直接記載するのは気持ち悪いため、JSで無理くり非表示にした。

```javascript
$('#pdfjs').on("load",function() {
    // PDF.JS側のダウンロードを非表示にする。
    $(this).contents().find('#download,#secondaryDownload').hide();
});
```

## 躓いた点⑤：ソフトウェアキーボードが消えてくれない
入力完了した際や、検索実行の際に、ソフトウェアキーボードが消えてくれないことが多々あった。

```javascript
//ボタンを押したタイミングなどで下記を実行さるようにすればソフトウェアキーボードが非表示となる。
$('.taget').blur();
```

## 躓いた点⑥：BootstrapのDropdownが動作しない

マウスだと動作するが、タッチ操作だと、動作しなかったものがあった。
その時は、 `a` タグに `href="#target"` を追加すれば動作するようになった

```html
<div class="dropdown">
    <a class="hogehoge" data-toggle="dropdown" href="#target">ドロップダウン</a>
    <ul>
        <li>ドロップダウンメニュー</li>
    </ul>
</div>
```

参考：[iOSのSafariでdata-toggleが動かない場合](https://qiita.com/pompopo/items/3f8b95464987f8206d34)

## 躓いた点⑦：ブラウザのアドレスバーが消えてくれない
通常のよく使用するサイトだと、下にスクロールすると、アドレスバーや下のツールバーが縮小されて、
ウェブサイトが最大化されて表示されるが、今回実装している画面でそれができなかった。

```html
<body>
    <div id="header">
        <!-- ヘッダー部分 -->
    </div>
    <div id="contents">
        <!-- コンテンツ部分 -->
    </div>
</body>
```

```css
/*原因となるCSS*/
#header {
    height: 40px;
    position: fixed;
}
#contents {
    /*コンテンツ要素に対してだけスクロールしていた*/
    height: calc(100% - 40px);
    overflow: auto;
}
```

```css
/*下記のように画面全体の要素に対して、スクロールをつけることで、アドレスバーを縮小できるようにできる。*/
body {
    overflow: auto;  
}

#header {
    height: 40px;
    position: relative;
}
```
この修正は、影響が大きすぎるので、今回では諦めたが・・・

# 教訓

- 最初はPC*Chromeのエミュレート機能を使用して開発をしていたが、実機のJSなどの動作差異などがネックになった。（特にiOS*Safariの組み合わせ）<br>**→早めに実機で検証をしたほうが良い。**

- PCに比べて、スマホやタブレットは少しの動作違和感がストレスを感じやすい<br>**→コンシューマーアプリなどで快適な動作に慣れている可能性があるので、少しでも違和感があれば、こだわったほうが良い。**