SEOに適した無限スクロールの導入
FacebookやTwitter、Pinterestなどのソーシャルメディアサイトが使っている事で一躍有名になった無限スクロール(英: Infinite Scrolling)ですが、今でもシングルページを利用したウェブサイト、特にコンテンツの量が豊富なギャラリー的なサイトではよく見かけます。
しかし、よく見られるjQueryを使ったシンプルな無限スクロールはコンテンツをすべて1つのHTMLファイル上に記述しておいて、スクロールするたびに「display:block」と「display:none」を使って表示させていく、というものです。人が見る分にはこの形でも良いでしょうが、Googlebot に対してとなると話が変わってきます。
ご自身のサイトのニュース フィードやピンボードで、ユーザーの利便性を考えて無限スクロール(英語)を使用している方もいらっしゃるでしょう。しかし、Googlebot に対してとなると話が変わってきます。無限スクロールでは、クローラーがユーザーの行動(スクロールやボタンを押してさらにアイテムを読み込むなど)を常にエミュレートできるとは限らないため、フィードやギャラリー内のすべてのアイテムにアクセスできないことがあります。クローラーがアクセスできないコンテンツは、検索結果に表示されることもないでしょう。
無限スクロール ページからリンクされている個別のアイテムを検索エンジンがクロールできるようにするには、無限スクロールを分割した一連のページ群を生成するようにしましょう。

Google ウェブマスター向け公式ブログ [JA]: 検索エンジンとの相性を考慮した無限スクロールのベストプラクティス
pushStateによるブラウザの履歴の更新
pushStateとは?
pushStateとは、HTML5でサポートされるAPIです。
ページを遷移せずHTML(の一部)を変えた場合でもブラウザに履歴を残し、また一意のURLを割り当てることが可能です。HTMLの中身が変わってもAjaxはページを遷移しないのでURLが同じままです(#以下が入れ替わるだけで一意のURLとして処理しない)。
ブラウザの戻るボタンを押しても前のコンテンツを再び表示させることはできません。
本当に前のページに戻ってしまいます。なのでGoogleは、クロール・インデックスできるように特殊な仕様をサポートしてくれたわけです。
しかしpushStateを使えば、Ajaxで変化させたそれぞれのコンテンツに対してユニークなURLを割り当てられるのです。
つまり検索エンジンにとってクロール・インデックスしやすくなります。
Googleの記事では、無限スクロールは次々にページを捲っていく事と同じとしている。そのため、無限スクロールで新しいコンテンツが表示される度にブラウザの履歴(URL)を更新しなければいけない。さらにスクロールでページを進んだり戻ったりする度にURLを更新させる必要があります。
JavaScriptが切れている状態でも手動でページ遷移出来るような設定も取り入れ、検索エンジンとの相性を考慮した無限スクロールにカスタマイズしましょう。
さらに簡易的なリダイレクト機能を使って、下層ページから入った時にトップページに戻るよう設定しましょう。
<meta http-equiv="refresh" content="0;URL='index.html'" />
以上の内容を踏まえて、今回は検索エンジンが処理しやすい無限スクロールを作っていきましょう。
今回のポイント
- ajaxを使ったシームレスなページ遷移
- HTML5のAPIを使い、各ページにユニークなURLやタイトルを最適化する事が出来る
- 無限スクロールページを、JavaScript が無効でもアクセス可能な形にする。
- 各コンテンツページにはトップページに自動的に戻るリダイレクト機能を実装
- 相対パスはNGなのでルートパス、もしくは絶対パスを使用すること
- 各コンテンツ毎にユニークなタイトルの設定が可能
特にページのタイトルの最適化は非常に大事です。通常の無限スクロールは1枚のhtmlファイルに無数のコンテンツが記述されていますが、今回のようにhtmlファイルを細分化する事で、コンテンツに応じたより細かいタイトルやURLの設定が可能になります。
<script> $('#container').cleverInfiniteScroll({ contentsWrapperSelector: '#container', contentSelector: '.wrapper', nextSelector: '#next', }); </script>
デモページ
http://yachin29.html.xdomain.jp/infini-scroll/
Javascriptによるリダイレクト
Javascriptによるリダイレクトの方法もあるので、試してみましょう。
setTimeout("redirect()", 0); function redirect(){ location.href='../index.html'; }
トップページ
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <title>SEOに適した無限スクロール</title> <meta name="viewport" content="width=device-width"> <link rel="stylesheet" href="css/style.css"> </head> <body class="top-page"> <div id="container"> <div class="wrapper"> <h1>SEOに適した無限スクロール</h1> <div class="key-visual"> <img src="http://felica29.starfree.jp/infini-scroll/img/the_river.jpg" alt=""> </div> <div class="top-main"> <h2>浮世絵で巡る東海道</h2> <p class="description"> 東海道五十三次(とうかいどうごじゅうさんつぎ)は、江戸時代に整備された五街道の一つ、東海道にある53の宿場を指す。古来、道中には風光明媚な場所や有名な名所旧跡が多く、浮世絵や和歌・俳句の題材にもしばしば取り上げられた。 </p> </div><!--/.top-main--> </div><!--/.wrapper--> </div><!--/#container--> <p id="btn"><a href="#"><img src="img/to-top.svg" alt=""></a></p> <p><a href="http://felica29.starfree.jp/infini-scroll/nihonbashi/" id="next">次のページへ</a></p> <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script> <script src="js/jquery.clever-infinite-scroll.js"></script> <script> $('#container').cleverInfiniteScroll({ contentsWrapperSelector: '#container', contentSelector: '.wrapper', nextSelector: '#next', }); $(function() { $('#btn a').on('click', function () { $('html,body').animate({ scrollTop: 0 },200); }); }); </script> </body> </html>
下層ページ
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <title>東海道五拾参次|品川宿</title> <meta name="viewport" content="width=device-width"> <meta http-equiv="refresh" content="0;URL='../index.html'"> <link rel="stylesheet" href="/infini-scroll/css/style.css"> </head> <body class="under"> <div id="container"> <div class="wrapper"> <h1>其壱・品川宿</h1> <div class="photo"> <img src="http://felica29.starfree.jp/infini-scroll/img/shinagawa.jpg" alt=""> </div> <p class="txt">品川宿(しながわしゅく、しながわじゅく)は、東海道五十三次の宿場の一つ。東海道の第一宿であり、中山道の板橋宿、甲州街道の内藤新宿、日光街道・奥州街道の千住宿と並んで江戸四宿と呼ばれた。</p> </div> </div> <p><a href="http://felica29.starfree.jp/infini-scroll/kawasaki/" id="next">次のページへ</a></p> <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script> <script src="../js/jquery.clever-infinite-scroll.js"></script> <script> $('#container').cleverInfiniteScroll({ contentsWrapperSelector: '#container', contentSelector: '.wrapper', nextSelector: '#next', }); </script> </body> </html>
/* ress.css • v1.2.2 * MIT License * github.com/filipelinhares/ress */html{box-sizing:border-box;-webkit-text-size-adjust:100%}*,:after,:before{background-repeat:no-repeat;box-sizing:inherit}:after,:before{text-decoration:inherit;vertical-align:inherit}*{padding:0;margin:0;box-sizing:border-box}audio:not([controls]){display:none;height:0}hr{overflow:visible}article,aside,details,figcaption,figure,footer,header,main,menu,nav,section,summary{display:block}summary{display:list-item}small{font-size:80%}[hidden],template{display:none}abbr[title]{border-bottom:1px dotted;text-decoration:none}a{background-color:transparent;-webkit-text-decoration-skip:objects}a:active,a:hover{outline-width:0}code,kbd,pre,samp{font-family:monospace,monospace}b,strong{font-weight:bolder}dfn{font-style:italic}mark{background-color:#ff0;color:#000}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}input{border-radius:0}[role=button],[type=button],[type=reset],[type=submit],button{cursor:pointer}[disabled]{cursor:default}[type=number]{width:auto}[type=search]{-webkit-appearance:textfield}[type=search]::-webkit-search-cancel-button,[type=search]::-webkit-search-decoration{-webkit-appearance:none}textarea{overflow:auto;resize:vertical}button,input,optgroup,select,textarea{font:inherit}optgroup{font-weight:700}button{overflow:visible}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{border-style:0;padding:0}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button:-moz-focusring{outline:1px dotted ButtonText}[type=reset],[type=submit],button,html [type=button]{-webkit-appearance:button}button,select{text-transform:none}button,input,select,textarea{background-color:transparent;border-style:none;color:inherit}select{-moz-appearance:none;-webkit-appearance:none}select::-ms-expand{display:none}select::-ms-value{color:currentColor}legend{border:0;color:inherit;display:table;max-width:100%;white-space:normal}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}img{border-style:none;vertical-align: bottom}progress{vertical-align:baseline}svg:not(:root){overflow:hidden}audio,canvas,progress,video{display:inline-block}@media screen{[hidden~=screen]{display:inherit}[hidden~=screen]:not(:active):not(:focus):not(:target){position:absolute!important;clip:rect(0 0 0 0)!important}}[aria-busy=true]{cursor:progress}[aria-controls]{cursor:pointer}[aria-disabled]{cursor:default}::-moz-selection{background-color:#b3d4fc;color:#000;text-shadow:none}::selection{background-color:#b3d4fc;color:#000;text-shadow:none}ul,ol{list-style:none;}a{text-decoration:none;}.wrapper{overflow:hidden;}body{overflow-y:scroll;} body{ font-family: serif; } /*トップページ*/ .top-page h1{ text-align: center; font-size: 40px; padding: 50px 0 30px; } .key-visual{ text-align: center; margin-bottom: 40px; } .top-main{ max-width:800px; margin: 0 auto 100px; } .top-page h2{ margin-bottom: 20px; font-size: 30px; } #btn{ width: 50px; height: 50px; position: fixed; bottom: 30px; right: 30px; } /*下層ページ*/ .under .wrapper{ height: 130vh; text-align: center; } .under h1{ text-align: center; font-size: 40px; padding: 50px 0; } .photo{ margin-bottom: 50px; text-align: center; } .txt{ width: 600px; margin: 0 auto; }
コメント