業務上、なんやかんやとまだ使っているjQuery、そしてそれを利用したスムーススクロール。
基本的にjQueryを使ったスムーススクロールだと、以下のような記述をしていると思います。
$(function(){
$('a[href^="#"]').on('click', function(){
var href= $(this).attr('href');
var target = $(href == '#' || href == '' ? 'html' : href);
var position = target.offset().top;
$('html, body').animate({scrollTop:position}, 500, 'swing');
return false;
});
});
大体はこれで動きますし、offset()
も普通に値が取得できると思います。
今回は
- jsでアコーディオン化した要素の中にアンカーリンクとアンカーリンク先がある
- アンカーリンクをクリックするとスムーススクロールで指定のアンカーに移動する
この条件の時にIE11対応で躓いたので、その時の対応を忘れないためのものになります。
今も尚IE11対応してる人の助けにもなったら幸い。(今もIE11対応してる人どれだけいるの?という疑問はともかくとして)
htmlの例としては以下のような感じです。
<dl class="accodion_wrap">
<dt class="accodion_btn">アコーディオン開閉ボタン</dt>
<dd class="accodion_box">
<p>アコーディオンの中身</p>
<ul>
<li>
<a href="#link1">アンカーリンク1</a>
<a href="#link2">アンカーリンク2</a>
<a href="#link3">アンカーリンク3</a>
</li>
</ul>
<div id="link1">
アンカーリンク先1
</div>
<div id="link2">
アンカーリンク先2
</div>
<div id="link3">
アンカーリンク先3
</div>
</dd>
</dl>
アコーディオンの中身が長く、アコーディオンの中にアンカーリンクを入れてほしいとの要望があったのでアンカーリンクを挿入したら、アコーディオン内のアンカーリンククリック時にIE11だけ何故かoffset()
の値が取得できず、スムーススクロールが正常に動かなくなってしまいました。
似たような事象と対応例がないか調べてみたのですが見つからず、色々試した結果以下の対応で動作するようになりました。
<dl class="accodion_wrap">
<dt class="accodion_btn">アコーディオン開閉ボタン</dt>
<dd class="accodion_box">
<p>アコーディオンの中身</p>
<ul>
<li>
<a href="#link1" class="js_accordion_anchor">アンカーリンク1</a>
<a href="#link2" class="js_accordion_anchor">アンカーリンク2</a>
<a href="#link3" class="js_accordion_anchor">アンカーリンク3</a>
</li>
</ul>
<div id="link1">
アンカーリンク先1
</div>
<div id="link2">
アンカーリンク先2
</div>
<div id="link3">
アンカーリンク先3
</div>
</dd>
</dl>
$(function(){
$('.js_accordion_anchor').on('click', function(){
var href= $(this).attr('href');
var target = $('.accodion_box._is_open ' + href);
var position = target.offset().top;
$('html, body').animate({scrollTop:position}, 500, 'swing');
return false;
});
});
jsの変数target部分の記述を、アコーディオンを開閉している(displayをblockとnoneで切り替えている)親要素に加え、アコーディオンを開く際に親要素にaddClass()
で追加しているclass(上記記述の場合だと_is_open
)を予め指定して記述することで、offset()
の値が取得できるようになりました。
また、親要素の指定を入れる都合上、アコーディオン外にアンカーリンクがある場合、そのアンカーリンク+スムーススクロールが正常に動作できなくなってしまうので、アンカーリンクのイベント発火をclass指定にしています。
なお、この対応を入れる場合、アコーディオン外のスムーススクロール用記述に関しては以下のように記述を変えた方が良いです。
$(function(){
$('a[href^="#"]:not(".js_accordion_anchor")').on('click', function(){
var href= $(this).attr('href');
var target = $(href == '#' || href == '' ? 'html' : href);
var position = target.offset().top;
$('html, body').animate({scrollTop:position}, 500, 'swing');
return false;
});
});
色々試してみるうちにこの方法に辿り着き、問題解消できた訳ですが、この方法で何故有効になっているのか、理由というか理屈はわかっていなかったりします。
読み込み時に非表示状態(display: none;
にしている)のアコーディオン部分に入っているから取得できないのか…?
display: none;
のとき要素のサイズが取得できない理屈と同様なのだろうか…?
(でもアコーディオンを開いてリンクをクリックする訳で、その時にはdisplay: block;
になっているのですが…)
とは色々考えているのですが、ChromeとかEdgeではこの対応をしなくても普通に取得できているんですよね…。
このあたり、もしわかる方がいたら教えていただけると幸いです。
…それにしても、IE11対応から解放される日はいつになるのやら。
(以前ここに書いた記事も、IE11対応に泣かされた記事である事に気付いて頭を抱える)