裏アドだらけの人生

読んでおもしろい内容はほとんどない個人的な備忘録です

FancyboxのインラインフレームをiOSでスクロール

2012-11-07 18:31:00 | jQuery
Lightbox系のモーダルウィンドウの中でも見た目がとても美しいFancybox
その上痒いところに手が届くオプション満載で、ほとんど文句のつけようがないんだけど、近年スマホやタブレット端末が勢力を拡大していく中で、インラインフレームで読み込んだページをタッチパネルではスクロールできないのが悩みの種でした。
非推奨だからって言われればそれまでだし、Androidは手に負えなかったりするんで使わないのが一番いいんだろうけど、そうもいかない案件もあるんで今回重い腰を上げてとりあえずiOSだけは無理矢理スクロール(フリック)できるようにしてみました。

単なるインラインフレーム表示で使う際に書いてた設定が下記。
$("a.preview").fancybox({
    'width': 800,
    'height': 600,
    'type': 'iframe'
});
previewってクラスのついたaの対象ページを幅800px、高さ600pxで表示させてくださいって感じ。
この状態でaをクリックすると、Fancyboxは「#fancybox-inner」という高さ600pxの箱(div)の中に「#fancybox-frame」というiframeを作って対象ページを見せてくれます。
で、PCだと高さ600pxを超えるコンテンツは自動的にスクロールバーが表示されるわけですが、スマホやタブレットだとスクロールバーは表示されず、フリックもできないので、600pxより下に書いてあることは全く読めないわけです。
なんとかならないものかとソースを見てみたら、幸いFancybox側でiframeをdivで囲んでくれてるのに気づき、これならコンテンツ部分はフリックできなくても、うまくやればフリックするエリアくらいは作れるかなと思いました。

とりあえずデフォルトだと「#fancybox-inner」のoverflowがhiddenになってるので、これをautoに変えたい。
やっかいなことになるのかなあと思ってたんだけど、蓋を開けてみたら上記設定のオプションに
'scrolling': 'yes'
を追加するだけであっけなくできました。
あとは「#fancybox-frame」の幅を800pxより若干小さくして、フリックするエリアを作ってやる寸法です。
以下おそるおそる書いたソース。
var agent = navigator.userAgent;
if (agent.search(/iPhone/) != -1 || agent.search(/iPad/) != -1 || agent.search(/iPod/) != -1) {
    var isTouch = true;
}
var fbInner = $('#fancybox-inner');

$("a.preview").fancybox({
    'width': 800,
    'height': 600,
    'type': 'iframe',
    'scrolling': 'yes',
    'onComplete': function() {
        if (isTouch == true) {
            $('#fancybox-frame').load(function() {
                var fbHeight = fbInner.height();
                var ifHeight = $(this).contents().find('body').height();
                if (ifHeight > fbHeight) {
                    $(this).css('width', '760px');
                    fbInner.css('background', 'url(xxx.jpg) right center no-repeat');
                } else {
                    $(this).css('width', '100%');
                    fbInner.css('background', 'none');
                }
            });
        }
    },
    'onCleanup': function() {
        fbInner.css('background', 'none');
    }
});
最初のほうに出てくる「isTouch」はiOSを判別するために設定してます。
Fancyboxのオプションで
'scrolling': 'yes'
を追加した後の「onComplete」以降が、Fancyboxを開いた後の処理になります。
とりあえず条件分岐でPCかiOSかを判別して、iOSなら処理を実行します。
インラインフレームの幅を760pxに縮小してるのが
$(this).css('width', '760px');
で、それによってできた40px分の余白に「ここをスクロールしてね」って感じの画像をあてはめてるのが
fbInner.css('background', 'url(xxx.jpg) right center no-repeat');
です。
今回作った画像はコレ
あてはめたイメージはこんな感じ↓です。



これだけでもよかったんだけど、どうせなんでスクロールする必要がないコンテンツを読み込んだ場合は何も処理をしないようにしてみました。
var fbHeight = fbInner.height();
はインラインフレームを囲む箱「#fancybox-inner」の高さ。
var ifHeight = $(this).contents().find('body').height();
はインラインフレーム「#fancybox-frame」で読み込むコンテンツの高さ。
if (ifHeight > fbHeight) { ... }
で箱よりコンテンツの高さが大きかった時だけ処理するように分岐しています。

あと最後のほうの「onCleanup」オプションはFancyboxを閉じた時に実行される内容です。
fbInner.css('background', 'none');
ってやらないと同一ページ内の他のFancybox(iframeじゃないやつ)を実行した時に画像が残っちゃうんで。
「onClose」ってオプションもあったけど、これだと続けざまにFancyboxを開いた時にうまく処理してくれませんでした。

以上けっこう無理矢理だし、iPhoneなんかだと画面が小さくてフリック自体しにくいんで、今後はどうしてもって時だけ使おうと思ってます。

どんな感じか見てみたい人は下記のページをiPadとかで開いて、右側のほうにある「総括」とか「遺書」とかをタップしてみてください。
PCでは通常と何ら変わりませんのでご注意を。

実装ページ → bochi