この記事では、JavaScriptの.nextElementSibling
を使って、ユーザーがクリックしたアイテムの直後に位置する要素を操作することで、スムーズな開閉アニメーションと画像のロードを実現します。
簡潔なコードスニペットを交えながら、初心者でも理解しやすいようにポイントを押さえて説明します。
.nextElementSibling
JavaScriptの.nextElementSibling
は、DOM(Document Object Model)における特定の要素の直後に位置する兄弟要素を取得するために使用されます。
これにより、HTMLの構造をJavaScriptを使って動的に操作することができます。
たとえば、HTML内のリストアイテムがあり、特定のリストアイテムの次にくる要素を取得したい場合に.nextElementSibling
を使用することができます。
// HTMLのリストアイテムを示す要素を取得
var currentItem = document.getElementById('current-item');
// currentItemの次の兄弟要素を取得
var nextItem = currentItem.nextElementSibling;
// 次の要素があれば、何かの操作を行う
if (nextItem) {
// 例:次の要素のテキスト内容をコンソールに出力
console.log(nextItem.textContent);
}
実際のユースケースとしては、例えばウェブページにおいてユーザーが現在選択しているメニューアイテムをハイライトし、その次のメニューアイテムにも何らかのスタイルを適用したいときなどに役立ちます。
DOMの探索を容易にし、ユーザーインターフェイスの動的な変更を効率的に行うためによく用いられるプロパティです。
アコーディオンの開閉と画像切り替えのサンプル
早速、サンプルです。
Q&Aのアコーディオンをそれぞれクリックすると、アコーディオン下に置いてある画像がそれぞれ設定した画像に切り替わります。
あのイーハトーヴォのすきとおった風、夏でも底に冷たさをもつ青いそら、うつくしい森で飾られたモリーオ市、郊外のぎらぎらひかる草の波。あのイーハトーヴォのすきとおった風、夏でも底に冷たさをもつ青いそら、うつくしい森で飾られたモリーオ市、郊外のぎらぎらひかる草の波。あのイーハトーヴォのすきとおった風、夏でも底に冷たさをもつ青いそら、うつくしい森で飾られたモリーオ市、郊外のぎらぎらひかる草の波。あのイーハトーヴォのすきとおった風、夏でも底に冷たさをもつ青いそら、うつくしい森で飾られたモリーオ市、郊外のぎらぎらひかる草の波。
Windowsでコンピューターの世界が広がります。1234567890Windowsでコンピューターの世界が広がります。1234567890Windowsでコンピューターの世界が広がります。1234567890Windowsでコンピューターの世界が広がります。1234567890Windowsでコンピューターの世界が広がります。1234567890Windowsでコンピューターの世界が広がります。1234567890Windowsでコンピューターの世界が広がります。1234567890Windowsでコンピューター
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
ダミーテキスト。ダミーテキスト。ダミーテキスト。ダミーテキスト。ダミーテキスト。ダミーテキスト。ダミーテキスト。ダミーテキスト。ダミーテキスト。ダミーテキスト。ダミーテキスト。ダミーテキスト。ダミーテキスト。ダミーテキスト。ダミーテキスト。ダミーテキスト。ダミーテキスト。ダミーテキスト。ダミーテキス
切り替わる時、ローディング中のスピナーを表示してから切り替えます。
実装の手順と方法
コードの詳細の前に、実装の手順と方法について解説していきます。
まずは、HTMLを記述します。
設置したい場所に記述しましょう。
<div class="acco">
<div class="accordion">Question one </div>
<div class="panel">
<p>あのイーハトーヴォのすきとおった風、夏でも底に冷たさをもつ青いそら、うつくしい森で飾られたモリーオ市、郊外のぎらぎらひかる草の波。あのイーハトーヴォのすきとおった風、夏でも底に冷たさをもつ青いそら、うつくしい森で飾られたモリーオ市、郊外のぎらぎらひかる草の波。あのイーハトーヴォのすきとおった風、夏でも底に冷たさをもつ青いそら、うつくしい森で飾られたモリーオ市、郊外のぎらぎらひかる草の波。あのイーハトーヴォのすきとおった風、夏でも底に冷たさをもつ青いそら、うつくしい森で飾られたモリーオ市、郊外のぎらぎらひかる草の波。</p>
</div>
<div class="accordion">Question two </div>
<div class="panel">
<p>Windowsでコンピューターの世界が広がります。1234567890Windowsでコンピューターの世界が広がります。1234567890Windowsでコンピューターの世界が広がります。1234567890Windowsでコンピューターの世界が広がります。1234567890Windowsでコンピューターの世界が広がります。1234567890Windowsでコンピューターの世界が広がります。1234567890Windowsでコンピューターの世界が広がります。1234567890Windowsでコンピューター</p>
</div>
<div class="accordion">Question three </div>
<div class="panel">
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut </p>
</div>
<div class="accordion">Question four </div>
<div class="panel">
<p>ダミーテキスト。ダミーテキスト。ダミーテキスト。ダミーテキスト。ダミーテキスト。ダミーテキスト。ダミーテキスト。ダミーテキスト。ダミーテキスト。ダミーテキスト。ダミーテキスト。ダミーテキスト。ダミーテキスト。ダミーテキスト。ダミーテキスト。ダミーテキスト。ダミーテキスト。ダミーテキスト。ダミーテキス</p>
</div>
</div>
<div id="imageContainer"><img src="https://source.unsplash.com/640x360/?dog"></div>
次に、JavaScriptのコードを記述します。
コードは <body>〜</body>
で、</body>
の閉じタグ(クロージングタグ)の前に記述しましょう。
document.addEventListener('DOMContentLoaded', function() {
var acc = document.getElementsByClassName('accordion');
function switchImage(accordionIndex) {
var imageContainer = document.getElementById('imageContainer');
imageContainer.innerHTML = '<div class="loader"></div>'; // スピナーを表示
var imageUrls = [
'https://source.unsplash.com/640x360/?nature',
'https://source.unsplash.com/640x360/?city',
'https://source.unsplash.com/640x360/?technology',
'https://source.unsplash.com/640x360/?space'
];
var img = new Image();
img.onload = function() {
imageContainer.innerHTML = ''; // スピナーをクリア
imageContainer.appendChild(img); // 画像を表示
};
img.onerror = function() {
imageContainer.innerHTML = '画像を読み込めませんでした。'; // エラーメッセージを表示
};
img.src = imageUrls[accordionIndex]; // 画像のURLを設定
}
Array.from(acc).forEach(function(element, index) {
element.addEventListener('click', function() {
// 他のアコーディオンの 'active' クラスを削除し、パネルを閉じる
Array.from(acc).forEach(function(el) {
if (el !== element) {
el.classList.remove('active');
el.nextElementSibling.style.maxHeight = null;
}
});
// クリックされたアコーディオンの 'active' クラスをトグル
var isActive = element.classList.toggle('active');
var panel = this.nextElementSibling;
if (isActive) {
panel.style.maxHeight = panel.scrollHeight + "px";
} else {
panel.style.maxHeight = null;
}
// アコーディオンに応じた画像を切り替え
switchImage(index);
});
});
});
最後にCSSを書いて、見た目を整えましょう。
.accordion {
display: block;
line-height: 50px;
border: none;
cursor: pointer;
font-size: 1.2rem;
transition: 0.5s ease-in;
position: relative;
padding-left: 60px;
height: 53px;
margin: 0;
border-radius: 5px;
background: #FFF;
margin-bottom: 15px;
font-weight: 600;
}
.accordion:before {
content: "Q";
position: absolute;
left: 15px;
top: 50%;
display: inline-block;
width: 35px;
height: 35px;
line-height: 35px;
vertical-align: middle;
text-align: center;
font-family: Arial, sans-serif;
font-size: 21px;
background: #313131;
color: #fff;
border-radius: 50%;
transform: translateY(-50%);
}
.accordion.active {
margin-bottom: 0;
}
div.panel{
max-height:0;
overflow:hidden;
transition: 0.3s ease-out;
}
.panel p {
padding: 10px 20px;
background: #fafafa;
margin: 0 0 15px;
position:relative;
padding-left: 60px;
}
.panel p:before {
content: "A";
position: absolute;
left: 15px;
display: inline-block;
width: 35px;
height: 35px;
line-height: 35px;
vertical-align: middle;
text-align: center;
font-size: 21px;
background: #e80000;
color: #fff;
border-radius: 50%;
}
.acco{
position:relative;
}
div.accordion:hover{
background-color: #ddd;
}
div.accordion:after {
content: '\02795';
font-size: 1rem;
color: #777;
position: absolute;
right: 10px;
top: 50%;
transform: translateY(-46%);
}
div.accordion.active:after {
content: "\2796";
}
div#imageContainer {
position: relative;
background: #f9f9f9;
width: 100%;
min-height: 340px;
}
#imageContainer img {
width: 100%;
height: 360px;
object-fit: cover;
}
.loader {
border: 6px solid #f3f3f3;
border-radius: 50%;
border-top: 6px solid #3498db;
width: 40px;
height: 40px;
-webkit-animation: spin 2s linear infinite;
animation: spin 2s linear infinite;
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
}
@-webkit-keyframes spin {
0% { -webkit-transform: rotate(0deg); }
100% { -webkit-transform: rotate(360deg); }
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
ざっくりとしたコードの解説
コードは、HTML・JavaScript・CSSの3種類です。ざっくりですが、順に解説していきます。
HTML
HTMLではアコーディオン機能と画像表示エリアを含む要素で構成されています。
<div class="acco">
<div class="accordion">Question one </div>
<div class="panel">
<p>あのイーハトーヴォのすきとおった風、夏でも底に冷たさをもつ青いそら、うつくしい森で飾られたモリーオ市、郊外のぎらぎらひかる草の波。あのイーハトーヴォのすきとおった風、夏でも底に冷たさをもつ青いそら、うつくしい森で飾られたモリーオ市、郊外のぎらぎらひかる草の波。あのイーハトーヴォのすきとおった風、夏でも底に冷たさをもつ青いそら、うつくしい森で飾られたモリーオ市、郊外のぎらぎらひかる草の波。あのイーハトーヴォのすきとおった風、夏でも底に冷たさをもつ青いそら、うつくしい森で飾られたモリーオ市、郊外のぎらぎらひかる草の波。</p>
</div>
<div class="accordion">Question two </div>
<div class="panel">
<p>Windowsでコンピューターの世界が広がります。1234567890Windowsでコンピューターの世界が広がります。1234567890Windowsでコンピューターの世界が広がります。1234567890Windowsでコンピューターの世界が広がります。1234567890Windowsでコンピューターの世界が広がります。1234567890Windowsでコンピューターの世界が広がります。1234567890Windowsでコンピューターの世界が広がります。1234567890Windowsでコンピューター</p>
</div>
<div class="accordion">Question three </div>
<div class="panel">
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut </p>
</div>
<div class="accordion">Question four </div>
<div class="panel">
<p>ダミーテキスト。ダミーテキスト。ダミーテキスト。ダミーテキスト。ダミーテキスト。ダミーテキスト。ダミーテキスト。ダミーテキスト。ダミーテキスト。ダミーテキスト。ダミーテキスト。ダミーテキスト。ダミーテキスト。ダミーテキスト。ダミーテキスト。ダミーテキスト。ダミーテキスト。ダミーテキスト。ダミーテキス</p>
</div>
</div>
<div id="imageContainer"><img src="https://source.unsplash.com/640x360/?dog"></div>
アコーディオンはクリックで開閉する情報セクションで、ここには4つの異なるセクション(質問)があります。各セクションの下には詳細なテキストが隠されており、クリックによって表示されます。
- 「div.acco」は全てのアコーディオンセクションを包含するコンテナです。
- 「div.accordion」は各アコーディオンのタイトルを表し、これをクリックすると対応する「div.panel」が開閉します。
- 「div.panel」には各セクションの内容が含まれます。
- 「div#imageContainer」は、アコーディオンの操作に応じて変更可能な画像を表示するためのエリアです。デフォルトで、犬の画像が表示されています(Unsplashからのランダムな画像)。JavaScriptを使って、アコーディオンのセクションがクリックされるたびにこの画像を変更することが想定されています。
JavaScript
JavaScriptは、アコーディオン機能と画像の動的切り替え機能。
アコーディオンのセクションをクリックすると、そのセクションが展開し、他のセクションが閉じます。
また、クリックされたセクションに応じて、指定されたURLから画像を読み込み、表示します。画像が読み込まれるまでローディングスピナーが表示され、画像の読み込みが完了するとスピナーが画像に置き換わります。
// DOMが完全に読み込まれた後に実行される関数を設定
document.addEventListener('DOMContentLoaded', function() {
// 'accordion'クラスを持つすべての要素を取得
var acc = document.getElementsByClassName('accordion');
// 指定されたインデックスに応じた画像に切り替える関数
function switchImage(accordionIndex) {
var imageContainer = document.getElementById('imageContainer');
imageContainer.innerHTML = '<div class="loader"></div>'; // ローディングスピナーを表示
// 画像URLの配列
var imageUrls = [
'https://source.unsplash.com/640x360/?nature',
'https://source.unsplash.com/640x360/?city',
'https://source.unsplash.com/640x360/?technology',
'https://source.unsplash.com/640x360/?space'
];
// 新しい画像要素を作成
var img = new Image();
img.onload = function() {
imageContainer.innerHTML = ''; // 画像が読み込まれたらスピナーをクリア
imageContainer.appendChild(img); // 画像を表示
};
img.onerror = function() {
imageContainer.innerHTML = '画像を読み込めませんでした。'; // 画像の読み込みに失敗した場合のメッセージを表示
};
img.src = imageUrls[accordionIndex]; // 画像のURLを設定
}
// 各アコーディオン要素にクリックイベントリスナーを設定
Array.from(acc).forEach(function(element, index) {
element.addEventListener('click', function() {
// 他のアコーディオンから 'active' クラスを削除し、そのパネルを閉じる
Array.from(acc).forEach(function(el) {
if (el !== element) {
el.classList.remove('active');
el.nextElementSibling.style.maxHeight = null;
}
});
// クリックされたアコーディオンの 'active' クラスをトグルし、対応するパネルを開閉
var isActive = element.classList.toggle('active');
var panel = this.nextElementSibling;
if (isActive) {
panel.style.maxHeight = panel.scrollHeight + "px"; // パネルを開く
} else {
panel.style.maxHeight = null; // パネルを閉じる
}
// アコーディオンに応じた画像を切り替える
switchImage(index);
});
});
});
各コードの詳細はコメントアウトの中の解説を参考にしてみてください。
CSS
CSSでは、アコーディオンUIと画像表示エリアにスタイルを適用しています。
.accordion {
display: block;
line-height: 50px;
border: none;
cursor: pointer;
font-size: 1.2rem;
transition: 0.5s ease-in;
position: relative;
padding-left: 60px;
height: 53px;
margin: 0;
border-radius: 5px;
background: #FFF;
margin-bottom: 15px;
font-weight: 600;
}
.accordion:before {
content: "Q";
position: absolute;
left: 15px;
top: 50%;
display: inline-block;
width: 35px;
height: 35px;
line-height: 35px;
vertical-align: middle;
text-align: center;
font-family: Arial, sans-serif;
font-size: 21px;
background: #313131;
color: #fff;
border-radius: 50%;
transform: translateY(-50%);
}
.accordion.active {
margin-bottom: 0;
}
div.panel{
max-height:0;
overflow:hidden;
transition: 0.3s ease-out;
}
.panel p {
padding: 10px 20px;
background: #fafafa;
margin: 0 0 15px;
position:relative;
padding-left: 60px;
}
.panel p:before {
content: "A";
position: absolute;
left: 15px;
display: inline-block;
width: 35px;
height: 35px;
line-height: 35px;
vertical-align: middle;
text-align: center;
font-size: 21px;
background: #e80000;
color: #fff;
border-radius: 50%;
}
.acco{
position:relative;
}
div.accordion:hover{
background-color: #ddd;
}
div.accordion:after {
content: '\02795';
font-size: 1rem;
color: #777;
position: absolute;
right: 10px;
top: 50%;
transform: translateY(-46%);
}
div.accordion.active:after {
content: "\2796";
}
div#imageContainer {
position: relative;
background: #f9f9f9;
width: 100%;
min-height: 340px;
}
#imageContainer img {
width: 100%;
height: 360px;
object-fit: cover;
}
.loader {
border: 6px solid #f3f3f3;
border-radius: 50%;
border-top: 6px solid #3498db;
width: 40px;
height: 40px;
-webkit-animation: spin 2s linear infinite;
animation: spin 2s linear infinite;
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
}
@-webkit-keyframes spin {
0% { -webkit-transform: rotate(0deg); }
100% { -webkit-transform: rotate(360deg); }
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
- 「.accordion」クラスはアコーディオンの見出しに適用され、見た目とホバー時の背景色変更などの基本スタイルを定義します。
- 「.accordion:before」は、各アコーディオンの見出しの前に”Q”(質問の意味)を示す円形のアイコンを追加します。
- 「.accordion.active」と「.accordion.active:after」の擬似要素は、アコーディオンが選択(アクティブ)状態のときのスタイルを定義し、アクティブ時には”−”アイコンを表示します。
- 「div.panel」はアコーディオンのコンテンツパネルに適用され、デフォルトでは非表示(max-height: 0)に設定されていますが、アクティブ時にはコンテンツが展開されるようになっています。
- 「.panel p」と「.panel p:before」はパネル内のテキストと、その前に”A”(答えの意味)を示す円形のアイコンにスタイルを適用します。
- 「#imageContainer」と「#imageContainer img」は、画像を表示するコンテナとその中のimgタグにスタイルを適用します。画像はコンテナの幅に合わせて調整され、高さが固定されています。
- 「.loader」クラスと関連するキーフレームアニメーションは、画像が読み込まれるまでの間に表示されるローディングスピナーにスタイルを提供します。
さいごに
今回は、JavaScriptの.nextElementSibling
を活用して、アコーディオンの開閉機能と画像の切り替えについてでした。
実装例を参考に、JavaScriptを用いたさまざまな機能の実装にチャレンジしてみてください。