「layzr.js」でiframeの遅延ロード実装 – 激重なウィジェット表示対策

前回投稿した『jsdo.itでアクセスの多かったUIデザインに役立つJavaScriptコード紹介』という記事では、jsdo.itというサービスのウィジェットを15個表示させることにしました。ウィジェットはJavaScriptのdocument.write()が使われていたため、15個も表示させるとページがこれでもかというくらい重くなり、投稿も半ば諦めモードになりかけました。最終的にはdocument.write()が書き出すiframeを取り出し、遅延ロードさせるという方法でなんとか乗り切りました。その辺の話を詳しく書こうと思います。

jsdo.it上のコードをページに埋め込む

jsdo.it内で書いたコードは、ウィジェットとしてブログなど好きなページに埋め込むことができるようになっています。jsdo.itのそれぞれのページに設置してある「ブログに埋め込む」というボタンを押すと、ページに埋め込むためのscriptタグがコピーできるようになっています。

jsdo.it ウィジェットを埋め込む

コピーできるscriptタグは以下のようになっています。

<script type="text/javascript" src="http://jsdo.it/blogparts/f9Cy/js?width=654&height=424&view=readme"></script>

上記のscriptタグをページに貼り付けると以下のようにjsdo.itのコードが表示されるようになっています。

コードを15個埋め込むとさすがに重い…

上記のように簡単にjsdo.itのコードをページ内に埋め込むことができるので、手軽にコードの紹介もできると思ったのが誤りでした…。何を欲張ったのかこのjsdo.itのコードを15個表示させることにしました

記事を書くためにせっせとウィジェットを15個コピーしてはページに埋め込んでいきました。そうして気づいた時にはすでに時遅し、ページが激重になっていました…。プレビューもままならず、途方に暮れることになりました。せっかく記事も書いたし、投稿を辞めるわけにもいかず、いろいろ悩んだ挙句とにかくこの問題を解決させる道を模索することにしました。

ページが激重の原因はdocument.write()

まずscriptタグで読み込んでいるjsファイルがどうなっているか見てみることにしました。以下のscriptタグ内のsrc属性の値の部分(jsファイルのURL)をコピーしてブラウザのアドレスバーに貼り付けました。

http://jsdo.it/blogparts/f9Cy/js?width=654&height=424&view=readme

展開されたjsファイルの中身は以下のようになっていました。

document.write("<div class=\"bpJsdoit\" style=\"text-align:center; width:654px;\"><iframe allowfullscreen=\"allowfullscreen\" scrolling=\"no\" src=\"http://jsdo.it/blogparts/f9Cy?view=readme\" width=\"654\" height=\"424\" style=\"border:1px #CCC solid; width: 654px; margin: 0px;\"></iframe></div>");

おわかりのように、激重の原因はdocument.write()でした。document.write()の問題点と言えば、document.write()による書き出しが終わるまで、それ以降のページのレンダリングを止めてしまうことです。それに拍車をかけるように、ウィジェット内には激重の代表格と言われているFacebookやTwitterのソーシャルボタンが使われていました。15個のウィジェットの表示が終わるまで、ページの読み込みが終わらないという最悪の状態となっていました。

docment.write()は非同期処理ができない

これを解決するために、まず考えたのはscrpt要素にasync属性やdefer属性をつけて非同期でウィジェットを表示させることでした。ただdocment.write()がくせものたる所以はここにあって、docment.write()はasync属性やdefer属性に対応していないということです。

要するに、実行された場所で即座に内容の生成を行うdocment.writeに対して、非同期系の処理を与えるということは無理があるということです。ということでウィジェットの非同期での表示は諦めざるをえませんでした。

ただ調べてみると以下のようにdocument.write()を非同期で実行させるような裏技的な方法は存在するようです。ただ自分はブログの記事に対して実装するのは面倒くさいと思って別の方法を探すことにしました。

iframe要素の遅延ロードを試すことに

ということで次に考えたのは、document.write()で書き出されるHTMLタグの部分を直接ブログの記事内に貼り付けることでした。上記でも触れたように、jsdo.itのscript要素のsrc属性に指定されているJSファイルを開くと以下のようになっています。

document.write("<div class=\"bpJsdoit\" style=\"text-align:center; width:654px;\"><iframe allowfullscreen=\"allowfullscreen\" scrolling=\"no\" src=\"http://jsdo.it/blogparts/f9Cy?view=readme\" width=\"654\" height=\"424\" style=\"border:1px #CCC solid; width: 654px; margin: 0px;\"></iframe></div>");

document.write()内のHTMLタグ部分を抜き出して、整形し直すと以下のようになります。これをそのままページに貼り付けることにしました。

<div class="bpJsdoit">
<iframe allowfullscreen="allowfullscreen" scrolling="no" src="http://jsdo.it/blogparts/f9Cy?view=readme" width="654" height="424" ></iframe>
</div>

ただ、これだけではdocument.write()とやっていることは変わらず、相変わらず激重なままです。そこで考えたのが、iframe要素の遅延ロードです。これしか方法はないかなと思いました。

遅延ロードの実装は、手っ取り早くjQueryプラグインに頼ることにしました。遅延ロードと言ったら、まず真っ先に思いつくのは、定番中の定番となっているlazyloadだと思います。

lazyloadはよく画像の遅延ロードに使われていますね。調べてみるとiframeにも対応しているようでした。ただ以下のブログを見るとiframeの対応はなんだか手間がかかりそうな感じがしたので、これも諦めて違うプラグインを探すことにしました。

iframe要素の遅延ロードの実装にはlayzr.jsが使えそう

そして見つけたのがlayzr.jsというJavaScriptのライブラリです。

軽量で、高速で、モダンで、jQueryなど何にも依存しないJSライブラリとなります。以下のブログ記事を見ると、すごく簡単にiframeの遅延ロードを実装できることがわかりました。

さっそくlayzr.jsを使ってiframeの遅延ロードを実装することにしました。

layzr.jsの実装方法

layzr.jsのダウンロード

まずlayzr.jsを以下のGitHubのページよりダウンロードします(npmbowerにも対応しています)。またはGitHubのページに記載のCDNのURLをコピーします。

layzr.jsの読み込み

ダウンロードしたlayzr.jsをページに読み込みます。

<script src="layzr.js"></script>

iframeのsrc属性をdata-layzr属性に変更

iframeのsrc属性をdata-layzr属性に変更します。

<div class="bpJsdoit">
<iframe allowfullscreen="allowfullscreen" scrolling="no" data-layzr="http://jsdo.it/blogparts/f9Cy?view=readme" width="654" height="424"></iframe>
</div>

新しいインスタンスを生成する

以下のコードを記載し、ページ読み込み後に、Layzrオブジェクトの新しいインスタンスを生成するようにします。

<script>
window.addEventListener('load', function () {
  var layzr = new Layzr();
}, false);
</script>

ローディング画像を設定する

これで遅延ロードされるようになりましたが、ロードされるまで空白が表示された状態となっているので、ローディング画像を設定しておきます。iframeのsrc属性にローディング画像を設定することができます。

<div class="bpJsdoit">
<iframe allowfullscreen="allowfullscreen" scrolling="no" data-layzr="http://jsdo.it/blogparts/f9Cy?view=readme" width="654" height="424" src="https://preloaders.net/preloaders/719/Appearing%20squares.gif"></iframe>
</div>

ローディング画像は以下のサイトのものを使わせてもらいました。

iframe要素のレスポンシブ対応

忘れてはいけないのが、iframeのスマホ対応です。画面サイズに合わせてiframeのサイズをフレキシブルに変更する必要があります。今回はcssを使ってスマホ対応しました。書いたcssのコードは以下のようになります。

<style>
.bpJsdoit iframe {
  border: 1px #ccc solid;
  box-sizing: border-box;
  margin: 0;
  /* iframe要素内でサイズ指定している場合は必要なし */
  width: 654px;
  height: 424px;
}
/* レスポンシブ対応 */
@media screen and (max-width: 654px) {
  .bpJsdoit {
    position: relative;
    width: 100%;
    padding: calc(424 / 654 * 100%) 0 0;
  }
  .bpJsdoit iframe {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
  }
}
</style>

iframeのスマホ対応についての詳細は、当ブログの以下の記事を参考にしてください。

iframe要素の遅延ロードの実装完了

実装後のjsdo.itのウィジェットは以下のように遅延して表示されるようになりました。

layzr.jsは複数のiframeにも対応しています。上記で紹介した方法でインスタンスをひとつ生成するだけで、複数のiframeを遅延ロードさせることができるようになります。複数のiframeに遅延ロードを実装した例は当ブログの前回の記事になりますので、ぜひご確認ください。15個のウィジェットを表示させていますが、それほどもっさり感は感じないと思います。

まとめ

フロントエンドに力を入れている面白法人カヤックのサービスらしからぬ重々なウィジェットにかなり面食らいましたが、なんとか上記のような実装を施し、記事を公開することができました。ひとまずほっとしています。

今回利用したlayzr.js、なかなか使えると思います。今回はiframeの遅延ロード方法を紹介しましたが、もちろん画像にも使えます。オプションもいろいろ用意されているようなので、その辺りも今後詳しく見ていこうと思っています。世の中には激重なウィジェットがたくさん存在していると思います。こういった解決策もあるものだと参考にしてもらえれば幸いです。

コメント一覧

  • 必須

コメント