Webサイト高速化のためのWebフォントとソーシャルボタンを遅延読み込みさせるすべらない話

Movable Type Webサイト高速化

いつも読んでくださりありがとうございます、あ、及川です。

SREスタッフが日々の活動内容や学びを更新している「SRE BLOG」ですが、引っ越しました。

Movable Typeを活用しているWeb制作に関わっているとお仕事としてもよくある引っ越しですが、なぜ引っ越したのか、具体的にどんなことをしたのか、などなど、せっかくなのでまとめておきます。

レスポンシブWebデザインの設計の基本

なぜ引っ越したのか?

「なぜ会社としてブログを運営しているのか?」

ブログの定期的な更新を続けることは、情報収集や記事作成の点でもそれなりに労力のいることですし、お金に変わることではありません。ではなぜWeb制作会社なのにブログを更新し続けるのか。

キレイな言葉(笑)を並べると次のようになります

  1. お客様や外部パートナーにSREが何ができるのかを知っていただく
  2. SREを知らない人に見つけてもらう機会を増やす
  3. 一緒に働きたいと思ってもらえる仲間に知ってもらう、みつけてもらう

これらを運営する側の視点の言葉におきかえると次のようになります。

  1. 既存顧客と見込み客、および外部パートナーにSREが何ができるのか認知度を上げてインバウンド数増加
  2. 見込み客のインバウンドを促進するためのSEO強化
  3. 見込み採用応募者への情報発信と興味喚起

1については、引っ越しの理由ではありません。SRE BLOGを見てくださるお客様や外部パートナーにとって読んでタメになる情報を考えて伝えることを、粛々とつづけていくのみです。

3も、まずは外部の採用サイトなどを使ってWebサイトに誘導し、SREに興味を持っていただいて初めてブログをみて社内のスタッフや業務内容の一端に触れていただくことができます。

ということで、2が最大の理由でした。
カンパニーサイトとブログを同一ドメインに集約することで、更新性を上げ、コンテンツを増やし、両方を一貫したオウンドメディアとしてより多くの方にSREを知ってもらうチャンスを増やしたいと考え、引っ越しを決めました。

更新を止めないためにブログを複製、データは後で一括インポート

Webサイトやブログを移行するのに更新は止めたくないのでブログを複製して、改修を始めました。複製後に追加されたコンテンツは一括インポートすることにしました。

元のブログがサブドメインのhttp://blog.sr-engine.com/を使っていましたが、移行先はhttp://www.cherry-pick.jp/blog/なので階層が異なります。画像、cssやjsなども合わせて階層が変わるのでcssやjs、画像のパスの修正を行います。

表示速度の計測とチューニングで、Webフォントやソーシャルボタンを遅延読み込み

ブログを構築したときに表示速度を計測して8.5秒程度かかっていました。ただ、サーバからのレスポンスというよりは、ソーシャルボタンなどが影響していた部分が大きかったため、しょうがない精神で乗り切って(見て見ぬふりをして笑)いましたが、一念発起で改善に着手しました。

課題は見出しの通り次の2点です。

  1. Webフォントの読み込みが終わらないとテキストが表示されない
  2. ソーシャルボタンの読み込みが遅い

「1. Webフォントの読み込みが終わらないとテキストが表示されない」を解決する

そのままですが、Webフォントデータの読み込みが終わらないとブラウザ側でテキストが表示されません。SRE BLOGで使用している日本語Webフォントは8MBを超えるためダウンロードに時間がかかります。スマホで見たときはそれが顕著になってしまうため、解決策としてデータをダウンロードしてからCSSを反映させる遅延読み込みを行うことにしました。

使用したのはGoogleが提供しているWebFont Loaderです。指定したWebFontを読み込むと、htmlタグにclass属性を追加してくれます。また、コールバック関数を設定すればWebフォントを読み込む前、読み込んだ後などに処理を実行することができます。

具体的に次のようにしました。

Webフォントを直接的にfont-familyに指定しない

記事タイトルやカテゴリ名に直接font-familyでWebフォントを指定していましたが、一般的なフォント、たとえばMSゴシックやMS明朝、ヒラギノなどに変更します。

元のHTMLは以下ですが、WebFont LoaderはWebフォントの読み込みが終わった時に次のようなclass属性を追加します。

オリジナルのhtmlタグ
<html itemscope="1" itemtype="http://schema.org/" lang="ja" xml:lang="ja" xmlns:og="http://ogp.me/ns#">

WebFont Loaderによりclass属性が追加されたhtmlタグ
<html itemscope="1" itemtype="http://schema.org/" lang="ja" xml:lang="ja" xmlns:og="http://ogp.me/ns#" class="wf-fudtsukumind-n4-active wf-active">

要は、この追記されるclass名を含んだスタイルを用意しておくと、htmlタグにclass属性が追記されたタイミングでWebフォントが反映されるようにします。具体的な設定は以下を参考にしてください。

CSS

SRE BLOGではF+UD-筑紫明朝 Dというフォントを使っていて、このフォントをcssで次のように定義しています。

@font-face {
 font-family: "fudtsukumind";
 src: url(/blog/assets/fonts/F+UD-TsukuMin-D/F+UD-TsukuMin-D.otf) format('opentype');
}

WebFont Loaderが付与するclass名があるときだけ、スタイルが反映されるようにCSSを用意しておきます。

.wf-fudtsukumind-n4-active article section.body h3,
.wf-fudtsukumind-n4-active article section.body h4 {
  font-family: "fudtsukumind";
}

JavaScript

F+UD-筑紫明朝 DをWebFont Loaderに認識させて、その処理を遅延させるために次の関数をつくって、全ページ共通のcommon.jsで呼び出しを行っています。

// Lazy loading WebFonts
function load_webfonts() {
 setTimeout(function() {
   WebFont.load({
     custom: {
       families: ["fudtsukumind"]
     }
   })
  }, 3000);
}
load_webfonts();

これで、Webフォントの読み込みが終わるまではブラウザ依存のWebフォントで表示され、Webフォントが読み込まれたら反映されるようになりました。
Chromeの開発ツールのNetworkで見るとわかりますが、ページ読み込みのLoad Eventが完了したあとにWebフォントの読み込みが始まっているのがわかります。

ChromeCapture.png

「2. ソーシャルボタンの読み込みが遅い」を解決する

ソーシャルボタンのタグやhtmlをただ埋め込むと、Webブラウザがhtmlを読み込んでリクエストしてから、レスポンスが遅くて表示に時間がかかります。

読み込みが終わらないので、自分のほしい情報の表示が終わったのかどうか分からないので、利用者が次の行動に移ることをためらうことも少なくありません。たとえば、爆速Yahoo!にアクセスすると読み込み表示が早いので即座にほしい情報を探し始めることができます。

外部サービスはどうにもできないのでやっぱり遅延読み込み

とはいえ、ソーシャルボタンによる評価やシェア、ブックマークなどをしてもらい、いろんな人に見てほしいしタメになるものは何度でも読んでほしい!
なので、ボタンは外さずにページ自体の表示速度は早めて、提供している情報はより快適に読めるようにしたい。

ということで、やはり遅延読み込みをすることで、ページ自体の読み込みを早くすることにしました。

JavaScript

具体的には、次のような関数をつくり、サイト共通のソーシャルボタンは全ページ共通のcommon.jsで関数を実行します。

function show_social_btn(parent, page_url, page_title) {
  var btn_fb, btn_twitter, btn_hatena, btn_pocket, btn_google;
  var url,title;
  url = page_url ? page_url : document.URL;
  page_title = page_title ? page_title : 'SRE BLOG';
  btn_fb = '<div class="fb-like" data-font="verdana" data-href="'+url+'" data-layout="button_count" data-send="false" data- show-faces="false" data-width="103"></div>';
  btn_twitter = '<a class="twitter-share-button" data-lang="ja" data-text="' + title + '" data-url="' + url + '" href="https://twitter.com/share" charset="UTF-8">ツイート</a>';
  btn_hatena = '<a class="hatena-bookmark-button" data-hatena-bookmark-layout="standard" data-hatena-bookmark-title="' + title + '" href="http://b.hatena.ne.jp/entry/'+encodeURIComponent(url)+'" title="このエントリーをはてなブックマークに追加">';
  btn_hatena += '<img alt="このエントリーをはてなブックマークに追加" height="20" src="//b.st-hatena.com/images/entry-button/button-only.gif" style="border: none;" width="20" />';
  btn_hatena += '</a>';
  btn_pocket = '<a data-pocket-label="pocket" data-pocket-count="horizontal" class="pocket-btn" data-lang="ja" data-save-url="' + url + '"></a>';
  btn_google = '<g:plusone size="medium" href="' + url + '"></g:plusone>';
  setTimeout(function() {
    // Facebook
    $(parent).append(btn_fb);
    (function(d, s, id) {
    var js, fjs = d.getElementsByTagName(s)[0];
    if (d.getElementById(id)) return;
    js = d.createElement(s); js.id = id;
    js.src = "//connect.facebook.net/ja_JP/all.js#xfbml=1&appId=430179513756656";
    fjs.parentNode.insertBefore(js, fjs);
    }(document, 'script', 'facebook-jssdk'));
 
    // Twitter
    $(parent).append(btn_twitter);
    
    // Hatena
    $(parent).append(btn_hatena);
    !function(d){var j=d.createElement('script');j.src="http://b.st-hatena.com/js/bookmark_button.js";j.charset="utf-8";j.async="async";d.body.appendChild(j);}(document);</p>

     // Pocket
     $(parent).append(btn_pocket);

     // Google+
     $(parent).append(btn_google);
     window.___gcfg = {lang: 'ja'};
     (function() {
     var po = document.createElement('script'); po.type = 'text/javascript'; po.async = true;
     po.src = 'https://apis.google.com/js/plusone.js';
     var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(po, s);
  })(); }, 3000);
 
  setTimeout(function() {
    // Twitter
    !function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0],p=/^http:/.test(d.location)?'http':'https';if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src=p+'://platform.twitter.com/widgets.js';js.charset='utf-8';fjs. parentNode.insertBefore(js,fjs);}}(document, 'script', 'twitter-wjs');
    
    // Pocket
    !function(d,i){if(!d.getElementById(i)){var j=d.createElement("script");j.id=i;j.src="https://widgets.getpocket.com/v1/j/ btn.js?v=1";var w=d.getElementById(i);d.body.appendChild(j);}}(document,"pocket-btn-js");
  }, 4000);
}

show_social_btn('#global-sns', 'http://www.cherry-pick.jp/blog/', 'SRE BLOG');

第1引数に、ソーシャルボタンを表示するID、第2引数はURL、第3引数はページタイトルを設定します。
この関数は、同じページでWebサイトのソーシャルボタンと個別記事のソーシャルボタンを同時に表示することができます。

さらに、ソーシャルボタンのhtmlの追加処理と、TwitterとPocketのボタンを表示のためのJavaScriptの読み込みを分けて、後者をボタンの表示後に読み込み無用にしています。
TwitterとPocketのボタンは、先にボタン表示のhtmlがないと読み込んだJavaScriptが正しく認識してくれないためです。ページ全体でボタンが1つだけであれば分けなくてよいのですが、Webサイト全体のソーシャルボタンと記事のソーシャルボタンを同じページに複数表示したいときなど、あとから読み込むボタンが正しく表示されないことがあったので読み込む間隔をあけました。

GTMetrixで表示速度と他の改善案をチェック

Webページの表示速度のチェックや改善点の確認によく使うのがGTMetrixです。ChromeのPageSpeedでも良いのですが、GTMetrixだとYSlow!の評価も同時に行ってくれます。

Googleだけでもいいとも思いますが、1つの評価軸にだけ捕らわれずにどちらでも高得点を狙うことで複数の視点から見ることを忘れないようにしています。

改修前のキャプチャを撮り忘れたのですが、D評価だったり8.5秒くらいかかっていたものがPageSpeedではB評価、YSlow!ではA評価となりました。
表示速度は1.66秒と7秒も改善されています。

130902_GTmetrix.png

実はこの記事を書く前に、某有名IT企業の技術ブログなどもベンチマークにしようと勝手に計測してみましたが、早いものでも3秒くらいかかっていたり、時間のかかるものでは8秒くらいかかっているものもあったので1.66秒でもかなり早い方でした。

SRE BLOGはレスポンシブWebデザインで、スマホでも快適に見られることを目指しているので、この辺りの改善は継続的かつ積極的に進めていこうと思います。

今回は、ブログの移行と改修内容を公開してみました。
表示速度を改善したい!提供する情報構造を最適化したい!(要するにSEOですw)
そんなときは、ご相談だけでもお気軽にお問い合せください!

商品・サービスへのお問い合わせ

ご相談、お見積もりのご依頼など

お問い合せはこちら