JavaScriptとCSSのみで、クリックすると画像がフェードインで切り替わるギャラリーを実装します。

Ad

DEMO

HTML

<div class="gallery"><img src="https://blog.grinee.net/demo/images/image1.png"></div>
<ul class="nav">
	<li class="nav-list"><a href="https://blog.grinee.net/demo/images/image1.png"><img src="https://blog.grinee.net/demo/images/image1.png"></a></li>
	<li class="nav-list"><a href="https://blog.grinee.net/demo/images/image2.png"><img src="https://blog.grinee.net/demo/images/image2.png"></a></li>
	<li class="nav-list"><a href="https://blog.grinee.net/demo/images/image3.png"><img src="https://blog.grinee.net/demo/images/image3.png"></a></li>
</ul>

CSS

ギャラリーの画像のopacityの変化に対して、CSSのtransitionで設定しています。

.nav {
	display: flex;
	margin: 10px -5px 0;
	padding: 0;
}
.nav-list {
	list-style: none;
	margin: auto 5px;
}
.nav-list img {
	height: 75px;
	width: 75px;
}
.nav-list img.active {
	opacity: .5;
}
.nav-list a {
	display: block;
	outline: none;
}
.gallery img {
	display: block;
	opacity: 0;
	transition: opacity 0.5s ease;
}
.gallery img.active {
	opacity: 1;
}
.gallery img.notransition {
	transition: none;
}

JavaScript

active と notransition のクラスを切り替えることで、画像のフェードインを実装しています。

window.addEventListener('load', function () {
	const gallery = document.querySelector('.gallery img'); // メイン画像
	const galleryContainer = document.querySelector('.gallery'); // ギャラリー親
	const navLinks = document.querySelectorAll('.nav a'); // サムネイルリンク

	// 高さ調整関数
	const adjustHeight = () => galleryContainer.style.height = gallery.clientHeight + 'px';

	// 初期表示
	if (navLinks.length === 0) return;
	const firstLink = navLinks[0];
	firstLink.querySelector('img').classList.add('active'); // サムネイルをactive
	gallery.classList.add('notransition');
	gallery.classList.add('active');
	gallery.src = firstLink.href;
	gallery.addEventListener('load', function initLoad() {
		adjustHeight();
		void gallery.offsetWidth; // reflow
		gallery.classList.remove('notransition');
		gallery.removeEventListener('load', initLoad);
	}, { once: true });

	// サムネイルクリック処理
	navLinks.forEach(link => {
		link.addEventListener('click', function (e) {
			e.preventDefault();
			const thumbImg = this.querySelector('img');

			// 既に選択中なら何もしない
			if (thumbImg.classList.contains('active')) return;

			// サムネイルの active 更新
			document.querySelectorAll('.nav img').forEach(i => i.classList.remove('active'));
			thumbImg.classList.add('active');

			const newSrc = this.href;

			// プリロードしてから切替える
			const temp = new Image();
			temp.onload = function () {
				// 1) transition を無効化(即時切替)
				gallery.classList.add('notransition');
				gallery.classList.remove('active');
				// 2) src 切替
				gallery.src = newSrc;
				adjustHeight();
				void gallery.offsetWidth; // reflow
				// 3) transition を戻して次フレームでフェードイン
				gallery.classList.remove('notransition');
				requestAnimationFrame(() => {
					requestAnimationFrame(() => {
						gallery.classList.add('active');
					});
				});
			};
			temp.src = newSrc;
		});
	});
});

jQuery版

jQueryでの実装方法については、以前の記事でまとめています。