[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
});
});
目次を生成したい部分を囲む要素に対して,
- 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にはページ先頭へ戻るためのリンクを自動的に生成する機能がありますが,
各見出しの真横にリンクが生成されたり,最初の見出しにもリンクが生成されてしまったりと好みに合わなかったため,
上記の使い方のところでは
これも,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;
}
}
});
});
以上で,ページ内リンクがスムーズにスクロールするようになり,ユーザが迷子になりづらいページが出来上がります.
まとめ
ページのユーザビリティを高めるために,非常に相性の良いjqTOCとInterface Element for jQueryのscroll.jsを組み合わせて導入する方法を紹介しました.
導入手順を簡単におさらいすると以下のようになります.
- jqTOC.js, jqTOC.css, interface_1.2.zip のダウンロード
- interface_1.2.zip内のifxscrollto.jsを修正
- 必要なファイルを設置
- 目次作成・ページTOPへのリンク作成・スムーススクロールの実現をjavascriptを書く
- 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



GJ!
石橋さん
コメントありがとうございます.
jQueryはまだまだ日本語のドキュメントが少ないですが,どんどんRailsに組み込んでいこうと思ってます.
あと,ZEROBASEのスムーススクロールが動かなくなってます.コメントへの返信の中で書いてすいません.
スムーススクロールのスクリプト使わせて頂きました。 素晴らしい内容でビックリです。 これからもjQueryネタが出てくると嬉しいです。
kimpoさん
コメントありがとうございます.
スムーススクロールのスクリプトを使っていただき,ありがとうございます.
jQueryには私も注目しているので,便利なプラグインや使い方,Railsとの連携などをこれからも書いていくつもりです.なので,また見に来てくださいね.
はじめまして、今まで想像もできないような便利なスクリプトだと思い、是非、自分のサイトに使わせてもらいたいと思い、じっくり読ませてもらってます。目次の表示はできたのですが、javascriptなどがまったく初心者なもので間違っているようでスムーススクロールの機能が働いてくれずに、普通のページ内リンクの状態になってしまいます。すいませんが、about.jsのどの部分を書き換えればいいのかもう少し詳しく教えてもらう事はできまませんか? よろしくお願いします
kimuraさん:
コメントありがとうございます.また,目次の表示ができたとのことで,参考になったのであれば幸いです.
さて,スムーススクロールが動作しないとのことですが,コメントいただいた内容だけではちょっと判断できないです.
公開できるのであれば,本エントリ内容を適用して作成したページのURLをお教えいただければアドバイスできるかもしれません.
または,スムーススクロール実現のためにkimuraさんが書かれたソースコードを見せていただけますか.
ちなみに,本エントリ内でのスムーススクロール実現のためのスクリプトは「interface.jsによるスムーススクロール」 - 「使い方」の節に書いてある部分です.
noriakiさん:
お返事ありがとうございます。
ページ内目次とスムーススクロールを使用したいページですが、このURLになります。お手数かけて申し訳ないです。
http://www.kimuradesukedo.net/photo/index.htm
またスクリプト内でのエンコードに関してなんですけど、これに関して参考になるようなWebページを教えてもらえないでしょうか。
よろしくお願いします。
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
noriakiさん:
教えてもらった通りでうまく動きました。 ありがとうございます。
長いページでもユーザビリティの配慮を気にせず使えるのですごく便利です。
これからもjQueryネタなどチェックさせてもらいます。ありがとうございました。
これはすごいですね。私もスムーススクロール自分のサイトに取り入れたいと思います。