【便利】detailsとsummaryタグ【覚書】
便利なタグですよね。
アコーディオンがこれだけで実装できるわけですから!
ただ、動きがちょっとねぇ、と思ったりする場合もあるかなと思うので、実際に使ったものを。
HTML
<details>
<summary><h4><span>精霊の力</span></h4></summary>
<div class="details-inner">
<p>精霊は生まれ持った基礎力(単位:エコル)を持ち、人間でいう体力のようなもの。一般的な精霊は完成形で生まれるため成長せず、基礎力は100~150エコルほど。稀に200エコルに達する精霊は精霊王候補となる。リーフは成長するために生まれた特別な精霊で、テラと出会った頃には200エコルほどあったが、これは自身に枷を掛けていた状態であり、実際の力はその倍。リーフは守り人との血の契約で力がさらに何倍にもなる。</p>
</div>
</details>
SCSS
details {
position: relative;
overflow: hidden;
transition: height 0.5s ease;
summary {
cursor: pointer;
display: block;
padding-bottom: 1.5rem;
&::-webkit-details-marker {
display: none;
}
h4 {
position: relative;
margin-bottom: 0 !important;
&:hover {
color: $hrborder;
}
&::before {
content: "+";
display: inline-flex;
align-items: center;
justify-content: center;
height: 2rem;
width: 2rem;
font-size: $font-size-base;
line-height: $line-height1;
transition: transform 0.2s ease;
transform-origin: center center;
}
}
}
&[open] {
summary {
h4 {
&::before {
transform: rotate(45deg);
}
}
}
}
}
JavaScript
document.querySelectorAll('details').forEach(details => {
const summary = details.querySelector('summary');
const inner = details.querySelector('.details-inner');
let isAnimating = false;
summary.addEventListener('click', (e) => {
e.preventDefault();
if (isAnimating) return;
isAnimating = true;
if (details.open) {
// 【閉じる時】
details.style.height = `${details.offsetHeight}px`;
requestAnimationFrame(() => {
requestAnimationFrame(() => {
details.style.height = `${summary.offsetHeight}px`;
});
});
const onTransitionEnd = (event) => {
if (event.propertyName === 'height') {
details.removeAttribute('open');
details.style.height = '';
isAnimating = false;
details.removeEventListener('transitionend', onTransitionEnd);
}
};
details.addEventListener('transitionend', onTransitionEnd);
} else {
// 【開く時】
const startHeight = summary.offsetHeight;
details.open = true;
requestAnimationFrame(() => {
const endHeight = summary.offsetHeight + inner.offsetHeight;
details.style.height = `${startHeight}px`;
requestAnimationFrame(() => {
details.style.height = `${endHeight}px`;
});
});
const onTransitionEnd = (event) => {
if (event.propertyName === 'height') {
details.style.height = '';
isAnimating = false;
details.removeEventListener('transitionend', onTransitionEnd);
}
};
details.addEventListener('transitionend', onTransitionEnd);
}
});
});
実際に使っているページはこちら。
https://tomisan.com/kizahana/world/
なんだかんだでゴリゴリ書いてますが、便利になったなぁ! と思うこの頃。