バニラJSでステップアコーディオンアニメーションを実装。
Jqueryを使用しないことで軽量で且つどこでも動くフレキシブルなコードを実現。
採用ステップなど、説明としてはサイトに入れておきたいが、長いイメージを持たれたくない時に便利なアニメーション。
HTML
<div class="accordion1">
<ol class="accordion1__items">
<li class="accordion1__item">
<div class="accordion1__itemInner">
<p class="accordion1__txt"><span>STEP01</span>15分ヒアリング</p>
</div>
</li>
<li class="accordion1__item js-accordion1Items">
<div class="accordion1__itemInner">
<p class="accordion1__txt"><span>STEP02</span>日程の調整</p>
</div>
</li>
<li class="accordion1__item js-accordion1Items">
<div class="accordion1__itemInner">
<p class="accordion1__txt"><span>STEP03</span>初回面談</p>
</div>
</li>
<li class="accordion1__item js-accordion1Items">
<div class="accordion1__itemInner">
<p class="accordion1__txt"><span>STEP04</span>面接後に内定</p>
</div>
</li>
</ol>
<span class="accordion1__more js-accordion1Btn">STEP2~を開く</span>
</div>
ポイント!
①<li>の隠すものに全て.js-accordion1Itemsを付与。
②ボタンは<ol>の外に置き.js-accordion1Btnを付与。
CSS
.accordion1__items {
width: 300px;
max-width: 100%;
margin: 0 auto;
position: relative;
list-style: none;
padding-left: 0;
}
.accordion1__item:after {
margin: 20px auto;
display: block;
content: "";
width: 0;
height: 0;
border-right: solid 12px transparent;
border-left: solid 12px transparent;
border-top: solid 10px #8F8F8F;
}
.accordion1__item:last-of-type:after {
display: none;
}
.js-accordion1Items {
/*最初は閉じておく*/
display: none;
opacity: 0;
}
.js-accordion1Btn.is-hide {
/*ボタンが消える時*/
opacity: 0;
}
.accordion1__itemInner {
padding: 20px 5%;
box-shadow: 0 0 6px rgba(0, 0, 0, 0.2);
background-color: #fff;
}
.accordion1__txt {
display: flex;
column-gap: 2em;
}
.accordion1__txt span {
font-weight: bold;
}
.accordion1__more {
display: flex;
align-items: center;
justify-content: center;
border-radius: 100px;
color: #fff;
background-color: #63C560;
width: 150px;
height: 40px;
font-size: 14px;
margin: 20px auto 0;
cursor: pointer;
box-shadow: 0 5px 0 #4E9C4C;
transition: all ease .3s;
}
.accordion1__more:hover {
box-shadow: 0 0 0;
transform: translateY(4px);
}
ここだけは必須記述!
.js-accordion1Items {
/*最初は閉じておく*/
display: none;
opacity: 0;
}
.js-accordion1Btn.is-hide {
/*ボタンが消える時*/
opacity: 0;
}
JS
document.addEventListener('DOMContentLoaded', () => {
const btn = document.querySelector('.js-accordion1Btn');
const items = Array.from(document.querySelectorAll('.js-accordion1Items'));
if (!btn || items.length === 0) return;
const STEP = 300;
const DURATION = 300;
const OPEN_START_DELAY = 80; // ← items側を少し遅らせる(調整用)
const last = items.length - 1;
// 初期テキストを保持(元に戻す用)
const defaultText = btn.textContent;
items.forEach((el) => {
el.style.transitionProperty = 'opacity';
el.style.transitionDuration = `${DURATION}ms`;
el.style.transitionTimingFunction = 'ease';
});
let open = false;
btn.addEventListener('click', () => {
open = !open;
// ★テキスト切り替え
btn.textContent = open ? '閉じる' : defaultText;
if (open) {
// ① ボタンを「即」消す(押し下げが見える前に消す)
btn.style.transition = 'none';
btn.classList.add('is-hide');
// 次フレームで transition を戻す(再表示用)
requestAnimationFrame(() => {
btn.style.transition = '';
});
// ② 次のフレームで全itemsを先に表示して高さ確保(透明のまま)
requestAnimationFrame(() => {
items.forEach((el) => {
el.style.transitionDelay = '0ms';
el.style.display = 'block';
el.style.opacity = '0';
});
// ③ ボタンが消えた後に items を動かし始める
setTimeout(() => {
items.forEach((el, i) => {
el.style.transitionDelay = `${i * STEP}ms`;
el.style.opacity = '1';
});
// ④ 全部出そろったらボタンをふわっと戻す
const total = last * STEP + DURATION;
setTimeout(() => {
if (open) btn.classList.remove('is-hide');
}, total);
}, OPEN_START_DELAY);
});
return;
}
// ----- 閉じる(下→上) -----
items.forEach((el, i) => {
const delay = (last - i) * STEP;
el.style.transitionDelay = `${delay}ms`;
el.style.opacity = '0';
setTimeout(() => {
if (!open) el.style.display = 'none';
}, delay + DURATION);
});
});
});
まるっとコピペでOK!
実際の動き
-
STEP0115分ヒアリング
-
STEP02日程の調整
-
STEP03初回面談
-
STEP04面接後に内定

コメント