開閉するボックスを作る(HTML/CSS/JS)
前書き
開閉するボックス(アコーディオン)の作り方を掲載しています。
目次
- 開閉する
- スマホサイズの時だけ開閉する
- 隣合わない要素を開閉する
- jQueryを使わずに要素を開閉する
- detailsタグで開閉する
- 参考
開閉する
例
シンプルに開閉させます。
-
質問1
答え1
-
質問2
答え2
<ul>
<li class="list">
<div class="question question-a" data-question_a>
<p class="question-text">質問1</p>
</div>
<div class="answer answer-a" data-answer_a>
<p class="answer-text">答え1</p>
</div>
</li>
<!-- 2つ目省略 -->
</ul>
//各見本共通
.list{
padding:1em 0; border-bottom: 1px solid #ccc;
&:nth-of-type(1){
border-top: 1px solid #ccc;
}
}
.question{
position: relative; cursor: pointer;
&::before{
position: absolute; top: 1em; right: 1em; content: "+";
}
&.active{
&::before{
content: "-";
}
}
}
.question-text,
.answer-text{
position: relative; padding: 1em 3em;
&::before{
position: absolute; top: 0.875em; left: 0; width: 2em; height: 2em; line-height: 2;
font-weight: bold; text-align: center; border-radius: 50%;
}
}
.question-text{
&::before{
content:"Q"; color: #fff; background: #845080;
}
}
.answer-text{
&::before{
content:"A"; background: #e7d4e3;
}
}
//個別設定
.answer-a{
display: none;
}
$("[data-question_a]").on("click",function(){
const question = $(this);
const answer = $(this).next();
question.toggleClass("active");
answer.slideToggle(200);
});
スマホサイズの時だけ開閉する
例
スマホサイズの時だけ開閉させます。PCサイズの時は開けたままにします。
-
質問1
答え1
-
質問2
答え2
<ul>
<li class="list">
<div class="question question-b" data-question_b>
<p class="question-text">質問1</p>
</div>
<div class="answer answer-b" data-answer_b>
<p class="answer-text">答え1</p>
</div>
</li>
<!-- 2つ目省略 -->
</ul>
//個別設定
.question-b{
@media screen and (min-width: 768px)
cursor: default;
&::before{
display: none;
}
}
}
.answer-b{
display: none;
@media screen and (min-width: 768px)
display: block;
}
}
$("[data-question_b]").on("click",function(){
const ww = window.innerWidth;
const question = $(this);
const answer = $(this).next();
if(ww < 768){
if( question.hasClass("active")){
question.removeClass("active");
answer.slideUp(200,function(){
//スライドアップしたら、style属性のdisplay:noneを消す
answer.css({'display':''});
});
}else{
question.addClass("active");
answer.slideDown(200);
}
}
});
隣合わない要素を開閉する
例
data属性の値が一致する要素を開閉します。
-
質問1
答え1
-
質問2
答え2
<ul>
<li class="list">
<div class="question question-c" data-question_c="1">
<p class="question-text">質問1</p>
</div>
<div class="answer answer-c" data-answer_c="1">
<p class="answer-text">答え1</p>
</div>
</li>
<li class="list">
<div class="question question-c" data-question_c="2">
<p class="question-text">質問2</p>
</div>
<div class="answer answer-c" data-answer_c="2">
<p class="answer-text">答え2</p>
</div>
</li>
</ul>
//個別設定
.answer-c{
display: none;
}
$("[data-question_c]").on("click",function(){
const question = $(this);
const num = $(this).data("question_c");
const answer = $('[data-answer_c="' + num + '"]');
question.toggleClass("active");
answer.slideToggle(200);
});
jQueryを使わずに要素を開閉する
例
jQueryを使わない場合は、開いた時の高さをどう取得するか問題になります。
こちらの例では、高さを取得する為だけに、div要素を一つ追加しています。
-
質問1
答え1
-
質問2
答え2
<ul>
<li class="list">
<div class="question question-d" data-question_d>
<p class="question-text">質問1</p>
</div>
<div class="answer answer-d" data-answer_d>
<div data-inner_d>
<p class="answer-text">答え1</p>
</div>
</div>
</li>
<!-- 2つ目省略 -->
</ul>
//個別設定
.answer-d{
overflow: hidden; height: 0;
}
document.querySelectorAll('[data-question_d]').forEach(( question, i ) => {
question.addEventListener('click',function(){
const answer = document.querySelectorAll('[data-answer_d]')[i];
const inner = document.querySelectorAll('[data-inner_d]')[i];
let active = false;
if(!active){
const timeStart = Date.now();
const timeTotal = 200;
const heightBefore = answer.offsetHeight;
const heightMax = inner.offsetHeight;
let heightAfter;
if( heightBefore == 0 ){
question.classList.add("active");
}else{
question.classList.remove("active");
}
const answerToggle = ( progress ) => {
if( heightBefore == 0 ){
if( progress > 1 ){
heightAfter = "auto";
}else{
heightAfter = heightMax * progress + 'px';
}
}else{
if( progress > 1 ){
heightAfter = "";
}else{
heightAfter = heightBefore * ( 1 - progress ) + 'px';
}
}
answer.style.height = heightAfter;
}
const tick = () => {
const progress = ( Date.now() - timeStart ) / timeTotal; //経過率
answerToggle( progress );
if( progress < 1 ){
active = true;
requestAnimationFrame( tick ); //繰り返し
}else{
active = false;
}
}
requestAnimationFrame( tick );
}
});
});
detailsタグで開閉する
例
htmlのdetailsタグを使っています。二つ目のタグにはopen属性を記載しています。
質問1
答え1
質問2
答え2
<details>
<summary>質問1</summary>
<div class="details-text">答え1</div>
</details>
<details open>
<summary>質問2</summary>
<div class="details-text">答え2</div>
</details>
details{
padding:1em 0; border-bottom: 1px solid #ccc;
&:nth-of-type(1){
border-top: 1px solid #ccc;
}
}
summary{
outline: none; cursor: pointer;
}
.details-text{
padding: 0 0 0 1em; margin: 1em 0 0;
}
参考
CSSすら不要!detailsとsummaryタグで作る簡単アコーディオン
関連記事
この記事は役に立ちましたか?
送信中