HTMLとCSSでUITableViewっぽい見た目にする


# はじめに

別にハイブリッドアプリってほどじゃないんだけど、アプリの一部を簡単なWebページにしてWebViewで表示したいことってありますよね？そんなときにあたかも UITableView で表示しているかのように見せかける方法です。

動作確認は WKWebView を使ったアプリで、 iPhone 6s plus (iOS 9.0.2), iPhone 4S (iOS 9.2.1) の２機種で行いました。

# 見た目

![IMG_0162.jpg](https://qiita-image-store.s3.amazonaws.com/0/53805/9d452ac4-5974-7579-9dbd-5ec87a049552.jpeg)

# HTML

viewport の設定で、等倍かつユーザーのピンチ操作による拡大縮小を無効にしています。タイトル行だけ class に "title" を指定します。これで UITableView のセクションを再現できます。

```html
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,minimum-scale=1.0,user-scalable=no">
  <link rel="stylesheet" href="style.css">
  <title>Menu</title>
</head>
<body>
  <ul>
    <li class="title">Menu</li>
    <li><a href="tos.html">利用規約</a></li>
    <li><a href="usage.html">使い方</a></li>
    <li><a href="contact.html">お問い合わせ</a></li>
    <li><a href="license.html">ライセンス表記</a></li>
  </ul>
</body>
</html>
```

# CSS

CSS で iOS 9 での UITableView と同じ見た目になるようにしてみました。

```css
body {
  font-size: 16px;
  font-family: sans-serif;
  margin: 0;
  padding: 0;
  background-color: #F7F7F7;
  color: black;
  -webkit-touch-callout:none;
  -webkit-user-select:none;
  -webkit-text-size-adjust: 100%
}

ul {
  background-color: white;
  list-style-type:none;
  margin: 0;
  padding: 0;
}

li {
  padding: 0;
}

li:not(.title)+li:not(.title)::before {
  content: '';
  display: list-item;
  margin-left: 10px;
  border-top: 1px solid #C8C7CC;
}
@media(-webkit-min-device-pixel-ratio:2) {
  li:not(.title)+li:not(.title)::before {
    border-top: 0.99px solid #C8C7CC;
  }
}
@media(-webkit-min-device-pixel-ratio:3) {
  li:not(.title)+li:not(.title)::before {
    border-top: 0.49px solid #C8C7CC;
  }
}

li.title {
  font-family: sans-serif;
  font-weight: bold;
  padding-top: 2px;
  padding-bottom: 2px;
  padding-left: 16px;
  background-color: #F7F7F7;
}

li > * {
  padding: 10px 0 10px 8px;
}

a {
  display: block;
  text-decoration: none;
}
a:link {
  color: black;
}
a:visited {
  color: black;
}
a:active {
  color: black;
  background-color: #C8C7CC;
}
```

# CSSの解説

##  -webkit-touch-callout:none;

ユーザーがリンクを長押ししても何も起こらないようにしています。

##  -webkit-user-select:none;

ユーザーがテキストを長押ししてもテキスト選択できないようにしています。

##  -webkit-text-size-adjust: 100%

これを指定しておかないと、WebKitが勝手に文字サイズを最適化しようとします。font-size に指定した絶対pxで表示して欲しいので指定しています。

## リスト項目の区切り線

"li:not(.title)+li:not(.title)" は class が title でない li 要素で、かつ直前も title でない li 要素を指定しています。それの上にボーダー線を引きたいわけです。

素直にやるならこうです。

```css
li:not(.title)+li:not(.title) {
  border-top: 1px solid #C8C7CC;
}
```

でも UITableView の区切り線って、微妙に左側に隙間があるんですよね。それを実現するために、before を使って要素を上に足します。

```css
li:not(.title)+li:not(.title)::before {
  content: '';
  display: list-item;
  margin-left: 10px;
  border-top: 1px solid #C8C7CC;
}
```

で、その要素に左マージンを設定して隙間を作っています。

ボーダーの太さを Retina のときにキッカリ 1 dot にしたいんです。英語で言うところの hairline にしたい。以下の部分でそれぞれ２倍、３倍の Retina の場合の線の太さを指定しています。２倍の場合は 0.5 を指定しても大丈夫だったんですが、３倍の方は 0.33, 0.34 では線が表示されませんでした。

```css
@media(-webkit-min-device-pixel-ratio:2) {
  li:not(.title)+li:not(.title)::before {
    border-top: 0.99px solid #C8C7CC;
  }
}
@media(-webkit-min-device-pixel-ratio:3) {
  li:not(.title)+li:not(.title)::before {
    border-top: 0.49px solid #C8C7CC;
  }
}
```

## リンクをリンクっぽくしない

色をつけないようにしたり、下線を引かないようにしたり、クリックしたときに li の中身全部の色が変化するようにしています。

```css
a {
  display: block;
  text-decoration: none;
}
a:link {
  color: black;
}
a:visited {
  color: black;
}
a:active {
  color: black;
  background-color: #C8C7CC;
}
```
UITableView に似せるなら a リンクの上の li 全体に色が付くべきです。でもCSS は子要素に条件指定して親要素に何か設定するって方法がなさそうなので、li 要素の padding をなくして、代わりにその下の要素に padding を指定しています。

```css
li > * {
  padding: 10px 0 10px 8px;
}
```

これで a リンクにも padding が設定されます。でも a リンク使わない li 項目は必ず中に padding を適用する子タグ(divなど)が必要になります。

## 選択した項目に色をつけたままにする

UITableView はタップした項目に色がついた（選択状態の）ままになるみたいです。これを再現したかったら、以下を指定します。

```css
li:hover {
  background-color: #C8C7CC;
}
```

自分は鬱陶しく感じたのでやめましたが・・・。

# pre

利用規約とか使ってるライブラリのライセンス表記とかは pre で改行もテキストままで表示したくなりますよね？

```html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,minimum-scale=1.0,user-scalable=no">
    <link rel="stylesheet" href="style.css">
    <title>ライセンス表記</title>
</head>
<body>
    <ul>
        <li class="title">RxSwift</li>
        <li><pre>
The MIT License Copyright © 2015 Krunoslav Zaher All rights reserved.

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
        </pre></li>

        <li class="title">Swinject</li>
        <li><pre>
The MIT License (MIT)

Copyright (c) 2015 Swinject Contributors

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
        </pre></li>
```

CSS には以下を追記します。

```css
pre {
  white-space: pre-wrap;
  font-size: 12px;
}
```

# 最後に

今日で突貫で作ったので、まだ足りないところとか機種やiOSバージョンでうまく表示できないとかあるかもしれません。そういった報告歓迎です。