<details class="js-details">
<summary class="js-summary">
<span class="summary_inner">
概要<span class="icon"></span>
</span>
</summary>
<div class="content js-content">
<div class="content_inner">折りたたまれている部分です。</div>
</div>
</details>
<details class="js-details">
<summary class="js-summary">
<span class="summary_inner">
概要<span class="icon"></span>
</span>
</summary>
<div class="content js-content">
<div class="content_inner">折りたたまれている部分です。</div>
</div>
</details>
<script>
'use strict';
{
document.addEventListener('DOMContentLoaded', () => {
setAccordion();
});
const setAccordion = () => {
const details = document.querySelectorAll('.js-details');
const RUNNING_VALUE = 'running';
const IS_OPENED_CLASS = 'is-opened';
details.forEach(element => {
const summary = element.querySelector('.js-summary');
const content = element.querySelector('.js-content');
summary.addEventListener('click', event => {
event.preventDefault();
if (element.dataset.animStatus === RUNNING_VALUE) {
return;
}
if (element.open) {
element.classList.toggle(IS_OPENED_CLASS);
const closingAnim = content.animate(
closingAnimKeyframes(content),
animTiming
);
element.dataset.animStatus = RUNNING_VALUE;
closingAnim.onfinish = () => {
element.removeAttribute('open');
element.dataset.animStatus = '';
};
} else {
element.setAttribute('open', 'true');
element.classList.toggle(IS_OPENED_CLASS);
const openingAnim = content.animate(
openingAnimKeyframes(content),
animTiming
);
element.dataset.animStatus = RUNNING_VALUE;
openingAnim.onfinish = () => {
element.dataset.animStatus = '';
};
}
});
});
};
const animTiming = {
duration: 400,
easing: 'ease-out',
};
// 閉じる
const closingAnimKeyframes = content => [
{
height: content.offsetHeight + 'px',
opacity: 1,
},
{
height: 0,
opacity: 0,
},
];
// 開く
const openingAnimKeyframes = content => [
{
height: 0,
opacity: 0,
},
{
height: content.offsetHeight + 'px',
opacity: 1,
},
];
}
</script>
<style>
summary {
display: block;
}
summary::-webkit-details-marker {
display: none;
}
.summary_inner {
cursor: pointer;
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
padding: 16px 24px;
border: 1px solid #d2beff;
font-weight: bold;
color: #002255;
}
.icon {
display: block;
position: relative;
width: 24px;
margin-left: 6px;
flex-shrink: 0;
transform-origin: center 43%;
transition: transform 0.4s;
}
details.is-opened .icon {
transform: rotate(180deg);
}
.icon::before,
.icon::after {
content: '';
position: absolute;
display: block;
width: 15px;
height: 3px;
background-color: #7050ff;
}
.icon::before {
left: 0;
transform: rotate(45deg);
}
.icon::after {
right: 0;
transform: rotate(-45deg);
}
.content {
overflow: hidden;
background-color: #f0f2ff;
}
.content_inner {
padding: 24px 48px;
display: flex;
flex-direction: column;
gap: 16px;
}
</style>