2014

2

1

スマホ・タブレット端末でiframeが伸びてスクロール効かない対応してやんよ!!!

スポンサードリンク


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

この現象は知っていましたが、いざ実際に遭遇するとけっこう厄介な代物だと気づかされたのでかなり力技ですが対策スクリプトを書きました。

対応策①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;
}

デモページ

上記を記述したデモページがコチラ

結果的に直接記述しているoverflowautohiddenかの違いです。

対応策②ハック処理(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め・・・。

トップへ