サムネイルで画像を切替えるギャラリーのJavaScriptコードをClaudeに書いてもらい、コードの意味を理解するために説明を追記しています。
要件
- 画像をサムネイルで切り替えるギャラリーを作成する
- 1ページ内にサムネイル切替の画像を複数表示する
- 選択されてないサムネイルを半透明opacity:.7;にする
- CMS上でも動く
特徴(Claudeの説明)
- CMS対応: DOMContentLoadedとreadyStateの両方をチェック
- エラーハンドリング: 要素が見つからない場合の対応
- 再初期化機能: 動的コンテンツ追加後にreinitializeGalleries()を呼び出し可能
- アクセシビリティ: キーボードナビゲーション対応
- 画像プリロード: スムーズな切り替えのための事前読み込み
- このコードはCMS環境でも動作しやすいよう設計されています
##コード
HTML
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>画像サムネイル切替</title>
<link rel="stylesheet" href="style.css" />
<script src="script.js" defer></script>
</head>
<body>
<h1>画像サムネイル切替デモ</h1>
<!-- ギャラリー1 -->
<div class="gallery-container" data-gallery="gallery1">
<div class="gallery-title">風景写真ギャラリー</div>
<img class="main-image" src="./img/img1.jpg" alt="メイン画像" />
<div class="thumbnails">
<img
class="thumbnail active"
src="./img/thumb_img1.jpg"
alt="サムネイル1"
data-main="./img/img1.jpg" />
<img
class="thumbnail"
src="./img/thumb_img2.jpg"
alt="サムネイル2"
data-main="./img/img2.jpg" />
</div>
</div>
<!-- ギャラリー2 -->
<div class="gallery-container" data-gallery="gallery2">
<div class="gallery-title">自然写真ギャラリー</div>
<img class="main-image" src="./img/img3.jpg" alt="メイン画像" />
<div class="thumbnails">
<img
class="thumbnail active"
src="./img/thumb_img3.jpg"
alt="サムネイル1"
data-main="./img/img3.jpg" />
<img
class="thumbnail"
src="./img/img4.jpg"
alt="サムネイル2"
data-main="./img/img4.jpg" />
</div>
</div>
</body>
</html>
CSS
.gallery-container {
margin: 20px auto;
max-width: 600px;
border: 1px solid #ddd;
/* border-radius: 8px; */
padding: 20px;
background: #f9f9f9;
}
.main-image {
width: 100%;
height: 300px;
object-fit: cover;
/* border-radius: 8px; */
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
transition: opacity 0.3s ease;
}
.thumbnails {
display: flex;
gap: 10px;
margin-top: 15px;
overflow-x: auto;
padding: 10px 0;
}
.thumbnail {
width: 80px;
height: 60px;
object-fit: cover;
/* border-radius: 4px; */
cursor: pointer;
border: 2px solid transparent;
transition: all 0.2s ease;
flex-shrink: 0;
opacity: 0.7;
}
.thumbnail:hover {
border-color: #007bff;
/* transform: scale(1.05); */
opacity: 1;
}
.thumbnail.active {
border-color: #007bff;
/* box-shadow: 0 0 0 2px rgba(0, 123, 255, 0.25); */
opacity: 1;
}
.gallery-title {
text-align: center;
margin-bottom: 15px;
color: #333;
font-size: 18px;
font-weight: bold;
}
JavaScript
// class(オブジェクトを作成するひな形のようなもの)
// クラスからオブジェクトを生成する処理をインスタンス化という
// オブジェクトリテラルは作成したいオブジェクトの数だけ個別に定義する必要があるのでclassを使うと簡単に複数オブジェクトを作成できる
// コンストラクタ:オブジェクト作成時に実行される処理
// containerを引数として渡す
console.log("Script loaded");
class ThumbnailGallery {
constructor(container) {
this.container = container;
this.mainImage = container.querySelector(".main-image");
this.thumbnails = container.querySelectorAll(".thumbnail");
this.init();
console.log(this.mainImage);
}
init() {
// 各サムネイルにクリックイベントを追加
this.thumbnails.forEach((thumbnail) => {
thumbnail.addEventListener("click", (event) => {
this.switchImage(event.target);
});
});
}
switchImage(clickedThumbnail) {
// 現在のactiveクラスを削除
const currentActive = this.container.querySelector(".thumbnail.active");
if (currentActive) {
currentActive.classList.remove("active");
}
// クリックされたサムネイルにactiveクラスを追加
clickedThumbnail.classList.add("active");
// メイン画像を切り替え(フェードエフェクト付き)
this.mainImage.style.opacity = "0";
setTimeout(() => {
this.mainImage.src = clickedThumbnail.dataset.main;
// datasetのmainはhtmlのカスタムデータ属性data-main
this.mainImage.alt = clickedThumbnail.alt;
// HTMLAreaElement: alt プロパティ
this.mainImage.style.opacity = "1";
}, 150);
}
}
// DOMが読み込まれた後に初期化
document.addEventListener("DOMContentLoaded", function () {
// 全てのギャラリーコンテナを取得して初期化
const galleryContainers = document.querySelectorAll(".gallery-container");
galleryContainers.forEach((container) => {
new ThumbnailGallery(container);
});
});
// 画像読み込みエラーのハンドリング
document.addEventListener(
"error",
function (event) {
if (event.target.tagName === "IMG") {
console.error("画像の読み込みに失敗しました:", event.target.src);
// フォールバック画像を設定する場合
// event.target.src = 'path/to/fallback-image.jpg';
}
},
true
);