[Rails meets jQuery] jQueryで作るページ内目次とスムーススクロール

書いた人: noriaki 2007,10月03日(水) 04:30

今回はjQueryのプラグインを2つ組み合わせて,ページのユーザビリティを高める方法を紹介します.

それはjqTOCプラグインを使ってページ内の目次を自動作成し,Interface Element for jQueryプラグインを使ってページ内の移動をスムーススクロールで実現するものです.

ページが長くなった場合,ページ内の項目を抜き出した目次を作ると,訪れたユーザはページ内容を把握しやすくなり,見たい項目を探しやすくなります. この機能を提供するjQueryプラグインがjqTOCです.

またこのとき,目次のリンクをクリックして目的の項目へと移動するわけですが,通常のページ内リンクでは画面が急にその項目の場所へと切り替わってしまうため,ユーザはいま自分がどこにいるのかを見失ってしまいかねません.

「ページ内リンクでスムーススクロール」するためのJavaScriptコードを配布します。ページ内リンクを使う際に、このスクリプトもあわせて使えば、訪問者に親切かもしれません。

[ajax] ページ内リンクでスムーススクロール @ ZEROBASE BLOG

そこで,ページ内リンクに対してリンク先へスムーズにスクロールする機能をInterface Element for jQueryプラグインの中のscroll.jsを利用して作ります. これは,上記ページで紹介されているprototype.jsを利用したもののjQuery版といってもいいでしょう.

以下では,2つのプラグインの導入方法や,IEでのレイアウトバグの直し方,スムーススクロールの長距離スクロールできないバグの直し方,サンプルページについて紹介します.

サンプルページ

まずはサンプルページを見てどんなものかイメージしてみてください.

Gigazinize Tools - Image: About

このページは,先日ご紹介したGigazinize Tools - Image」のAboutページです.

右上に表示されている「お品書き」をクリックすると目次が現れます. また,目次内のリンクや,ページ中の「ページTOP」といったリンクをクリックするとスムーズにスクロールします.

jqTOC

jqTOCは,ページ内の見出し(h1,h2...)から自動的に目次を生成するjQueryプラグインです.

例えば,以下のようなHTMLはわりとちゃんとしたマークアップとして用いられると思いますが,このようなセクションやサブセクションを目次として生成します.

<div id="contents">
  <h1>ページタイトル</h1>
  <p>ページ概要</p>


  <h2>1. セクション</h2>
  <p>セクション本文</p>

  <h3>1.1. サブセクション</h3>
  <p>サブセクション本文</p>

  <h3>1.2. サブセクション</h3>
  <p>サブセクション本文</p>

  <h4>1.2.1 サブサブセクション</h4>
  <p>サブサブセクション本文</p>


  <h2>2. セクション</h2>
  <p>セクション本文</p>

  ...
</div>

使い方

jqTOCのページからjavascriptファイルとCSSファイルをダウンロードして,任意のディレクトリに置くと準備完了です.

javascriptファイル

目次を設置したいページのscriptタグ内か,外部スクリプトファイルに以下のように記述します.なおこのとき,jQuery本体の読み込みよりもよりも後に記述する必要があります.

jqTOC_init.js
$(function() {
  $('#contents').jqTOC({
    tocWidth: 200,
    tocTitle: 'お品書き', // エスケープ後'\u304A\u54C1\u66F8\u304D'
    tocStart: 2,
    tocEnd: 4,
    tocContainer: 'toc_container',
    tocAutoClose: true,
    tocShowOnClick: true,
    tocTopLink: false
  });
});

目次を生成したい部分を囲む要素に対して,.jqTOC()メソッドを呼び出します. このとき,引数にオブジェクト形式でオプションを渡すことによって設定を変更することが可能です. オプションそれぞれの意味は,以下のようになっています.それぞれは省略可能で,省略した再にはデフォルトの値が利用されます.

tocWidth
目次の幅
tocTitle
目次タイトル
tocStart
目次作成を開始する見出しの深さ(h2から)
tocEnd
目次作成を終了する見出しの深さ(h4まで)
tocContainer
生成される目次の要素ID
tocAutoClose
目次をクリックしたら自動的に目次を閉じる
tocShowOnClick
クリックで目次を開閉する
tocTopLink
各見出しの横に「ページの先頭へ戻る」リンクを作る
文字列を指定するとその文言で生成される
jqTOC用CSSの修正

次に,ダウンロードして配置したjqTOC用CSSの冒頭にあるIE用のfix部分を以下のように修正します.

jqTOC.css

/* for IE6 fixed positioning support */
* html {overflow-x:auto; overflow-y:scroll;}
* html #toc_container {position:absolute;}
body {
  margin:0;
  padding:0 10px 0 10px;
  height:100%;
}
/* end fixes */

なぜこのような修正を行うかというと,そのままではページをスクロールできなかったためです. 他のファイルとの関係が原因の場合も考えられるので,一度デフォルトのまま設置してみて,おかしいようなら修正してみてください.

ページ先頭へのリンク

jqTOCにはページ先頭へ戻るためのリンクを自動的に生成する機能がありますが, 各見出しの真横にリンクが生成されたり,最初の見出しにもリンクが生成されてしまったりと好みに合わなかったため, 上記の使い方のところではtocTopLinkfalseで無効にし,自分でページ先頭へ戻るリンクを設置することにしました.

これも,jQueryを使えば簡単に作ることができます. 例えば,以下のようなスクリプトをscriptタグ内か外部スクリプトファイルに書きます.

$(function() {
  $('h2:gt(0), #footer').before($.N('p', {
    className: 'movetop'
  }, [
    $.N('a', {
      href: '#header', // ページTOPにあるタグのIDを指定
      title: 'ページTOPへ移動する'  // '\u30DA\u30FC\u30B8TOP\u3078\u79FB\u52D5\u3059\u308B'
    }, 'ページTOP')  // '\u30DA\u30FC\u30B8TOP'
  ]));
};

なお,ここで利用している$.N()は先日のエントリ「jQuery入門」でご紹介したHTML要素作成のためのメソッドです.

interface.jsによるスムーススクロール

今回はjQueryとInterface.jsで作るスムーススクロールです。ページ内リンクを滑らかに移動するやつ 。

Interface.jsで簡単スムーススクロール - Emotional Web

interface.jsによるスムーススクロールは上記のページを参考にしました. さらに今回は,上記のページコメント欄で報告されている長距離のスクロールが途中で止まるというバグを解決する方法をご紹介します.

ダウンロード

Interface Element for jQueryはわりと大きなモジュールの集まりなので,必要なものだけを選択してダウンロードできるようになっています. この場合,選択されたものをコード圧縮したjsファイルがダウンロードできます.

しかし,今回は上記バグ修正を行うために,非圧縮ソースファイルを利用します. ソースファイルをダウンロードするには,Downloadページ内下部の「Interface 1.2」というリンクをクリックします. そして,その中のifxscrollto.jsを利用します.

ソースコードの修正

適当なエディタでifxscrollto.jsを開き,72行目を以下のように修正します.

// 修正前
z.clear = function(){clearInterval(z.timer);z.timer=null;jQuery.dequeue(z.e, 'interfaceFX');};
// 以下のように修正する
z.clear = function(){clearInterval(z.timer);z.timer=null;jQuery(e).dequeue('interfaceFX');};

使い方

上記の修正したifxscrollto.jsを適当なディレクトリに置き,利用したいページのヘッダ部分で外部スクリプトとして読み込んでください.なおこのとき,jQuery本体よりも後に読み込む必要があります.

次に,すべてのページ内リンクに対してスムーススクロールを実現するonclickイベントを設定します. これは以下のようなスクリプトをscriptタグ内か,外部スクリプトファイルとして読み込みます.

$(function() {
  $('a[href*=#]').click(function() {
    if (location.pathname.replace(/^\//,'') == this.pathname.replace(/^\//,'')
      && location.hostname == this.hostname) {
      var $target = $(this.hash);
      $target = $target.length && $target
        || $('[name=' + this.hash.slice(1) +']');
      if ($target.length) {
        var targetOffset = $target.offset().top - 20;
        $('html,body')
          .animate({scrollTop: targetOffset}, 1000);
        return false;
      }
    }
  });
});

以上で,ページ内リンクがスムーズにスクロールするようになり,ユーザが迷子になりづらいページが出来上がります.

まとめ

ページのユーザビリティを高めるために,非常に相性の良いjqTOCInterface Element for jQueryのscroll.jsを組み合わせて導入する方法を紹介しました.

導入手順を簡単におさらいすると以下のようになります.

  1. jqTOC.js, jqTOC.css, interface_1.2.zip のダウンロード
  2. interface_1.2.zip内のifxscrollto.jsを修正
  3. 必要なファイルを設置
  4. 目次作成・ページTOPへのリンク作成・スムーススクロールの実現をjavascriptを書く
  5. IEでの閲覧に問題があればjqTOC.cssの修正

最後に上記手順4番目で書くjavascriptを1つにまとめたものを示します.以下のコードを適当な名前のfavascriptファイルとしてヘッダ部分の最後で読み込めばこれらの機能が実現できます.

about.js

$(function() {
  // Table of Contents
  $('#wrap').jqTOC({
    tocWidth: 200,
    tocTitle: '\u304A\u54C1\u66F8\u304D',
    tocStart: 2,
    tocEnd: 4,
    tocAutoClose: true,
    tocShowOnClick: true,
    tocTopLink: false
  });

  // Move up to Page-Top
  $('h2:gt(0), #footer').before($.N('p', {
    className: 'movetop'
  }, [
    $.N('a', {
      href: '#header',
      title: '\u30DA\u30FC\u30B8TOP\u3078\u79FB\u52D5\u3059\u308B'
    }, '\u30DA\u30FC\u30B8TOP')
  ]));
  $('a[href*=#]').click(function() {
    if (location.pathname.replace(/^\//,'') == this.pathname.replace(/^\//,'')
      && location.hostname == this.hostname) {
      var $target = $(this.hash);
      $target = $target.length && $target
        || $('[name=' + this.hash.slice(1) +']');
      if ($target.length) {
        var targetOffset = $target.offset().top - 20;
        $('html,body')
        .animate({scrollTop: targetOffset}, 1000);
        return false;
      }
    }
  });
});

サンプルページ

Gigazinize Tools - Image: About

参考ページ

Interface.jsで簡単スムーススクロール - Emotional Web
http://www.lllcolor.com/web/jquery/74.html
Learning jQuery » Animated Scrolling for Same-Page Links
http://www.learningjquery.com/2007/08/animated-scrolling-for-same-page-links
# スクロールバグの修正方法についてコメント#16も参照
Learning jQuery » Animated Scrolling with jQuery 1.2
http://www.learningjquery.com/2007/09/animated-scrolling-with-jquery-12
jqTOC: jQuery meets Table of Contents at Nepherim
http://nepherim.lifehaiku.com/lyceum/jqtoc

このエントリをdel.icio.usにブックマークしているユーザ数このエントリをdel.icio.usに追加する
このエントリをはてなブックマークしているユーザ数このエントリをはてなブックマークに追加する
 | Posted in  | Tags ,

コメント

  1. 石橋 said 約12分 later:

    GJ!

  2. noriaki said 約13分 later:

    石橋さん

    コメントありがとうございます.

    jQueryはまだまだ日本語のドキュメントが少ないですが,どんどんRailsに組み込んでいこうと思ってます.

    あと,ZEROBASEのスムーススクロールが動かなくなってます.コメントへの返信の中で書いてすいません.

  3. kimpo said 30日 later:

    スムーススクロールのスクリプト使わせて頂きました。 素晴らしい内容でビックリです。 これからもjQueryネタが出てくると嬉しいです。

  4. noriaki said 30日 later:

    kimpoさん

    コメントありがとうございます.

    スムーススクロールのスクリプトを使っていただき,ありがとうございます.

    jQueryには私も注目しているので,便利なプラグインや使い方,Railsとの連携などをこれからも書いていくつもりです.なので,また見に来てくださいね.

  5. kimura said 44日 later:

    はじめまして、今まで想像もできないような便利なスクリプトだと思い、是非、自分のサイトに使わせてもらいたいと思い、じっくり読ませてもらってます。目次の表示はできたのですが、javascriptなどがまったく初心者なもので間違っているようでスムーススクロールの機能が働いてくれずに、普通のページ内リンクの状態になってしまいます。すいませんが、about.jsのどの部分を書き換えればいいのかもう少し詳しく教えてもらう事はできまませんか? よろしくお願いします

  6. noriaki said 49日 later:

    kimuraさん:

    コメントありがとうございます.また,目次の表示ができたとのことで,参考になったのであれば幸いです.

    さて,スムーススクロールが動作しないとのことですが,コメントいただいた内容だけではちょっと判断できないです.

    公開できるのであれば,本エントリ内容を適用して作成したページのURLをお教えいただければアドバイスできるかもしれません.

    または,スムーススクロール実現のためにkimuraさんが書かれたソースコードを見せていただけますか.

    ちなみに,本エントリ内でのスムーススクロール実現のためのスクリプトは「interface.jsによるスムーススクロール」 - 「使い方」の節に書いてある部分です.

  7. kimura said 49日 later:

    noriakiさん:

    お返事ありがとうございます。

    ページ内目次とスムーススクロールを使用したいページですが、このURLになります。お手数かけて申し訳ないです。

    http://www.kimuradesukedo.net/photo/index.htm

    またスクリプト内でのエンコードに関してなんですけど、これに関して参考になるようなWebページを教えてもらえないでしょうか。

    よろしくお願いします。

  8. noriaki said 52日 later:

    kimuraさん:

    スムーススクロールを利用しているページを拝見しました.

    スムーススクロールが動作しない原因は,about.js内の14行目から21行目にかけて利用している$.N()という関数が存在しないためだと思います.

    この部分では,目次を作成した各項目の末尾に「ページTOP」へのリンクを自動的に付加しています.

    $.N()関数に関しては,[Rails meets jQuery] jQuery入門(+ prototype.js との比較)をご覧いただき,jQuery入門のページにあるソースコードをabout.jsの先頭にコピーしてください.

    また,kimuraさんのページの場合,about.jsの14行目を以下のようにするとうまく「ページTOP」へのリンクが挿入されると思います.(たぶん)

    $('.offensive_half').append($.N('p', {
    

    または,「ページTOP」へのリンク挿入が必要なければ14行目から21行目までを削除していただいてもかまいません.

    最後に,スクリプト内でのエンコードに関しては,以下のWebページで変換を行いました.

    Text Escaping and Unescaping in JavaScript

  9. kimura said 53日 later:

    noriakiさん:

    教えてもらった通りでうまく動きました。 ありがとうございます。

    長いページでもユーザビリティの配慮を気にせず使えるのですごく便利です。

    これからもjQueryネタなどチェックさせてもらいます。ありがとうございました。

  10. 実花 said 104日 later:

    これはすごいですね。私もスムーススクロール自分のサイトに取り入れたいと思います。

このエントリはアーカイブされています。
コメントする場合は、お手数ですが「このページのURL」を記載した上で、新しいエントリにお願いします。