HTML:アンカー(aタグ)でページ内リンクを作成する方法

最終更新:2018-08-14 by Joe

HTMLのaタグを使ってアンカー要素でページ内リンクしたい時、正しい方法をたまに忘れるのでメモします。クリック後のスクロールがずれてしまう問題も、解決指針を付け加えました。

HTML でのページ内リンクの設定方法

Step 1ページ内リンク先に id を設定する

ページ内リンクは、該当の HTML 要素の「id 属性」を使って設定します。

<!-- ページ内のリンク先の指定はIDを利用 -->
<h1 id="link-to-me">ここにジャンプして〜。</h1>

id 属性の名前は、下記の点に注意します:

  1. ページ内でユニーク(唯一無二)な名前をアルファベットで付ける
  2. 数字で書き始めてはいけない(例えば、「id=”1″」 などは不可)
  3. 大文字・小文字を区別する

特に、1のルールに関して注意が必要です。

HTML 要素の id 属性は「ページ内で唯一無二でなければならない」ですので、誤って2つ同じ名前記述してしまっても、ページの表示自体は、問題ありませんが、そのページ内リンクは期待通り動作しなくなるかもしれません。(HTMLの仕様書に基づくと「先に検出されたほう」が勝ち、そこにリンクします。)

蛇足ですが、CSS で要素を参照するときにおいても、id をセレクタとして利用すると、名前の重複などが発生すると問題が大きく、id 名の管理はしばしば問題になります。CSS の場合は、強い理由がない限りは、id ではなく必ず class 属性を利用して要素をセレクトするのが一般的ですし、安全です。

Step 2リンク元のアンカー要素(aタグ)のhrefを指定する

クリックされるアンカー側は、至ってシンプルです。

<!-- ジャンプ先のIDを#とともに指定 -->
<a href="#link-to-me">これをクリックすると、ページ内リンクにジャンプ</a>

ID名の冒頭に「#」を付けるのを忘れないようにして下さい。#がない場合、「<現在のページの親ディレクトリ>/<指定したリンク>」という相対パスとして認識されてしまいます。

name属性も利用できる?

下記も現状(2017年5月)時点で、多くのブラウザで動作はしますが、HTML 要素の「name 属性」を使った方法も存在します。

<!-- いちおう有効だが・・ -->
<h1>
  <a name="link-to-me">ここにジャンプして〜</a>
</h1>

現在も多くのブラウザで動作はしますが、HTML5移行は、アンカー要素の name 属性は廃止予定です。一方で、id を利用したページ内リンクは依然として有効ですので、アンカー要素の name 属性を利用する必要はありません。name 属性を使ったページ内リンクの利用は、将来を見据えて、避けるべきでしょう。

参考:HTML 5.2 Editor’s Draft, 3 May 2017:

すでに廃止されているのであれば、name 属性を使う理由はないね。できるだけ id 属性を使ってリンクしよう。

ページ内リンクにジャンプしても、ずれてしまう?問題

ページのレイアウトによっては、ページ内リンクに移動した後に、なんだか少しスクロール位置がずれてしまうかもしれません。

原因は多くの場合、CSSを使ったレイアウトに起因します。一概には言えませんが、代表的な例が、marginとpadding に依るものです。

わかりやすさのために色を付けると・・

ページ内リンクがずれてしまう問題

ページ内リンクは、この色を付けた領域の先頭が、ブラウザのウィンドウの上枠に一致するようににジャンプします。これを解決するのはそもそも要素のレイアウトに影響してしまうためすこし厄介ですが、いくつか迂回策があります。

おすすめの解決策としては、「ページ内リンク専用の要素を追加する」です。

解決策1ページ内リンク専用の要素を追加する

[1-1] 対象をspan 要素で囲む

一段内側にインライン要素を追加し、その要素に対してリンクすることで、解決します。

<!-- 例1:spanでテキストを囲む。span のピッタリ上がジャンプ位置になる。 -->
<h1>
  <span id="link-1">ここにいるよ〜。</span>
</h1>

上記ですと、span 要素のピッタリ上にブラウザの上端が来るようにジャンプします。

[1-2] 兄弟 span 要素を絶対配置

上記と似ていますが、こちらの方法はスクロール位置(オフセット)を柔軟に対応できます。

対象の親要素(下記だとH1)内にリンク用の span 要素を追加、かつ、position: absolute を指定して、絶対座標を指定することで、オフセット(ジャンプ位置をどの方向に、どのくらいずらすか)を指定できます。

span 要素自体の大きさはゼロですので、レイアウトに影響しません。下記の例では、いちおう visibility: hiddenで視覚的にも表示されないようにしています。

<!-- 例2:spanをテキストの直前に挿入。絶対配置でオフセットを調整 -->
<h1>
  <span id="link-2" class="ex2"></span>ここにもいるよ。
</h1>


<style>
h1{
 position:relative;
}

/* top プロパティの値で、オフセットを設定できます。*/
h1 .ex2{
 position:absolute;
 visibility:hidden;
 top:-30px;
}
</style>

セマンティック(文書の意味的な)な観点で、「意味のない要素を追加する」のはすこし気が引けますし、HTMLも汚れる、言ってしまえばハックなのであまりおすすめはしませんが、どうしても手早く直したい時は使えると思います。

なるほど、こなれたCSSの使い方だね。。

解決策2jQuery 関数 animate を利用する

さて、ここからは中級編ですが、jQuery の利用経験があれば、それほど難しくないでしょう。

もし既存のページが jQuery を利用しているのであれば、この方法の導入は容易です。jQuery を利用しますので、セレクタは id 属性でなくても構いません。

<h1 class="target">ここにもいるよ。</h1>

<script>
// 匿名関数で、スコープを限定(変数名の衝突防止)
(function(){

  // スクロール先の上辺の縦(下方向)の座標
  var targetTop = $('.target').offset().top;

  // ずらしたいY軸方向の値。
  var OFFSET = 100;

  // ページ内の対象要素へジャンプ。OFFSETの分だけ減らす
  $(window).scrollTop( targetTop - OFFSET ); 

})();
</script>

当然ですが、scrollTop 関数の第二引数に0 を入れれば、ページトップまでスクロールバックすることができますので、「ページトップへ戻る」として利用できます。

ページ内リンクに、スクロールアニメーションをつける場合

また、animate 関数を利用すれば、スクロールアニメーションを利用できます。jQuery 関数のanimate() は通常はCSSプロパティを記述する使用ですが、追加的に「scrollTop」「scrollLeft」という値を受け付けます。これにより、所望の速度でスクロールを実施できます。

上記の$(window).scrollTop( xxx ); の部分を書きで置き換えます。

$('html, body').stop().animate({scrollTop:targetTop}, targetTop = OFFSET );

$(‘html, body’) の部分がやや奇妙に見えますが、理由として、animate 関数が有効なのは、DOM要素を持つjQuery オブジェクトのみですので、$(window) や$(document) 要素には適応出来ないことがあります。

Chome や Safari は $(‘body’).animte({scrollTop:100}), また、Firefox が$(‘html’).animate({scrollTop:100})と言った別々の記述を受け付けるため、併記する必要があります。

参考リンク:

この方法であれば、要素内部のスクロールもアニメーションで実装できるみたいだね。

解決策3ページ内スクロールのJavascriptプラグインを利用する

こちらは、jQuery ではなく、Javascript を使ったプラグインです。筆者としては、ページ内リンク機能の実現は、こちらのプラグインをおすすめします。

こちらの公開レポジトリからに dist/smooth-scroll,min.js (軽量化版) がありますので、こちらを読み込んでください。

ずれる問題も、「オフセット」という引数を指定することで、簡単に解決できますし、ぬるっとしたスムーズなスクロールしてくれるので、いい感じです。

<!-- HEADタグ内で読み込んで下さい。 -->
<script src="smooth-scroll.min.js"></script>

<script>
var scroll = new SmoothScroll('a[href*="#"]', {
  speed: 500, // 速度
  offset: 100, // オフセット
  easing: 'easeInOutCubic', // アニメーション効果
});

</script>

GitHub上のドキュメントにはいろいろと詳しく書いていますが、基本的な動作させるにはそんなに難しくないので、javascriptはちょっと・・、という方も、おすすめします。

smooth-scroll プラグインは、その他の javascript ロジックと分離して記述できるから、サクッと追加しやすいね。おすすめだよ。


以上です。