【jQuery】アコーディオン、エリア外からのアンカーでアコーディオンが開く、そしてアンカー場所へ移動する。
- 更新
- デザインのメモ


あのー、アンカーリンクのボタンを押したらアコーディオンが開いてその中にあるアンカーリンクの場所にスルスルーと移動させたいのですが可能ですかね?

なんだかややこしそうですが、やってみましょうかー
さっそく実装してみる
コードを見る(HTML・CSS・jQuery)
HTML
<section class="section">
<div class="anchor">
<ul>
<li>
<a href="#anchor1">アンカー1へ</a>
</li>
<li>
<a href="#anchor2">アンカー2へ</a>
</li>
<li>
<a href="#anchor3">アンカー3へ</a>
</li>
</ul>
</div>
<button class="more" type="button" aria-expanded="false">もっとみる(アコーディオン)</button>
<div class="one-detail hide">
<div class="one-body" id="anchor1">
<p>アンカー1</p>
</div>
<div class="one-body" id="anchor2">
<p>アンカー2</p>
</div>
<div class="one-body" id="anchor3">
<p>アンカー3</p>
</div>
</div>
</section>
CSS
絶対に必要なものだけ記載しておきます。デザインはおまかせしますー。
/* 見本そのもの(これだけは必要) */
.hide {
display: none;
}
/* ここから下は見た目(なくても動きます) */
/*=========
.anchor
=========*/
.anchor ul {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
list-style-type: none;
margin: 0 0 100px;
padding: 0;
box-sizing: border-box;
}
.anchor ul li {
width: calc(100% / 3);
border-right: 1px solid #fff;
text-align: center;
box-sizing: border-box;
}
.anchor ul li:last-child {
border-right: none;
}
.anchor ul li a {
display: block;
padding: 10px;
text-decoration: none;
color: #fff;
font-size: 16px;
background: #2b2a27;
border: 1px solid #2b2a27;
transition: .3s;
}
.anchor ul li a:hover {
color: #2b2a27;
background: #fff;
}
/*=========
.more
=========*/
.more {
display: block;
width: 100%;
font: inherit;
color: #fff;
font-size: 16px;
text-align: center;
background: #2b2a27;
border: 1px solid #2b2a27;
padding: 10px;
cursor: pointer;
transition: .3s;
}
.more:hover {
color: #2b2a27;
background: #fff;
}
/*=========
.one-detail
=========*/
.one-detail {
border: 1px solid #2b2a27;
background: #f3efe6;
padding: 30px;
}
.one-body {
margin: 0 0 100px;
}
.one-body p {
font-size: 16px;
margin: 0;
}
/* 動きを減らす設定のとき(jQuery の動きは <script> の $.fx.off で止める) */
@media (prefers-reduced-motion: reduce) {
.anchor ul li a,
.more { transition: none; }
}
jQuery
一行解説したいところですが、ざっくり説明すると、スルスルーとスクロール設定、待機設定、アコーディオン設定、アンカーからのアコーディオン設定、をしています。
$(function(){
// 動きを減らす設定のときは、jQuery の動きを止める
$.fx.off = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
//scrollTo
function scrollTo(_target, _offset){
var
_f = true,
_s = 500,
_t = 0;
if(_target && _target.length){
try{
_t = _target.offset().top;
}
catch(e){
_f = false;
}
}
if(_offset !== undefined){
_t = Math.max(0, _t + _offset);
}
if(_f){
$('body, html').animate({scrollTop: _t}, _s, 'swing');
}
}
//wait
$.wait = function(msec) {
var d = new $.Deferred;
setTimeout(function(){
d.resolve(msec);
}, msec);
return d.promise();
};
//more
$('.section').find('.more').on('click', function(){
var _p = $(this).closest('.section');
_p
.toggleClass('is-open')
.find('.one-detail').slideToggle(250);
// 開いているかどうか(aria-expanded)を切り替える
$(this).attr('aria-expanded', _p.hasClass('is-open'));
if(_p.hasClass('is-open')){
$.when(function(){
return $.wait(100);
}())
.then(function(){
scrollTo(_p.find('.one-detail'), -48.8);
});
}
return false;
});
//anchor + open
$('.section').find('.anchor').find('a').off().on('click', function(){
var
_p = $(this).closest('.section'),
_target = $($(this).attr('href')),
_wait = 300;
if(_p.hasClass('is-open')){
_wait = 100;
}
_p
.addClass('is-open')
.find('.one-detail').show();
_p.find('.more').attr('aria-expanded', 'true');
$.when(function(){
return $.wait(_wait);
}())
.then(function(){
scrollTo(_target, -0);
});
return false;
});
});
メモ
jQueryのことで何かわからないことがあればjQueryの日本語リファレンスサイトがあるので一度チェックしてみるのをおすすめします。
さいごに

おー、これですー

なかなかややこしかったですねー。さ、甘いもの食べに行きましょうー



