サナギわさわさ.json

サナギさんとキルミーベイベーとプログラミングが好きです

Friendly iFrameで広告コードを遅延読み込みする

沙村広明先生の漫画が好きなんですが、その中でも特に「ハルシオンランチ」が好きです。
ストーリーが良く出来ていて簡単に言うと女の子がゲロを吐いて世界が救われる話なんですが、その他にも読むとゲロを吐くことに対する躊躇いが無くなって、飲み過ぎた次の日でも復帰が早くなるというメリットもあります。

WEBサイトにアクセスした際に、広告が表示されてから本文が表示されるとげんなりします。というわけで広告コードを遅延読み込みさせようと思います。
bodyタグの終了直前に広告のスクリプトタグを配置するのが手軽で楽なのですが、その方法では結局window.onloadの発火が遅れてしまうので、Javascriptを多用するサイトだとあまり意味がありません。なので、今回はFriendly iFrameを使って遅延読み込みさせます。

Friendly iFrameとは、親と同一ドメインのiframeを動的に作成し、その中にサードパーティスクリプトを読み込む方法です。iframeなのでレンダリングを妨げませんし、Same Origin Policyに縛られないので親ドキュメントへのアクセスも行えるという点などが優れています。
※参照:Friendly iFrame とサードパーティスクリプトのロード - Please Sleep

Friendly iFrameの実装方法は単純で、

  • src 属性を about:self にした iframe 要素を動的に生成
  • サードパーティの url を指した script 要素を作成し、iframe 内のドキュメントに設置
  • inDapIF = true というフラグを iframe 内に作る

というだけです。実際の実装置いておきます。

var parentDom = document.getElementById('parent');
var iframe = document.createElement('iframe');
iframe.width = 300;
iframe.height = 250;
iframe.frameBorder = "0";
iframe.scrolling = "no";
iframe.marginWidth = 0;
iframe.marginHeight = 0;
iframe.src = "about:self";
parentDom.appendChild(iframe);
var doc = iframe.contentWindow.document;
doc.open();
var d = "";
d += '<html><head></head>';
d += '<body>';
d += '<script src="'+src+'"></script>';
d += '<script>inDapIF = true;</script>';
d += '</body></html>';
doc.write(d);
doc.close();

こんな感じで実装したのですが、何故か古いIEで広告が表示されないという問題が発生しました。
あと、

<script type="text/javascript">
var ad_vars = {
  ver    : xxx,
  app_id : ddlkajsu
};
</script>
<script type="text/javascript" src="http://test.com/ad.js"></script>

みたいなscriptタグの前に変数をセットする必要があるタイプに対応するのが少し面倒だったので、 結局src属性を自ドメインホスティングしている小さなhtmlファイルに向ける方式に変更しました。 変更後のコードはこうなります。

fif.html
<html>
<head>
</head>
<body>
<script type="text/javascript">
var ad_vars = {
  ver    : xxx,
  app_id : ddlkajsu
};
</script>
<script type="text/javascript" src="http://test.com/ad.js"></script>
</body>
</html>
js側ではiframeのsrcの向き先を以下に変更し、iframe.contentWindow.documentへの操作を行わない
iframe.src = "fif.html";

以上の実装でIEでも表示されました。小さいhtmlファイルとは言え動的生成に比べると若干アクセスに時間がかかるとは思うので、必要ない場合は動的生成の方が良いとは思います。

実装して自分で見てみると、本文が全て表示されてから広告タグが出てくるため非常に快適で、これがWEBサイトのあるべき姿だからもっと普及すればいいなと満足していたのですが、しばらくしてから広告収益を確認してみたら半分ぐらいになってて我に帰りました。
やはり広告クリックの半分ぐらいは読み込み時の押し間違いによるものという事ですね。皆さんもこれを適用するときは気をつけてください。

「テキストボックスのフォーカス時に全選択状態にする」をクロスブラウザ対応

フロント開発の楽しさを定量化するとキルミーベイベー第5話ぐらいはありますが、クロスブラウザ対応となると途端にキルミーベイベー第1話ぐらいの楽しさになってしまうというのは皆さんもご存知の通りです。

「テキストボックスのフォーカス時に全選択状態にする」という機能は難易度的に大したものではなく、30分ぐらいでできるよね? みたいなノリで振られると思うのですが、何も考えずに

<input id="test"></input>
var input = document.getElementId("test");
input.onfocus = focusInput;

function focusInput(e) {
    if (e) {
        var target = e.target;
        target.select();
    }
}

で実装したらAndroidとかMobile Safariとかで動かなくてえらい目にあいました。
そろそろ世の中に存在するブラウザの総数を規制してもらわないとクロスブラウザテストはやってられなくなりますし、
IE8以下はレッドデータブックに載せずに早く絶滅させた方が良いのですが、とりあえず以下のコードで対応しました。

var input = document.getElementId("test");
input.onfocus = focusInput;

function focusInput(e) {
    if (e) {
        (function(e){
        setTimeout( function() {setFocus(e);});
    })(e);
    }
}

function setFocus(e) {
    if (e) {
        var targetTag = e.target;
        targetTag.focus();
        //とりあえず全選択、選択範囲指定したいときはbgnとendを適宜指定
        var num = targetTag.value.length;
        var bgn = 0;
        var end = num;
        if(typeof(targetTag.selectionStart) != "undefined"){
            targetTag.selectionStart = bgn;
            targetTag.selectionEnd = end;
        } else if(document.selection) {
            var range = targetTag.createTextRange();
            range.collapse();
            range.moveEnd( "character", bgn );
            range.moveStart( "character", end );
            range.select();
        }   
    }
}

FireFox,Chrome,Safari,IE9,IE11,Android標準ブラウザ,Mobile Safari(iOS7)ではとりあえず動きました。 何か問題ありましたら教えてください。