ページ内を移動するリンクやボタンを設定する時のメモ

ページ内リンクにはいろいろな方法があって、毎回迷ってしまうので、自分の環境で一番手間のかからない方法のメモ。

環境

aタグのname属性、またはdivタグ等のid属性にリンクする方法

  • 最も基本的な方法は、以下のようにリンクを張るだけでOK。
    • name属性は必ずaタグに設定しなければならない。
    • id属性は任意のタグで大丈夫。
<%= link_to "タイトル1へ", "#page_link1" %>
...(中略)...
<a name="page_link1"></a>
<div>
タイトル1の始まり
...(中略)...
</div>

または...

<%= link_to "タイトル1へ", "#page_link1" %>
...(中略)...
<div id="page_link1">
タイトル1の始まり
...(中略)...
</div>

inputボタンをページ内を移動するボタンにする方法

  • 本来、ボタンはフォームの内容を送信するためのもので、ページ内を移動するならボタンの画像にリンクを設定すべきかもしれないが...。
  • javascriptを有効にして、prototype.jsのElement.scrollToを使えば指定したid属性の位置に移動できる。(link_toをbutton_toに変更しただけではダメだった。)
<%# ---------- app/views/layouts/test.rb ---------- %>
...(中略)...
<%= javascript_include_tag :defaults %>
...(中略)...
<%# ---------- app/views/tests/index.rb ---------- %>
<%= button_to_function "タイトル1へ", "Element.scrollTo($('page_link1'))" %>
...(中略)...
<div id="page_link1">
タイトル1の始まり
...(中略)...
</div>
  • もっとシンプルにscroll(pageX座標, pageY座標)を利用しても良いかもしれないが、ページ上の座標をpxで直接指定しなければならない。
<%= button_to_function "タイトル1へ", "scroll(0, 100)" %>

スムーズにスクロールしながら移動する方法

  • javascriptを使い始めるとちょっと欲が出てきて、それなら瞬間移動するのではなく、移動している最中をスクロールで見せたくなってくる。
  • 多くの人が同じようなことを考えるようで、「ページ内リンク スクロール」で検索すると、素晴らしい達人の技がとってもたくさん見つかる。
  • たくさんあり過ぎてどれを使うべきか迷う。しかし、Railsを使っているならデフォルトのjavascriptライブラリで以下のようにすれば実現できたのであった...。
<%# ---------- app/views/layouts/test.rb ---------- %>
...(中略)...
<%= javascript_include_tag :defaults %>
...(中略)...
<%# ---------- app/views/tests/index.rb ---------- %>
<%= button_to_function "タイトル1へ", "new Effect.ScrollTo('page_link1')" %>
...(中略)...
<div id="page_link1">
タイトル1の始まり
...(中略)...
</div>
<%= button_to_function "タイトル1へ", "new Effect.ScrollTo('page_link1', {duration:2, fps:10})" %>

スクロールアニメーションしない時...

  • ここまでsafari 3.1.2で確認して大満足だったのだけど、firefox 3.0.3とiPhone・iPodTouchのOS2.1のsafariでは思った通りのスクロールをしてくれない...。
  • 悩んだ末にソースを確認して、以下のようにやってしまった...。(果たして他の部分にどのような影響が出るか不明。)
  • 修正箇所はオレンジ色の3文字「,//」を追加した。
// ---------- public/javascripts/effects.js ----------
...(中略)...
Effect.ScrollTo = function(element) {
  var options = arguments[1] || { },
    scrollOffsets = document.viewport.getScrollOffsets(),
    elementOffsets = $(element).cumulativeOffset(),
    max = (window.height || document.body.scrollHeight) - document.viewport.getHeight();

  if (options.offset) elementOffsets[1] += options.offset;

  return new Effect.Tween(null,
    scrollOffsets.top,
    elementOffsets[1],// > max ? max : elementOffsets[1],
    options,
    function(p){ scrollTo(scrollOffsets.left, p.round()) }
  );
};
...(中略)...
  • 自分なりに何が起こっているのか考えたこと。
    • スクロールをアニメーションするための準備として、現在のページの座標scrollOffsets(現在のスクロールの状態)と、スクロール完了後のページの座標elementOffsetsを設定している。
    • しかし、スクロール先がページの終わりに近い場合、その位置をウィンドウの上までスクロールできない可能性がある。
    • その条件を判定するために、max*1を設定して、スクロールする残りが不足する場合は、余分にスクロールしないように設定しているようだ。
    • でも、maxの値を確認してみると、firefoxiPhone・iPodTouchでは常に0になってしまっている様子。
    • ブラウザによって、document.body.scrollHeightやdocument.viewport.getHeight()の基準が当初と違ってきているようだ。
    • そのため、常にページトップにスクロールで戻ってしまうという現象になっている。
    • safarifirefoxiPhone、iPodTouchで確認してみたが、余分にスクロールを指定してしまっても、特に問題ないようだ。(IE6,7では確認していないので問題あるかも)
    • そこで、条件判定するのはやめて、常にスクロール完了後のページの座標elementOffsetsを設定するようにしてしまった。

これで軽快にスクロールアニメーションしてくれるようになった!自分の環境では満足。

*1:maxはつまり、実際にスクロールできる範囲の座標を求めている。