ページ内スクロールと開閉プラグインの衝突

特定環境下で衝突するんですよ (´・ω・`)
特定というと狭い範囲のように思いますが、広範です。

条件

  • HTML5テンプレート を利用している
  • 開閉プラグインが開閉トリガーに aタグ を用いている
  • テンプレートにページ内スクロール(スムーススクロール)が導入されている

この条件が重なった時ですね。

挙動

  • 開閉ボタンをクリックすると ページ最上部にスクロールしてしまう

この原因と対策についてです。

その前に、上記とは異なる挙動の場合もありますよね。初期状態で閉じているべきものが開いている(クリックも効かない) 逆もまた然り。こちらについてはまた別の原因ですので以下の記事を参照のこと。

FC2ブログプラグインの動作確認をお願いします【あなたのプラグインが動かない理由】

FC2ブログプラグインの動作確認をお願いします【あなたのプラグインが動かない理由】

FC2ブログには プラグイン というのが用意されていますよね。 主にサイドメニュー部に簡単設置できて便利。 そして多種多様なものがあります。 中でも展開型プラグインは人気が高いような気がします。 アーカイブやコメントなどを 折りたたむ系 ですね。 公式プラグインというのはJS(Javascript じゃばすくりぷと)を極力使わない というのが制作理念のようです。 従って大変シンプルなものが多い。 一方、有志ユーザーさ...

変わってしまった aタグ の仕様

a(アンカー) というhtmlタグですが、html4からhtml5に移行するにあたり仕様が変更されています。

  • name属性の廃止
  • ダミーリンク(空リンク)の使い方変更

他にもありますが、今回の件に大きく関わる内容は上記2つです。

name属性廃止

html4時代の ページ内リンク というのは以下のようなことをしていたんですね

出発点

<a href="#jump">クリックすると移動します</a>

到達点

<a name="jump">ここが目的の位置です</a>

ページ遷移ではないですよ。ページ内移動 です。念のため。到達点の要素に対し、name属性を用いて目的地名称とします。それが旧式です。

現在ではどうするかというと

出発点

<a href="#jump">クリックすると移動します</a>

到達点

<div id="jump">ここが目的の位置です</div>

出発点の方の書き方は同じです。到達点の方が違います。html5では name属性が廃止 されているのと、到達点を a として設置する必要も無し になっているのですね (´・ω・`)
目的地名称はaタグのname属性を利用するのではなく、各要素のid名を利用するという形に変更されています。というのは、idを目的地名称とした場合にはaタグでのマークアップに限定される不都合が無いわけです。例えば「見出し」のマークアップは <hx>(xは1〜6までの数字) ですよね。じゃあそこへ飛ばすために見出しを <a> としてマークアップするの?ってことになります。それはどう考えてもセマンティックではないですよね。html5の理念というのは セマンティクス ですので、理に適っていない定義は軒並み廃止や変更が行われています。

そもそもページ内リンクの方法がhtml4とhtml5では 違う

というのがまずひとつ。

ダミーリンク(空リンク)の使い方も変更されている

空リンク(ページ遷移なし、移動なし)というのはどういう時に使うかというと、html4時代はそれこそ 開閉スイッチ に用いたり。別の言い方をすると プレイスホルダー (place holder)。
こんな感じ

<a href="#">クリックすると開閉します</a>

ページ遷移も移動もさせず、スイッチとして利用する。html5ではもうそういうことはしません。ダミーが必要な場合には

<a>クリックすると開閉します</a>

これでOK。
というよりもスイッチにaタグを用いる必要すらありません。<button> とかがありますから、わざわざ定義を曲げてまで <a> を使う理由はどこにもありません。

html4に於いては href属性が必須 でしたので、書かなきゃ仕方がなかったんですね。不要でも。その旧仕様が諸悪の根源です

スムーススクロールとの衝突

ページ内で移動する際にスルスル〜っと動くアレです。何故このスムーススクロールが必要かというと、ページ内移動の際に何らかの動きが無いと、閲覧者は何が起こったかわかりにくいんですね。いきなりバッとページ最上部やら最下部にやら移動させるよりも、滑らかにページ全体が動く様子を見せることで「ページ内で移動している = ページ遷移ではない」というのがわかりやすいわけです。専門家の中には「ページ内移動自体するべきではない。」とする方も居て。
その理由は「ページは遷移するのが当たり前だ。していないとなると閲覧者が困惑する。」といった感じ。困惑させないためのスムーススクロールです。見た目にかっこいいとかそういうのももちろんありますが、それが第一目的ではありません。

スムーススクロールを実装するにあたり、JSコード内に通常は以下のような記述が含まれます。

a[href^="#"]

緑の #
ハッシュ あるいは フラグメント と読みますが、この記述の意味というのは「id名がついていたら」です。html5の到達点というのは要素のidで示しますが、id名というのはコードを書いた人間が任意でつけますので特定ができません。ですから「id名への移動(ページ内移動)がある場合は全て」という形にせざるを得ないんです。
#hoge
かもしれないし、
#top
かもしれないし、
#bottom
かもしれない。それはわかりませんが、以下のようにフラグメントへの移動が示されたら

<a href="#hoge">クリック</a>

スムーススクロールを起動させてください、という意味です。で、既におわかりの通り、html4時代の開閉プラグインというのは大抵

<a href="#">クリック</a>

こうしてaタグをトリガーにし、必須属性のhrefの値を「空」のつもりで#
これが スムーススクロールの動作条件に含まれてしまう わけです。

対処法

「どうして」の原因がおわかり頂けたと思いますので、今度は「どうするか」の対処について。

スムーススクロールを削除する

ページTOPやらのボタンなどそもそも要らないんだ、という方はですね、scriptを削除してください。scriptを削除しても移動自体は行なえます。行えはしますが、押した瞬間にバっと移動してしまいますので味気ないのと(ry
この処理はテンプレート側で行います。

スムーススクロール対象を限定的にする

テンプレート製作者次第ですが、大抵の場合にはみなさんが記事内で使用できるようにコードが組まれています。正しいhtmlを書きさえすれば記事内でスムーススクロールを利用することが可能です。JSを書く必要はありません。「記事内で使うことなんて絶対にない!」と言い切れる方は、対象要素を限定してください。ページTOPへのスムーススクロールだけが必要ならば

$('a[href^="#"]')
緑の部位を
$('a[href^="#top"]')

と、こんな風に特定id名を入れます。「#top と書け」という意味ではないですよ。top の部分は移動対象になるid名を入れてください。それはテンプレート毎にまちまちですからここで「こう書け」とは言えません。各々ちゃんと調べて入れる、と。移動対象が複数あるならば

$('a[href^="#abc"],a[href^="#xyz"]')

こうしてカンマ区切りで指定。この処理はテンプレート側で行います。

対象プラグインをスムーススクロール除外指定

対象プラグインの衝突しているaタグにid名をつけます。はじめから付いている場合にはそれをそのまま利用します。

例)

<a href="#" title="OPEN" onclick="xxxxx;return false;">クリック</a>

xxxxxの部位は不特定の文字列です。
大体はこんな感じになっているのではないかと思います。
上記内容、現時点ではid名がありませんので追加します。

<a id="hoge" href="#" title="OPEN" onclick="xxxxx;return false;">クリック</a>

この作業はプラグイン側で行います。その上でテンプレート内のスムーススクロールのコードを

$('a[href^="#"]:not(#hoge)')

こうして除外する。対象が複数あるのならば

$('a[href^="#"]:not(#hoge):not(#hoge2)')

こうして :not() で繋げます。id名は 単一 指定しかできませんので対象が複数あるならばそれぞれにid名を付けてください。idでなくclassにすれば一括指定はできますが、ここでは強制力の強いid名をおすすめします。

この処理はプラグイン側 + テンプレート側 双方の作業です。

まとめ

簡易的な修正は上にまとめた通りです。私のおすすめはどれかというと、どれも該当しません。最善策は html5に準拠したものを使う ことです。

コメントに関する注意事項
  • テンプレートに関するご質問は各テンプレート専用記事でのみ受付致します。また、よくある質問をまとめているページも事前にご参照ください。
  • 専門的なご質問の場合、記事内容と明らかに関連の無い内容はお控えください(雑談の場合はその限りではありません)
  • 第三者が不快と感じる内容や論調でのコメントはお控えください(性的,高圧的,暴力的など)