aタグにpreventDefault()やreturn falseが効かない
画像の拡大表示などのスクリプトで、よくaタグ(リンクタグ)に対してイベントを設定することがあります。
そうした仕様の場合、元々のクリックイベントである「リンク」が作動しないように「元々のイベントをキャンセルする」ということが必要になります。
こういったケースの際、よく用いられるのがタイトルにある
- preventDefault
- return false
の2つです。
これらのメソッドや文の細かな説明は今回省かせていただきますが、
このいずれかをJavaScriptで記述すると元々のイベント(今回はリンク)がキャンセルされ
htmlタグに記述されているリンク先へ飛ぶことはありません。
…しかし、これらのどちらを入れても、両方記述したとしても(注:無意味です。苦笑)リンクがキャンセルされず
リンク先へ飛んでしまう、という事例がありました。
というか、このブログで(おそらく)結構な期間起きていました。。
それが今回のお話しです。
書いているうちにどんどん冗長になっていったので、結論から先に言います。
キャンセル処理より後に、別でクリックやタッチイベントを設定している為(再定義してしまっている)
(※このブログでは「User Heat」のヒートマップ解析をサイトの一番最後に読ませた為、自前のJSで設定したクリックイベントが全部書き換わっていた)
です。
※詳細は後述。
このブログで出ていた症状
- 画像の拡大表示をクリックすると、リンク先へ飛ぶ
- aタグ(リンクタグ)のpreventDefaultとreturn falseがすべて効かなくなっている
- +SNSへのシェアボタンがすべて効かない
初めて気づいたのは今月の頭くらい、ライトボックス(画像の拡大表示)プラグインの修正をしてサーバーへアップロードした時のチェックの際でした。
画像をクリックすると、途中まで拡大アニメーションが起こるのですが その後でaタグのhref(リンク先)に指定していた画像ファイルへジャンプしていました。
調べていくと、どうもaタグ全部のイベントキャンセルが効いていないことが分かった。
例えばReportトピックスの画面上部にはナビが固定で付いていますが、サブナビゲーションがある項目はカーソルオンでサブナビゲーションが展開するようになっています。(画像の上部「Topics」部分など)
例えここをクリックしたとしても何も起きないようにリンクイベントをキャンセルしていたのですが、 ここをクリックしてもURLに「#」が入る。(リンクイベントが生きている)
通常、こうした「プログラムした本来そうなるべき動作」にならない時は、書いたプログラムのどこかで何かしらエラーが出ているのがほとんどのパターンです。
なので、こうした「インスペクタ」や「デベロッパーツール」を使用してエラーの箇所を見つけます。 画像はFirefox(Developer Edition)のインスペクタ。
エラーが出ていれば、2つ目の画像のようにインスペクタ下部の「コンソール」にエラーの内容と、エラーが発生しているファイルの行を表示してくれます。
しかし、どのブラウザでチェックしようとも、エラーが出てきません。
つまるところ、「僕が設定したプログラムは正常に動作している」ということ。(狙った通りになっているかいないかは別として、「書いてある通りには動作している」という意)
謎が謎を呼ぶ謎症状
しかも、更に謎を深めたのが、これは開発環境では起こらず
また、同じスクリプトを使った別のサイトでも起こらなかったのです。
さらにはChrome、Safariではこの症状が出るものの、Firefofxではきちんとリンクはキャンセルされるという事態。
あれこれスクリプトを調査してみても全く原因が分かりませんでした。
試しにcssでaタグに対して「pointer-events:none」(cssでのクリックイベント無効)も行ってみたところ Firefoxでは拡大表示のスクリプトそのものも無効になりましたが、 なんと、Chrome、Safariではそれでもリンク先へ飛ぶ…
ということは、このイベントキャンセル後、aタグに対して「何らかのイベントが新たに設定されてしまった」と考えられる。
しかし、そんな動作をするプログラムは思い当たらず(※)あまり時間もなかったので一旦放置していました。。
…しかし、このpreventDefaultとreturn falseによるイベントキャンセルが書かれているスクリプトはhtmlの一番最後に読ませている。これより後に読み込まれるスクリプトなんて……?
もう一つの原因不明のエラー
そんな中、この間久しぶりにブログを書いたのでシェアしようと思って、シェアボタンを押すと……「エラー」
100歩譲って、画像拡大がリンクページなのはまだ目をつぶれる(クライアント様のじゃないし!そういう仕様のブログいっぱいあるし!)←製作者としてダメ
とまだ悠長にしていましたが、この間書いたブログが「アシスタントさん募集」という記事だけに「何コイツ、こんなウデしかないの?」と思われるのはちょっと困る。。それに、ここまで重篤なエラーがあってはさすがにいかんだろう、と本腰を入れて対処することにしました。
このエラー、一見今回の話の「preventDefaultとreturn falseが効かない」と関係ないように感じると思います。しかし、実はそうではなく、どちらも同じものが原因となって起こっていたのでした。
原因究明
- 他の環境では正常に動作していることから、ライトボックスプラグインには問題が無いと考えられる
- 別で設定しているreturn falseはおろか、pointer-events:noneすら効かない
- aタグに対しイベントを設定orクリックイベント関係に作用するプラグインは基本「クラス」起動
- こちらが書いたプログラムの後で読み込んでいるのは4つ
ということから
このあたりが怪しいのだろう、と仮定。
Lazyloadプラグインは画像の遅延表示のためのもの、social.jsはソーシャルボタン表示用のスクリプトをまとめただけのもの。scrolldepthはアナリティクス用…となると。。。
ヒートマップ用の一番下のスクリプトが何か悪さをしているのかな…?と。
試しに一度コメントアウトすると……
aタグのリンクキャンセルはもちろん、SNSのシェアボタンも生き返り、普通にすべてが意図していた通りになりました。
まとめ
なんだかんだで非常に時間をかけてしまいましたが、結論としてはやっぱり「使うもののことはしっかり把握しておこう」というこの一言に集約できるかなと思います。
Webサイトやページというものは、「自分以外の方が見るもの」。基本的にエラーやバグは「残していてはいけないもの」なので、見つけたら即改善すべきところではあります。 また、よく分からないエラーやバグというものはつきものではあるだけに、
- 信頼性のあるものを使う
- 内容をよく分かっていないものを置いておかない(使わない)
- 不具合を生みそうな組み合わせならコンフリクト(衝突)しないように修正する
というところがセオリーでしょう。
あとがき
ここまで原因究明に時間がかかったのは、正直「思い当たる節が多すぎた」というところでもあります。苦笑
実を言うと、現在のこのブログの状態は「大きなつぎはぎ入り」なので、細かなバグチェックがまったくできていない状態でした。
というのも、4月頃にリニューアルを考え新テーマを作成していたのですが、本番テストのために仮でこのトピックスだけ新テーマを適用しました。「仮」というだけあって、ファイル構成もfunction.phpの内容も違うテーマを無理矢理入れ込んでいるだけに、ところどころで不具合があります。。
(このテストの後すぐに新テーマに切り替える予定だったのですが…)
そんな折、忙しくなってきてブログを書く時間もなかなかとれず、開発も途中で止めてしまっていて、時間があいてしまったら「やっぱりもうちょっとこんな感じにしようかな…?」なんて欲も出てきて。。。という酷い状態を放置しているので、まぁ、何かしらは起こるよな…という。。
2015年12月末、新テーマへ切り替えました。
これからはもっと自分のものにも気を配り、常にちゃんと整えておいて恥ずかしくないものにしておくようにします。。
Comments