1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

アコーディオンの中にスムーススクロールのアンカーリンクを入れた時のIE11対応

Last updated at Posted at 2021-08-29

業務上、なんやかんやとまだ使っている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()の値が取得できず、スムーススクロールが正常に動かなくなってしまいました。

似たような事象と対応例がないか調べてみたのですが見つからず、色々試した結果以下の対応で動作するようになりました。

html
<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>
js
$(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対応に泣かされた記事である事に気付いて頭を抱える)

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?