普通にHTMLでベタ書きができるなら、アコーディオンにする要素を個別に指定できます。ですが、要素の個数が多いと一個一個目視でclass名を付与する必要があり、面倒です。
なので、この記事ではJavaScriptのループを使い「子要素の文字列の有無」を判別してアコーディオンを作ってくれるスニペットを作りました。
タイムラインのデザインでサンプルも作っています。
是非、参考にしてみてください。
.length
JavaScriptの length
は 配列の要素の数を設定または取得するプロパティです。
この記事では、for
文の中で要素の数を取得するところと、文字列の有無で length
を使っています。
詳しくは、こちらも「MDN Web Docs」をご覧ください。めちゃ分かりやすいです。
子要素の文字列の有無を判別してできるアコーディオンのサンプル
早速サンプルです。動作が分かりやすいようタイムラインのデザインです。
STEPは5つですが、「STEP1・STEP4・STEP5」の3つがアコーディオンで、「展開するコンテンツがあるSTEP」と表示されているタイトル部分をクリックすると、アコーディオンでその中身の要素が表示されます。
-
STEP1展開するコンテンツがあるSTEP
Windowsでコンピューターの世界が広がります。1234567890Windowsでコンピューターの世界が広がります。1234567890Windowsでコンピューターの世界が広がります。12345
-
STEP2展開するコンテンツがないSTEP
-
STEP3展開するコンテンツがないSTEP
-
STEP4展開するコンテンツがあるSTEP
日本国民は正当に選挙された国会における代表者を通じて行動し、われらとわれらの子孫のために、諸国民と協和による成果と、わが国全土にわたって自由のもたらす恵沢を確保し、政府の行為によって再び戦争の惨禍が起こることのないようにすることを決意し、ここに主権が国民に存することを宣言し、この憲法を確定する。そもそも国政は国民の厳粛な信託によるものであって、その権威は国民に由来し、その権力は国民の代表者がこれを行使し、その福利は国民がこれを享受する。これは人類普遍の原理であり、この憲法は、かかる原理に基づくものである。われらはこれに反する一切の憲法、法令及び詔勅を排除する。
-
STEP5展開するコンテンツがあるSTEP
Windowsでコンピューターの世界が広がります。1234567890Windowsでコンピューターの世界が広がります。1234567890Windowsでコンピューターの世界が広がります。12345
そして「展開するコンテンツがないSTEP」のタイトルは、アコーディオンではなく、単に文字が表示されているブロックです。
アコーディオンのブロックは、クリックで中身が表示されると装飾も少し変化するようになっています。
実装の手順
コードの解説の前に、実装の手順と方法について解説します。
はじめに、設置したい場所にHTMLを記述します。
<div class="ptimeline-wrap">
<ul class="ptimeline ">
<li class="ptimeline-item">
<div class="ptimeline-label">STEP1</div>
<div class="ptimeline-title">展開するコンテンツがあるSTEP</div>
<div class="ptimeline-main">
<p>Windowsでコンピューターの世界が広がります。1234567890Windowsでコンピューターの世界が広がります。1234567890Windowsでコンピューターの世界が広がります。12345</p>
</div>
<div class="ptimeline-marker "></div>
</li>
<li class="ptimeline-item">
<div class="ptimeline-label">STEP2</div>
<div class="ptimeline-title">展開するコンテンツがないSTEP</div>
<div class="ptimeline-main"></div>
<div class="ptimeline-marker "></div>
</li>
<li class="ptimeline-item">
<div class="ptimeline-label">STEP3</div>
<div class="ptimeline-title">展開するコンテンツがないSTEP</div>
<div class="ptimeline-main"></div>
<div class="ptimeline-marker "></div>
</li>
<li class="ptimeline-item">
<div class="ptimeline-label">STEP4</div>
<div class="ptimeline-title">展開するコンテンツがあるSTEP</div>
<div class="ptimeline-main">
<p>日本国民は正当に選挙された国会における代表者を通じて行動し、われらとわれらの子孫のために、諸国民と協和による成果と、わが国全土にわたって自由のもたらす恵沢を確保し、政府の行為によって再び戦争の惨禍が起こることのないようにすることを決意し、ここに主権が国民に存することを宣言し、この憲法を確定する。そもそも国政は国民の厳粛な信託によるものであって、その権威は国民に由来し、その権力は国民の代表者がこれを行使し、その福利は国民がこれを享受する。これは人類普遍の原理であり、この憲法は、かかる原理に基づくものである。われらはこれに反する一切の憲法、法令及び詔勅を排除する。</p>
</div>
<div class="ptimeline-marker "></div>
</li>
<li class="ptimeline-item">
<div class="ptimeline-label">STEP5</div>
<div class="ptimeline-title">展開するコンテンツがあるSTEP</div>
<div class="ptimeline-main">
<p>Windowsでコンピューターの世界が広がります。1234567890Windowsでコンピューターの世界が広がります。1234567890Windowsでコンピューターの世界が広がります。12345</p>
</div>
<div class="ptimeline-marker "></div>
</li>
</ul>
</div>
この記事のタイムラインをそのまま使って「STEP」を増やす場合は、li
タグのコードをコピーの上、任意の箇所を変更して記述しましょう。
次に、JavaScriptのコードをページに記述します。
コードは <body>〜</body>
で、</body>
の閉じタグ(クロージングタグ)の前に記述しましょう。
// アコーディオンの仕分け
var accpanel = document.getElementsByClassName('ptimeline-title');
var i;
for ( i = 0; i < accpanel.length; i++ ){
const nexttxt = accpanel[i].nextElementSibling;
if(nexttxt.children.length === 0){
console.log('空文字です');
accpanel[i].classList.add('accnonactive');
}else{
console.log('1文字以上の文字列です');
accpanel[i].classList.add('accactive');
}
}
// アコーディオンの動作
var acc = document.querySelectorAll('.ptimeline-title.accactive');
var i;
for ( i = 0; i < acc.length; i++ ){
acc[i].onclick = function() {
this.classList.toggle('active');
this.parentNode.classList.toggle('open');
var panel = this.nextElementSibling;
if ( panel.style.maxHeight ){
panel.style.maxHeight = null;
} else {
panel.style.maxHeight = panel.scrollHeight + 'px';
}
}
}
最後に、CSSを記述します。
/*********************************
* タイムライン
*********************************/
.ptimeline-wrap{
margin:0;
background: #FFF;
}
.ptimeline-wrap .ptimeline{
padding:0 !important;
list-style:none !important;
border: none;
margin: 0;
}
.ptimeline-wrap .ptimeline-label {
padding: 0px 0 0 2px;
color: #1565C0;
font-size: 0.95rem;
font-weight: 500;
}
.ptimeline-wrap .ptimeline-title {
font-size: 1.1em;
font-weight: 400;
line-height: 1.8;
color: #313131;
padding-top: 10px;
padding-bottom: 10px;
position: relative;
}
.ptimeline-wrap .ptimeline-title.accactive {
cursor: pointer;
color: #2165c0;
font-weight: 500;
font-size: 1.2rem;
display: block;
}
.ptimeline-title.accactive:after {
font-family: "Font Awesome 5 Free";
font-weight: 900;
font-size: 1em;
content: "\f055";
color: #2165c0;
position: absolute;
right: 5px;
}
.ptimeline-wrap .ptimeline-title.accactive:hover {
background: #f5faff;
}
.ptimeline-title.accactive.active:after {
color: #dbdbdb;
content: "\f056";
}
.ptimeline-wrap .ptimeline-main {
margin-top: 0.5em;
font-size: 0.9em;
line-height: 1.8;
color: #555;
max-height: 0;
overflow: hidden;
transition: 0.3s ease-out;
padding: 0;
position: relative;
border-bottom: dashed 1px #ddd;
margin-bottom: 0.5em;
}
.ptimeline-wrap .ptimeline-main img{
display:block;
margin:1em auto;
}
.ptimeline-wrap .ptimeline-item {
position: relative;
padding: 0 1em 1em 1.8em !important;
margin-bottom: 0 !important;
border: none;
}
.ptimeline-wrap .ptimeline .ptimeline-item:before {
content: "";
width: 3px;
background: #eee;
display: block;
position: absolute;
top: 28px;
bottom: 5px;
left: 5px;
}
.ptimeline-wrap .ptimeline-item.open:before {
background: #cae1ff;
}
.ptimeline-wrap .ptimeline-item:last-child:before{
content:none;
}
/*********************************
* タイムライン マーカー
*********************************/
.ptimeline-wrap .ptimeline-marker {
display: block;
position: absolute;
content: "";
top: 4px;
left: -2px;
width: 17px;
height: 17px;
border-radius: 50%;
border: solid 1px #2165c0;
background: #FFF;
box-shadow: 0 0 0px 4px #eee;
transition: 0.2s ease-out;
}
li.ptimeline-item.open .ptimeline-marker {
background: #2165c0;
box-shadow: 0 0 0px 4px #cae1ff;
}
コード量は多いですが、これで完了です。
ざっくりとしたコードの解説
コードは、HTML・JavaScript・CSSの3種です。順に解説していきます。
HTML
HTMLは、「ptimeline-wrap」のclass名を付けたコンテナを作り、「ptimeline-item」のclass名がついた li
タグが各STEPの親要素です。
そして、その子要素にタイトル・中身・マーカーポイントの3つが並列で格納されています。
<div class="ptimeline-wrap">
<ul class="ptimeline ">
<li class="ptimeline-item">
<div class="ptimeline-label">STEP1</div>
<div class="ptimeline-title">展開するコンテンツがあるSTEP</div>
<div class="ptimeline-main">
<p>Windowsでコンピューターの世界が広がります。1234567890Windowsでコンピューターの世界が広がります。1234567890Windowsでコンピューターの世界が広がります。12345</p>
</div>
<div class="ptimeline-marker "></div>
</li>
<li class="ptimeline-item">
<div class="ptimeline-label">STEP2</div>
<div class="ptimeline-title">展開するコンテンツがないSTEP</div>
<div class="ptimeline-main"></div>
<div class="ptimeline-marker "></div>
</li>
<li class="ptimeline-item">
<div class="ptimeline-label">STEP3</div>
<div class="ptimeline-title">展開するコンテンツがないSTEP</div>
<div class="ptimeline-main"></div>
<div class="ptimeline-marker "></div>
</li>
<li class="ptimeline-item">
<div class="ptimeline-label">STEP4</div>
<div class="ptimeline-title">展開するコンテンツがあるSTEP</div>
<div class="ptimeline-main">
<p>日本国民は正当に選挙された国会における代表者を通じて行動し、われらとわれらの子孫のために、諸国民と協和による成果と、わが国全土にわたって自由のもたらす恵沢を確保し、政府の行為によって再び戦争の惨禍が起こることのないようにすることを決意し、ここに主権が国民に存することを宣言し、この憲法を確定する。そもそも国政は国民の厳粛な信託によるものであって、その権威は国民に由来し、その権力は国民の代表者がこれを行使し、その福利は国民がこれを享受する。これは人類普遍の原理であり、この憲法は、かかる原理に基づくものである。われらはこれに反する一切の憲法、法令及び詔勅を排除する。</p>
</div>
<div class="ptimeline-marker "></div>
</li>
<li class="ptimeline-item">
<div class="ptimeline-label">STEP5</div>
<div class="ptimeline-title">展開するコンテンツがあるSTEP</div>
<div class="ptimeline-main">
<p>Windowsでコンピューターの世界が広がります。1234567890Windowsでコンピューターの世界が広がります。1234567890Windowsでコンピューターの世界が広がります。12345</p>
</div>
<div class="ptimeline-marker "></div>
</li>
</ul>
</div>
サンプルでは、5つのSTEPに準じた要素を記述しています。
JavaScript
JavaScriptは、大きく分けて「アコーディオンの仕分け」と「アコーディオンの動作」の2種類です。
はじめに記述している「アコーディオンの仕分け」では、「ptimeline-title」のclass名が付く要素を全て取得して、その直後にある要素 .nextElementSibling
で取得します。
そして、取得した要素の中身の文字列の有無を if
で条件分岐させ、文字列がない場合は「accnonactive」。1文字以上ある場合には「accactive」のclass名をそれぞれ追加します。
// アコーディオンの仕分け
var accpanel = document.getElementsByClassName('ptimeline-title');
var i;
for ( i = 0; i < accpanel.length; i++ ){
const nexttxt = accpanel[i].nextElementSibling;
if(nexttxt.children.length === 0){
console.log('空文字です');
accpanel[i].classList.add('accnonactive');
}else{
console.log('1文字以上の文字列です');
accpanel[i].classList.add('accactive');
}
}
// アコーディオンの動作
var acc = document.querySelectorAll('.ptimeline-title.accactive');
var i;
for ( i = 0; i < acc.length; i++ ){
acc[i].onclick = function() {
this.classList.toggle('active');
this.parentNode.classList.toggle('open');
var panel = this.nextElementSibling;
if ( panel.style.maxHeight ){
panel.style.maxHeight = null;
} else {
panel.style.maxHeight = panel.scrollHeight + 'px';
}
}
}
ここで追加した「accactive」がついた要素のみ、アコーディオンの動作をさせるよう後半のJavaScriptのコードで記述して、動作を切り替えています。
コード量は多いですが、雰囲気でわかるような記述内容だと思います。
CSS
CSSは、タイムラインのレイアウトを作る記述が多く、アコーディオンの動きはclass名の付け替えなので、それにじゅんじた記述内容です。
/*********************************
* タイムライン
*********************************/
.ptimeline-wrap{
margin:0;
background: #FFF;
}
.ptimeline-wrap .ptimeline{
padding:0 !important;
list-style:none !important;
border: none;
margin: 0;
}
.ptimeline-wrap .ptimeline-label {
padding: 0px 0 0 2px;
color: #1565C0;
font-size: 0.95rem;
font-weight: 500;
}
.ptimeline-wrap .ptimeline-title {
font-size: 1.1em;
font-weight: 400;
line-height: 1.8;
color: #313131;
padding-top: 10px;
padding-bottom: 10px;
position: relative;
}
.ptimeline-wrap .ptimeline-title.accactive {
cursor: pointer;
color: #2165c0;
font-weight: 500;
font-size: 1.2rem;
display: block;
}
.ptimeline-title.accactive:after {
font-family: "Font Awesome 5 Free";
font-weight: 900;
font-size: 1em;
content: "\f055";
color: #2165c0;
position: absolute;
right: 5px;
}
.ptimeline-wrap .ptimeline-title.accactive:hover {
background: #f5faff;
}
.ptimeline-title.accactive.active:after {
color: #dbdbdb;
content: "\f056";
}
.ptimeline-wrap .ptimeline-main {
margin-top: 0.5em;
font-size: 0.9em;
line-height: 1.8;
color: #555;
max-height: 0;
overflow: hidden;
transition: 0.3s ease-out;
padding: 0;
position: relative;
border-bottom: dashed 1px #ddd;
margin-bottom: 0.5em;
}
.ptimeline-wrap .ptimeline-main img{
display:block;
margin:1em auto;
}
.ptimeline-wrap .ptimeline-item {
position: relative;
padding: 0 1em 1em 1.8em !important;
margin-bottom: 0 !important;
border: none;
}
.ptimeline-wrap .ptimeline .ptimeline-item:before {
content: "";
width: 3px;
background: #eee;
display: block;
position: absolute;
top: 28px;
bottom: 5px;
left: 5px;
}
.ptimeline-wrap .ptimeline-item.open:before {
background: #cae1ff;
}
.ptimeline-wrap .ptimeline-item:last-child:before{
content:none;
}
/*********************************
* タイムライン マーカー
*********************************/
.ptimeline-wrap .ptimeline-marker {
display: block;
position: absolute;
content: "";
top: 4px;
left: -2px;
width: 17px;
height: 17px;
border-radius: 50%;
border: solid 1px #2165c0;
background: #FFF;
box-shadow: 0 0 0px 4px #eee;
transition: 0.2s ease-out;
}
li.ptimeline-item.open .ptimeline-marker {
background: #2165c0;
box-shadow: 0 0 0px 4px #cae1ff;
}
アコーディオンの「+」アイコンにはFontawesomeを使っているので、使う場合は本体の読み込みも忘れないようにしましょう。
さいごに
タイムラインは工程が多くなると、それに比例して縦に長くりがちですが、アコーディオンは情報を折りたたむことができるため、相性が良いです。
アコーディオンはスマホとも相性バッチリです。
ので、そのブロックにある情報の量を見ながら、この記事のようなアコーディオンにするなど、検討してみてください。