ページ内リンク(アンカー)に失敗する時の対策

部品の使い方や応用ノウハウ
アバター
yama
管理人
記事: 2873
登録日時: 2009年7月29日(水) 02:50

ページ内リンク(アンカー)に失敗する時の対策

投稿記事by yama » 2010年5月07日(金) 23:37

小さなTips的な内容を蓄積してみたいと思います。まずは何からと考えましたが、とりあえずこのネタで。

最近は減ったのではと思いますが(※そう思う理由は後述)、MODxでページを組む時、ページ内のリンクがなぜか機能しなくて困るというケースが多かったのではと思います。昔から継続してMODxを利用している人だと、今でも困っているかもしれません。

http://modxcms.com/forums/index.php?topic=29405.0
だいぶ前の話ですが、たとえばこちらで話題になっています。

コード: 全て選択

<a name="ref">

上記のようにアンカーを設定したとして、

コード: 全て選択

<a href="#ref">ジャンプ</a>

このようにリンクを張って、クリックしたら該当するポイントにジャンプする。はず。しかしなぜか、MODxで作ったページに限ってジャンプしません。htmlをいくら見直しても間違ってないのに期待どおりに動かず、気味悪く感じられます。

http://modxblog.com/resource/item/base_url_same-page-link_fix/
「Base URL Same-Page-Link Fix」プラグインをインストールすれば解決。ということになっています。しかし、このプラグインの存在を難なく探し当てられる人はそう多くないように思います。

この件に関してカラクリを解説した記事は特に見当たらないのですが、理屈は簡単です。MODxがいくら高機能だといっても、ページ内リンクを動的に阻害するような高度な仕掛けがあるわけではありません。実はこの問題は、html的には仕様に沿っています。

MODxはもともと相対パス設定がデフォルトになっていて、それはいいのですが、CMSとしてコンテンツをコントロールする以上、そのコンテンツを呼び出すページのコンテンツがどのディレクトリ階層に属していても、画像やページに対してリンクを正しく維持する必要があります。相対パスで記述しているのに、MODxではなぜそんなことが可能なのかというと、head要素内でbaseタグを記述しているからです。このbaseタグのおかげで、サイト内のあらゆるページにおいて、相対パス記述に対して絶対的な基準を持たせることができます。たとえばDittoを使う場合、上の階層から各記事に対してリンクを張ったりします。それでも画像などはリンク切れを起こさずに表示されるのはbaseタグで絶対的な基準を設定しているおかげ。つまり、見た目は相対パスですが実態は絶対パスなのです。このbaseタグ、扱いに慣れない人も多いのではないでしょうか。

baseタグの記述によりどういうことが起きるかというと、

コード: 全て選択

<base href="http://example.com/" />

このように指定したとして、先ほど挙げた例で言うと、

コード: 全て選択

<a href="#ref">ジャンプ</a>

上記のリンクは http://example.com/#ref に接続しようとするのです。該当ページのURLがhttp://example.com/page.html だったとすると、当然ながら想定どおりのジャンプができません。

プラグイン「Base URL Same-Page-Link Fix」をインストールすると、このリンクは

コード: 全て選択

<a href="http://example.com/page.html#ref">ジャンプ</a>

このように動的に書き換えられるため、正しくページ内リンクが働きます。

それでちょっと議論はあったのですが、MODx日本語版(というよりTinyMCEの設定)ではデフォルトの設定を絶対パスとしています。そのため、baseタグを記述しなくても画像やページに対して正しくリンクを張ることができるようになっています。baseタグは理屈を理解していれば論理的・合理的な使いこなしができるため便利なのですが、MODxの基本的な使い方を習得するだけで精一杯の人にとっては余計な落とし穴になりかねません。ある程度慣れてきたら、baseタグの採用を検討していただければと思います。

MODxのシステム自体は、現時点では、たとえばリンクタグ[~id~]を記述した場合は相対パスのみを出力するようになっています。これを絶対パスにしたい場合は先頭に「/」や[(site_url)]などを追加する必要があり、実は絶対パスはMODx的にはあまり美しくありません。将来的には改善されるかもしれませんが、今のところ予定はありません。

MODx0.9.2あたりまでは、baseタグはシステム側で強制的にテンプレートに挿入される仕様になっていました。MODxはその性格上、既存の静的htmlサイトのファイルからインポートして移行するようなケースが多かったと思いますが、この場合、画像のパスなどは相対パスで取り込まれることが多いです。MODxのファイルブラウザの既定のディレクトリは/assets/images/になっているので、苦肉の策としてこのような縛りが生まれたとも考えられます。

昔からMODxを使っている人だと、baseタグを記述していないと最初から困るので、MODxではbaseタグは必須と覚えている人も多いと思います。
sama55
メンバー
メンバー
記事: 816
登録日時: 2009年8月03日(月) 08:16

Re: ページ内リンク(アンカー)に失敗する時の対策

投稿記事by sama55 » 2010年5月08日(土) 07:53

なるほど。 そんな経緯があったですか。
Base URL Same-Page-Link Fix は自分も知りませんでした。
アバター
yama
管理人
記事: 2873
登録日時: 2009年7月29日(水) 02:50

Re: ページ内リンク(アンカー)に失敗する時の対策

投稿記事by yama » 2010年5月08日(土) 08:21

今思いつきましたが、Base URL Same-Page-Link Fixを導入するまでもなくジャンプ元を絶対パスで書けば解決ですよね。

コード: 全て選択

<a href="http://example.com/page.html#ref">ジャンプ</a>
こうなればいいので、

コード: 全て選択

<a href="#ref">ジャンプ</a>
こう書いてうまくいかないところを

コード: 全て選択

<a href="[(site_url)][~id~]#ref">ジャンプ</a>
たぶんこれでいいですよね?
sama55
メンバー
メンバー
記事: 816
登録日時: 2009年8月03日(月) 08:16

Re: ページ内リンク(アンカー)に失敗する時の対策

投稿記事by sama55 » 2010年5月08日(土) 08:58

yama さんが書きました:

コード: 全て選択

<a href="[(site_url)][~id~]#ref">ジャンプ</a>
たぶんこれでいいですよね?

こう ↓ かな?

コード: 全て選択

<a href="[(site_url)][~[*id*]~]#ref">ジャンプ</a>

これが面倒なんですよ・・・あちこち入れないといけないから。  :lol: