スマホサイトなどでiframe要素をスクロールさせる方法

スマホサイトなどでiframe要素をスクロールさせる方法です。

## iOS/Androidのiframe動作
両OSのiframe動作を確認したところ、iOS:Safari上では、iframeが正常に動かず、
要素がすべて表示されてしまった。

調べたところ、他にも同じことで困っている人がいるみたく、
解決方法があったので、実際に試してみました。

参考：
> [Scroll IFRAMEs on iOS](http://davidwalsh.name/scroll-iframes-ios)
> [iphoneでiframeをスクロールさせる](http://stoned-circle.net/blog/2173/iphone%E3%81%A7%E3%82%B9%E3%82%AF%E3%83%AD%E3%83%BC%E3%83%AB%E3%81%95%E3%81%9B%E3%82%8B
)

## iframeサンプル

とりあえず、iframeが正常に動かないhtmlと動くhtmlを作成しました。

ソースは[こちら](https://github.com/takuhou/smartdevice-iframe)。
iframe-no-scroll関連は動かないほうです。
iframe-scroll関連は動くほうです。

どこかのWebサーバにあげてスマホで見てください。
githubのキャラクターとgithubの説明（wikipedia参照）を載せたhtmlです。

## 動かないほう

htmlページにiframeを追加する親要素を記述し、
`<div id="iframe-no-scroll" style="width:100%; height:200px;"></div>`
javascript内の処理でiframe要素を作成し、親要素に追加するような動きになってます。

### キャプチャ
![noscroll.png](https://qiita-image-store.s3.amazonaws.com/0/55871/cb4db01a-25ea-19c5-1c1e-53d611807234.png)

## 動くほう
動かない方と同様の作りですが、javascript内で行っているiframe要素の作成処理が異なっていて、iframe要素の1階層上にラッパーのdivをかましています。

```js:iframe-wrapper.html
// iframeラッパー要素作成
var _iframeWrapper = document.createElement('div');
_iframeWrapper.className = 'iframe-wrapper';
_iframeWrapper.style.width = "100%";
_iframeWrapper.style.height = "100%";    

_iframeWrapper.appendChild(_iframe);
```

そして、そのラッパーのdivを親要素に追加するような動きになってます。
`_iframeScroll.appendChild(_iframeWrapper);`

後、ラッパーの動作をcss上で定義しています。

``` iframe-wrapper.css
.iframe-wrapper { 
	-webkit-overflow-scrolling: touch;
	overflow: auto;
};
```

`-webkit-overflow-scrolling: touch`は、慣性スクロールをできるようにする設定ぽいです。慣性スクロールは、スッってやったらページもスってなるイメージですが、合っているか不明です。

参考：
> [スマートフォンでページの一部を慣性スクロールできるようにする-webkit-overflow-scrolling](http://webdev.jp.net/overflow-scrolling/)

`overflow: auto;`は、要素からはみ出た部分の表示の仕方を設定するもので、
`auto`にすると、ブラウザに依存する設定になるみたいです。

参考：
> [overflow･････はみ出た内容の表示方法を指定する](http://www.htmq.com/style/overflow.shtml)

### キャプチャ
![scroll.png](https://qiita-image-store.s3.amazonaws.com/0/55871/5b3f64f9-7860-ab07-f3d8-87efd01f26bf.png)

## 結果
うまくできました。

ただ、Androidだと普通にiframeが動くので、javascirpt内で処理を分けたほうがいいです。

iOS判定処理です。

``` isIos.js
var isIod = function(){
var ua = window.navigator.userAgent.toLowerCase();
if (ua && ua.indexOf('iphone') === -1 && ua.indexOf('ipod') === -1 && ua.indexOf('ipad') === -1) {
return true;
}
return false;
};
```

後、そもそもなんで動かないかは、よくわかりません。
調べる元気があればソースを見てみます。
今後OSのアップデートで対応されるかもしれないですね。

## Tips
この検証をやった際に色々htmlの勉強になったので、Tipsをあげときます。

#### iframeのsrcとsrcdoc
iframeのソースの指定方法には、`src`以外に`srcdoc`というものがあります。
結構便利で、iframeのソースを直接記述することができます。
今回も使ってます。

```js:iframe-srcdoc.html
var desc = "テキスト・・・"
_iframe.src = "data:text/html;charset=utf-8," + desc;
```

もちろん、htmlも記述可能です。
後、ひっそり使っている`data:text/html;`ですが、[データURIスキーム](http://ja.wikipedia.org/wiki/Data_URI_scheme)というもので、
`text/html`以外のmimeタイプを指定すると色々できて便利です。

iframeのソース置く場所がないけど、iframeで表示しないといけないという、
特殊な状況に置かれた場合はこれを使ってみるといいと思います。

#### appendChildの実行順序による表示順番
iOS(iPhone4S,iOS8.1,safari)で、javascript内で作成した要素をappendするときに、appendされる順番が早いほうがz−index的に下に配置されてしまい、別の要素がappendされると、かぶさってしまう現象が発生しました。

確かに自然な動きに見えますが、
AndroidのChromeとデフォルトブラウザ、iOSのChromeは逆の動きをしていました。
しっかり検証していないので、なんともいえませんが、そんなことがありました。

#### androidデフォルトブラウザ(Android 4.4.1, Xperia SOL25)の文字表示
javascript内でaタグの要素を作成し、他の要素をaタグにappnedしたところ、
文字の下に勝手に下線が引かれる現象が発生しました。

原因はよくわかりませんが、`display:inline-block`で直りました。

以上です。