スマホやタブレットではiframeが効かない現象・・・
※正確にはiframeの高さの指定が利かずに内部コンテンツの中身がすべて出てしまう。

この現象は知っていましたが、いざ実際に遭遇するとけっこう厄介な代物だと気づかされたのでかなり力技ですが対策スクリプトを書きました。
対応策①CSSで疑似iframeに装飾
こちらはよく他のサイトでも解説されていますが、同じファイル内にコンテンツを記述しCSSでiframeの様に装飾をする方法があります。
HTMLの記述
<div class="counterfeit" style="overflow:auto;">
<h3>疑似iframeコンテンツ</h3>
<h4>overflow:auto</h4>
<p>コンテンツテキスト</p>
<p>コンテンツテキスト</p>
~
<p>コンテンツテキスト</p>
<p>コンテンツテキスト</p>
</div>
<div class="counterfeit" style="overflow:hidden;">
<h3>疑似iframeコンテンツ</h3>
<h4>overflow:hidden</h4>
<p>コンテンツテキスト</p>
<p>コンテンツテキスト</p>
~
<p>コンテンツテキスト</p>
<p>コンテンツテキスト</p>
</div>
CSSの記述
div.counterfeit {
border: #bcbcc2 1px solid;
margin:20px 10px;
width: 200px;
height: 250px;
float: left;
}
デモページ
上記を記述したデモページが
コチラ
結果的に直接記述している
overflowが
autoか
hiddenかの違いです。
対応策②ハック処理(iframeスクロール値は任意指定)
iframeの内部ファイルのコンテンツ自体がそこまでサイト自体の設計にそこまで入り組んでいない仕様だった場合は上項で対応できますが、iframeのファイルコンテンツ量が膨大だったりなどで実装が不可欠な場合を考慮し、現時点で実装されているiframeのHTMLはイジらずに対応してみました。
HTMLの記述
<h4>スクリプト非対応</h4>
<iframe src="140122_iframe.html" width="200"></iframe>
<h4>スクリプト対応</h4>
<iframe src="140122_iframe.html" width="200"></iframe>
比較のために2つ記述していますが1つで良いです。
CSSの記述
iframe {
border: #bcbcc2 1px solid;
float:left;
margin-right: 30px;
}
.frameBox {
width: 200px;
height:250px;
float:left;
border: #bcbcc2 1px solid;
position:relative;
overflow: auto;
}
.frameBox iframe {
width: 200px;
height: 250px;
position:absolute;
z-index:1;
border:none;
}
.frameBox .cover {
width: 200px;
height: 100%;
display:block;
position:absolute;
z-index:2;
opacity:0;
border:#333 solid 1px;
}
JavaScriptの記述
$("document").ready(function(){
$("iframe").eq(1).wrap('<div class="frameBox"></div>'); //解説①
$("iframe").after('<div class="cover"></div>'); //解説②
$(function(){
$(".cover").bind({
'touchstart' : function(e){ //解説③
$(".frameBox .cover").css({'height': '500px'}); //解説④
}
})
});
});
デモページ
上記を記述したデモページが
コチラ
左側がスクリプトをかけていないiframe。右側が上記のスクリプト処理でスクロールできる様になっているiframe。
ifream内ドキュメントの高さは約1000pxありますが、スクロール値を500pxに指定しているので半分までスクロールできる様になりました。
スクリプトの解説
- ①iframeの外側に動的要素class名「frameBox」を作成
iframeの外側に②で生成される要素のCSSでpositionプロパティの相対要素として作成します。デモではiframeは2つ記述しているのでeqメソッドで「2番目のiframe」として指定していますが、idやclassなどでも指定可能です。
- ②iframeの後に動的要素class名「cover」を作成
frameBox要素のCSSのpositionプロパティの絶対位置としてiframeの後にcover要素を作成します。こちらをcssでiframeと同じ横幅に指定します。iframeとcover要素のそれぞれz-indexプロパティで優先順位を指定する事でcover要素がiframeの上レイヤーになる様に指定しています。
- ③cover要素にタッチイベント処理を追記
②で生成されたcover要素にtouchstart関数を使ってスマホ・タブレットでiframeをタッチ(正確にはiframeの真上のレイヤーとして置かれているcover要素)した時にタッチイベントを処理させます。
- ④iframeをタッチした際にcover要素に指定した高さ分の見えない高さが指定される
③のタッチイベント発火時にiframe内の任意で指定した値分の高さがcover要素に加わるのでiframeにスクロール領域が生まれる
対応策③ハック処理(iframeスクロール値は自動取得)
上項の対応策では自分の好みでiframeのスクロール値を指定できますが、iframe内ドキュメントのコンテンツが増えるたびにスクリプトのスクロール値を増やさなければならないのでiframe内のドキュメントの高さを自動指定できるようにした追加記述。
JavaScriptの記述
$(function(){
$('iframe').load(function(){ //解説⑤
if (typeof $(this).attr('height') == 'undefined') { //解説⑥
h = this.contentWindow.document.documentElement.scrollHeight+10; //解説⑦
$(".frameBox .cover").css({'height': h + 'px'}); //解説⑧
}
});
});
スクリプトの解説
- ⑤iframeページに読み込まれた後に処理開始
iframe内ドキュメントの高さを取得するにはまずiframeが読み込まれる前にスクリプトが発動しない様にiframeがロードされてドキュメントの中身が完全にブラウザに反映されてから処理を開始します。
- ⑥iframeの高さを判定
読み込まれたiframeの高さをtypeof関数でオブジェクトの判定をしてその結果が「undefined」=「定義されていない」と一致するかの条件判定を行う。
- ⑦iframeドキュメントの高さを変数に代入
⑥の判定をクリアしたら変数hにiframe内のドキュメントの高さとスクロールバー分の10pxを追加した値を代入する。
- ⑧変数h分の値をcover要素の高さに指定
⑦でiframeの高さが代入された値(デモでは1017px)をcover要素の高さとして指定
デモページ
上記を記述したデモページが
コチラ
これでスクリプト非対応のiframeと同じコンテンツ高さのスクロールが出来るようになりコンテンツの最後まで見れるハズです。
まとめ
この対応策で既存で動いているHTMLのiframeや隣接した要素のレイアウトにも干渉しないのでスマホ・タブレットでもiframeのコンテンツがPC同様(?)に見えるハズ!!DOYA(`・ω´・)+ !!!
iPhoneはスクリプトが正常に動作する様ですが、Androidではコンテンツが2重になる事がある様で、再読み込みをすれば直ります。
ぐぬぬ・・・Androidめ・・・。