CSS×JS実装の生成AIプロンプトまとめ

特集

CSS×JS実装の生成AIプロンプトまとめ

投稿日2026/06/04

更新日2026/5/16

「このUI、どうやって作るんだろう?」

そんな動きのあるWeb演出も、今では生成AIに“プロンプト”を渡しながら効率よく制作できる時代になりました。

この記事では、

スクロールに連動する没入型メディアヒーロー
AI生成画像を活用した横スクロールスライダー
マウス追従の画像プレビューUI
奥行き感を演出する立体スライダー

など、CSSとJavaScriptで作る高品質なUI実装記事をまとめて紹介します。

すべて「実装用プロンプト付き」なので、

AIにそのまま投げて試したい
実装アイデアを増やしたい
モダンな演出を効率よく学びたい

という方にもぴったりです。

“作り方”だけでなく、“AIへの伝え方”も含めて学べる内容になっているので、ぜひ制作の参考にしてみてください。

【プロンプト有】AIがCSSとJSで作るメインが浮き上がる奥行き演出のスライダー

<div class="background-spotlight"></div>
<div class="carousel-container" id="carousel">
	<div class="card-stack" id="cardStack">
	</div>
	<div class="nav-dots" id="navDots">
	</div>
</div>
:root {
	--card-width: 320px;
	--card-height: 450px;
	--active-scale: 1.1;
	--inactive-scale: 0.85;
	--spacing: 160px;
	--rotation: 25deg;
	--transition-speed: 0.6s;
	--bg-color: #050505;
}
* {
	margin: 0;
	padding: 0;
	box-sizing: border-box;
}
body {
	background-color: var(--bg-color);
	height: 100vh;
	display: flex;
	justify-content: center;
	align-items: center;
	overflow: hidden;
	font-family: "Helvetica Neue", Arial, "Hiragino Kaku Gothic ProN", "Hiragino Sans", Meiryo, sans-serif;
	color: #fff;
}
.background-spotlight {
	position: fixed;
	top: 0;
	left: 0;
	width: 100%;
	height: 100%;
	background: radial-gradient(circle at 50% 40%, rgba(60, 60, 80, 0.4) 0%, rgba(5, 5, 5, 1) 70%);
	z-index: -1;
	filter: blur(40px);
}
.carousel-container {
	position: relative;
	width: 100%;
	height: 600px;
	perspective: 1500px;
	display: flex;
	flex-direction: column;
	justify-content: center;
	align-items: center;
	user-select: none;
}
.card-stack {
	position: relative;
	width: var(--card-width);
	height: var(--card-height);
	transform-style: preserve-3d;
	cursor: grab;
}
.card-stack:active {
	cursor: grabbing;
}
.card {
	position: absolute;
	width: 100%;
	height: 100%;
	border-radius: 20px;
	overflow: hidden;
	transition: transform var(--transition-speed) cubic-bezier(0.25, 1, 0.5, 1),
		opacity var(--transition-speed),
		filter var(--transition-speed);
	box-shadow: 0 20px 40px rgba(0, 0, 0, 0.5);
	background: #1a1a1a;
	pointer-events: none;
}
.card.active {
	pointer-events: auto;
}
.card img {
	width: 100%;
	height: 100%;
	object-fit: cover;
	display: block;
}
.card-overlay {
	position: absolute;
	bottom: 0;
	left: 0;
	width: 100%;
	height: 60%;
	background: linear-gradient(to top, rgba(0, 0, 0, 0.9) 0%, rgba(0, 0, 0, 0.4) 50%, transparent 100%);
	padding: 24px;
	display: flex;
	flex-direction: column;
	justify-content: flex-end;
}
.card-title {
	font-size: 1.25rem;
	font-weight: bold;
	margin-bottom: 8px;
	line-height: 1.2;
}
.card-description {
	font-size: 0.9rem;
	opacity: 0.8;
	display: -webkit-box;
	-webkit-line-clamp: 2;
	-webkit-box-orient: vertical;
	overflow: hidden;
	line-height: 1.4;
}
.external-link-icon {
	position: absolute;
	top: 20px;
	right: 20px;
	background: rgba(255, 255, 255, 0.2);
	backdrop-filter: blur(10px);
	padding: 8px;
	border-radius: 50%;
	opacity: 0;
	transition: opacity 0.3s;
	text-decoration: none;
	color: white;
	display: flex;
	align-items: center;
	justify-content: center;
}
.card.active .external-link-icon {
	opacity: 1;
}
.nav-dots {
	margin-top: 50px;
	display: flex;
	gap: 12px;
	z-index: 10;
}
.dot {
	width: 8px;
	height: 8px;
	border-radius: 50%;
	background: rgba(255, 255, 255, 0.3);
	cursor: pointer;
	transition: all 0.3s ease;
}
.dot.active {
	background: #fff;
	transform: scale(1.5);
	box-shadow: 0 0 10px rgba(255, 255, 255, 0.5);
}
@media (max-width: 768px) {
	:root {
		--card-width: 260px;
		--card-height: 380px;
		--spacing: 100px;
	}
}
const cardData = [{
	id: 1,
	title: '静寂のラグジュアリー',
	description: '心地よい時間を生み出す上質な空間体験',
	imageSrc: 'https://images.unsplash.com/photo-1600585154340-be6161a56a0c?auto=format&fit=crop&q=80&w=800',
	href: '#'
}, {
	id: 2,
	title: '洗練されたライフスタイル',
	description: '日常をより美しく彩るデザイン思想',
	imageSrc: 'https://images.unsplash.com/photo-1600210492486-724fe5c67fb0?auto=format&fit=crop&q=80&w=800',
	href: '#'
}, {
	id: 3,
	title: 'ダイナミックな躍動感',
	description: '感性を刺激する力強い存在感',
	imageSrc: 'https://images.unsplash.com/photo-1492144534655-ae79c964c9d7?auto=format&fit=crop&q=80&w=800',
	href: '#'
}, {
	id: 4,
	title: '細部へのこだわり',
	description: '丁寧に仕上げられた高品質なディテール',
	imageSrc: 'https://images.unsplash.com/photo-1581091226825-a6a2a5aee158?auto=format&fit=crop&q=80&w=800',
	href: '#'
}, {
	id: 5,
	title: '新しい価値の創造',
	description: '未来志向のアイデアが生む革新的体験',
	imageSrc: 'https://images.unsplash.com/photo-1485827404703-89b55fcc595e?auto=format&fit=crop&q=80&w=800',
	href: '#'
}];
let currentIndex = 0;
let isDragging = false;
let startX = 0;
let autoPlayTimer = null;
const cardStack = document.getElementById('cardStack');
const navDots = document.getElementById('navDots');

function createUI() {
	cardData.forEach((data, index) => {
		// Card
		const card = document.createElement('div');
		card.className = 'card';
		card.innerHTML = `
                <img src="${data.imageSrc}" alt="${data.title}">
                ${data.href ? `
                <a href="${data.href}" class="external-link-icon" target="_blank">
                    <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path><polyline points="15 3 21 3 21 9"></polyline><line x1="10" y1="14" x2="21" y2="3"></line></svg>
                </a>` : ''}
                <div class="card-overlay">
                    <div class="card-title">${data.title}</div>
                    <div class="card-description">${data.description}</div>
                </div>
            `;
		cardStack.appendChild(card);
		// Dot
		const dot = document.createElement('div');
		dot.className = 'dot';
		dot.addEventListener('click', () => goToIndex(index));
		navDots.appendChild(dot);
	});
	updateCarousel();
	startAutoPlay();
}

function updateCarousel() {
	const cards = document.querySelectorAll('.card');
	const dots = document.querySelectorAll('.dot');
	const total = cards.length;
	cards.forEach((card, i) => {
		// 循環インデックス計算(最も近い経路で表示)
		let diff = i - currentIndex;
		// ループ処理
		if (diff > total / 2) diff -= total;
		if (diff < -total / 2) diff += total;
		const absDiff = Math.abs(diff);
		const x = diff * 180; // 水平間隔
		const z = absDiff * -150; // 奥行き
		const rotateY = diff * -25; // 回転
		const scale = i === currentIndex ? 1.1 : 0.85;
		const translateY = i === currentIndex ? -30 : 0; // 中央を少し上げる
		const opacity = 1 - (absDiff * 0.3);
		card.style.transform = `translateX(${x}px) translateZ(${z}px) translateY(${translateY}px) rotateY(${rotateY}deg) scale(${scale})`;
		card.style.opacity = opacity;
		card.style.zIndex = 100 - absDiff;
		card.style.filter = absDiff > 0 ? 'brightness(0.5)' : 'brightness(1)';
		card.classList.toggle('active', i === currentIndex);
	});
	dots.forEach((dot, i) => {
		dot.classList.toggle('active', i === currentIndex);
	});
}

function goToIndex(index) {
	const total = cardData.length;
	currentIndex = (index + total) % total;
	updateCarousel();
}

function next() {
	goToIndex(currentIndex + 1);
}

function prev() {
	goToIndex(currentIndex - 1);
}
// ドラッグ・スワイプ処理
cardStack.addEventListener('mousedown', dragStart);
cardStack.addEventListener('touchstart', (e) => dragStart(e.touches[0]));
window.addEventListener('mousemove', dragMove);
window.addEventListener('touchmove', (e) => dragMove(e.touches[0]));
window.addEventListener('mouseup', dragEnd);
window.addEventListener('touchend', dragEnd);

function dragStart(e) {
	isDragging = true;
	startX = e.clientX;
	stopAutoPlay();
}

function dragMove(e) {
	if (!isDragging) return;
}

function dragEnd(e) {
	if (!isDragging) return;
	const endX = e.changedTouches ? e.changedTouches[0].clientX : e.clientX;
	const diff = startX - endX;
	if (Math.abs(diff) > 50) {
		if (diff > 0) next();
		else prev();
	}
	isDragging = false;
	startAutoPlay();
}
// キーボード操作
window.addEventListener('keydown', (e) => {
	if (e.key === 'ArrowRight') next();
	if (e.key === 'ArrowLeft') prev();
});
// 自動再生
function startAutoPlay() {
	stopAutoPlay();
	autoPlayTimer = setInterval(next, 5000);
}

function stopAutoPlay() {
	if (autoPlayTimer) clearInterval(autoPlayTimer);
}
const container = document.getElementById('carousel');
container.addEventListener('mouseenter', stopAutoPlay);
container.addEventListener('mouseleave', startAutoPlay);
createUI();
CSSとJavaScriptのみで構築された、奥行きのある3D表現が特徴のスライダーUIです。
カードが前後関係を持ちながらスムーズに切り替わることで、一般的なスライダーよりも視覚的なインパクトを演出できます。

AI生成プロンプトも掲載しているため、同様のUIを再現・カスタマイズしやすく、ポートフォリオやサービス紹介セクションにも活用できる実装例です。

【プロンプト有】CSSとJSで作る、マウスに追従する画像プレビューリスト

<main class="min-h-screen flex flex-col items-center justify-center">
	<div class="w-full max-w-4xl border-t border-slate-200">
		<div class="project-item group flex flex-col md:flex-row md:items-center justify-between py-10 px-6 border-b border-slate-200 cursor-pointer transition-colors duration-500 hover:bg-slate-50" data-image="https://images.unsplash.com/photo-1514924013411-cbf25faa35bb?auto=format&fit=crop&q=80&w=800">
			<div class="flex-1">
				<h2 class="text-2xl md:text-4xl font-light underline-animate inline-block">雨の日の街角</h2>
				<p class="text-slate-500 mt-2 text-sm md:text-base font-medium">濡れたアスファルトにネオンが反射する夜の都市風景</p>
			</div>
			<div class="mt-4 md:mt-0 flex items-center transform translate-x-[-10px] opacity-0 transition-all duration-300 group-hover:translate-x-0 group-hover:opacity-100">
				<span class="mr-4 text-sm font-semibold uppercase tracking-widest">View View</span>
				<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6">
					<path stroke-linecap="round" stroke-linejoin="round" d="M13.5 4.5 21 12m0 0-7.5 7.5M21 12H3" />
				</svg>
			</div>
		</div>
		<div class="project-item group flex flex-col md:flex-row md:items-center justify-between py-10 px-6 border-b border-slate-200 cursor-pointer transition-colors duration-500 hover:bg-slate-50" data-image="https://images.unsplash.com/photo-1439066615861-d1af74d74000?auto=format&fit=crop&q=80&w=800">
			<div class="flex-1">
				<h2 class="text-2xl md:text-4xl font-light underline-animate inline-block">静かな湖畔</h2>
				<p class="text-slate-500 mt-2 text-sm md:text-base font-medium">風のない水面に空が映り込む穏やかな自然の情景</p>
			</div>
			<div class="mt-4 md:mt-0 flex items-center transform translate-x-[-10px] opacity-0 transition-all duration-300 group-hover:translate-x-0 group-hover:opacity-100">
				<span class="mr-4 text-sm font-semibold uppercase tracking-widest">View View</span>
				<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6">
					<path stroke-linecap="round" stroke-linejoin="round" d="M13.5 4.5 21 12m0 0-7.5 7.5M21 12H3" />
				</svg>
			</div>
		</div>
		<div class="project-item group flex flex-col md:flex-row md:items-center justify-between py-10 px-6 border-b border-slate-200 cursor-pointer transition-colors duration-500 hover:bg-slate-50" data-image="https://images.unsplash.com/photo-1473580044384-7ba9967e16a0?auto=format&fit=crop&q=80&w=800">
			<div class="flex-1">
				<h2 class="text-2xl md:text-4xl font-light underline-animate inline-block">砂漠の夕暮れ</h2>
				<p class="text-slate-500 mt-2 text-sm md:text-base font-medium">広がる砂丘とオレンジ色に染まる地平線のコントラスト</p>
			</div>
			<div class="mt-4 md:mt-0 flex items-center transform translate-x-[-10px] opacity-0 transition-all duration-300 group-hover:translate-x-0 group-hover:opacity-100">
				<span class="mr-4 text-sm font-semibold uppercase tracking-widest">View View</span>
				<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6">
					<path stroke-linecap="round" stroke-linejoin="round" d="M13.5 4.5 21 12m0 0-7.5 7.5M21 12H3" />
				</svg>
			</div>
		</div>
	</div>
</main>
<div id="preview-container">
	<img id="preview-image" src="" alt="Preview">
</div>
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;500;700&display=swap');
body {
	font-family: 'Inter', sans-serif;
	background-color: #ffffff;
	overflow-x: hidden;
}
/* ホバー時の下線アニメーション */
.underline-animate {
	position: relative;
}
.underline-animate::after {
	content: '';
	position: absolute;
	width: 0;
	height: 2px;
	bottom: -2px;
	left: 0;
	background-color: currentColor;
	transition: width 0.4s cubic-bezier(0.25, 1, 0.5, 1);
}
.project-item:hover .underline-animate::after {
	width: 100%;
}
/* プレビューコンテナの初期状態 */
#preview-container {
	position: fixed;
	top: 0;
	left: 0;
	width: 320px;
	height: 200px;
	pointer-events: none;
	z-index: 50;
	transform: translate(-50%, -50%) scale(0.8);
	opacity: 0;
	filter: blur(20px);
	transition: transform 0.5s cubic-bezier(0.23, 1, 0.32, 1),
		opacity 0.4s ease,
		filter 0.4s ease;
	overflow: hidden;
	border-radius: 12px;
	box-shadow: 0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1);
}
#preview-container.active {
	opacity: 1;
	filter: blur(0px);
	transform: translate(-50%, -50%) scale(1);
}
/* 画像のふわっとした切り替え */
#preview-image {
	width: 100%;
	height: 100%;
	object-fit: cover;
	transition: opacity 0.3s ease;
}
/* モバイル対応:マウス追従を無効化する代わりにリスト表示を調整 */
@media (max-pointer: fine) {
	#preview-container {
		display: none;
	}
}
const previewContainer = document.getElementById('preview-container');
const previewImage = document.getElementById('preview-image');
const projectItems = document.querySelectorAll('.project-item');
let targetX = 0;
let targetY = 0;
let currentX = 0;
let currentY = 0;
// マウス位置の更新
document.addEventListener('mousemove', (e) => {
	targetX = e.clientX;
	targetY = e.clientY;
});
// 慣性(スムースな追従)アニメーション
function animate() {
	currentX += (targetX - currentX) * 0.15;
	currentY += (targetY - currentY) * 0.15;
	previewContainer.style.left = `${currentX}px`;
	previewContainer.style.top = `${currentY}px`;
	requestAnimationFrame(animate);
}
animate();
// 各項目へのイベント登録
projectItems.forEach(item => {
	item.addEventListener('mouseenter', () => {
		const imageUrl = item.getAttribute('data-image');
		// 画像をふわっと切り替える
		previewImage.style.opacity = '0';
		setTimeout(() => {
			previewImage.src = imageUrl;
			previewImage.style.opacity = '1';
		}, 50);
		previewContainer.classList.add('active');
	});
	item.addEventListener('mouseleave', () => {
		previewContainer.classList.remove('active');
	});
});
// タッチデバイスでの配慮
document.addEventListener('touchstart', () => {
	previewContainer.style.display = 'none';
}, {
	passive: true
});
https://cdn.tailwindcss.com
リストにホバーすると画像がマウスに追従して表示されるインタラクティブUIです。
カーソル位置に合わせてプレビュー画像が滑らかに動くことで、単なるテキスト一覧に動きと視覚的な魅力を加えています。

JavaScriptでマウス座標を取得し、補間処理によって自然な追従アニメーションを実現しています。
シンプルな構造ながら体験価値が高く、ポートフォリオや記事一覧、ギャラリーUIなど幅広い用途に応用できる実装です。

【プロンプト有】CSSとJSで作る、AIで生成した横スクロールの画像スライダー

<section class="max-w-7xl mx-auto py-12 px-4 sm:py-24">
	<div class="mb-10 flex flex-col md:flex-row md:items-end justify-between gap-4">
		<div>
			<h2 class="text-3xl sm:text-4xl font-bold tracking-tight text-gray-900">Featured Projects</h2>
			<p class="mt-2 text-lg text-gray-500">最新のデザインとテクノロジーを融合させたプロジェクト事例</p>
		</div>
		<div class="hidden md:flex gap-3">
			<button id="prevBtn" class="p-3 rounded-full border border-gray-200 bg-white shadow-sm hover:bg-gray-50 transition-all active:scale-95 disabled:opacity-30" aria-label="Previous">
				<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
					<path d="m15 18-6-6 6-6" />
				</svg>
			</button>
			<button id="nextBtn" class="p-3 rounded-full border border-gray-200 bg-white shadow-sm hover:bg-gray-50 transition-all active:scale-95 disabled:opacity-30" aria-label="Next">
				<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
					<path d="m9 18 6-6-6-6" />
				</svg>
			</button>
		</div>
	</div>
	<div class="relative group">
		<div id="carousel" class="scroll-container hide-scrollbar flex gap-4 sm:gap-6 overflow-x-auto pb-8 -mx-4 px-4 sm:mx-0 sm:px-0">
			<div class="card w-[85vw] sm:w-[calc(50%-12px)] lg:w-[calc(33.333%-16px)]">
				<a href="#" class="block relative overflow-hidden rounded-2xl aspect-[4/5] group/card">
					<img src="https://images.unsplash.com/photo-1498050108023-c5249f4df085?auto=format&fit=crop&q=80&w=800" alt="Minimal Tech" class="absolute inset-0 w-full h-full object-cover transition-transform duration-500 group-hover/card:scale-110">
					<div class="absolute inset-0 bg-gradient-to-t from-black/80 via-black/20 to-transparent"></div>
					<div class="absolute bottom-0 p-6 sm:p-8 text-white">
						<span class="text-xs font-semibold uppercase tracking-wider text-blue-400">Technology</span>
						<h3 class="text-2xl font-bold mt-2">Core OS Architecture</h3>
						<p class="text-sm text-gray-300 mt-2 opacity-0 group-hover/card:opacity-100 transition-opacity duration-300">次世代のオペレーティングシステムに向けた革新的なアーキテクチャ設計。</p>
					</div>
				</a>
			</div>
			<div class="card w-[85vw] sm:w-[calc(50%-12px)] lg:w-[calc(33.333%-16px)]">
				<a href="#" class="block relative overflow-hidden rounded-2xl aspect-[4/5] group/card">
					<img src="https://images.unsplash.com/photo-1441986300917-64674bd600d8?auto=format&fit=crop&q=80&w=800" alt="E-commerce" class="absolute inset-0 w-full h-full object-cover transition-transform duration-500 group-hover/card:scale-110">
					<div class="absolute inset-0 bg-gradient-to-t from-black/80 via-black/20 to-transparent"></div>
					<div class="absolute bottom-0 p-6 sm:p-8 text-white">
						<span class="text-xs font-semibold uppercase tracking-wider text-blue-400">Design</span>
						<h3 class="text-2xl font-bold mt-2">Luxe Fashion Store</h3>
						<p class="text-sm text-gray-300 mt-2 opacity-0 group-hover/card:opacity-100 transition-opacity duration-300">ミニマリズムを追求したハイエンドファッションブランドのECサイト。</p>
					</div>
				</a>
			</div>
			<div class="card w-[85vw] sm:w-[calc(50%-12px)] lg:w-[calc(33.333%-16px)]">
				<a href="#" class="block relative overflow-hidden rounded-2xl aspect-[4/5] group/card">
					<img src="https://images.unsplash.com/photo-1550745165-9bc0b252726f?auto=format&fit=crop&q=80&w=800" alt="Cybersecurity" class="absolute inset-0 w-full h-full object-cover transition-transform duration-500 group-hover/card:scale-110">
					<div class="absolute inset-0 bg-gradient-to-t from-black/80 via-black/20 to-transparent"></div>
					<div class="absolute bottom-0 p-6 sm:p-8 text-white">
						<span class="text-xs font-semibold uppercase tracking-wider text-blue-400">Security</span>
						<h3 class="text-2xl font-bold mt-2">Quantum Encryption</h3>
						<p class="text-sm text-gray-300 mt-2 opacity-0 group-hover/card:opacity-100 transition-opacity duration-300">量子コンピュータ時代の到来に備えた最高機密レベルの暗号化。 </p>
					</div>
				</a>
			</div>
			<div class="card w-[85vw] sm:w-[calc(50%-12px)] lg:w-[calc(33.333%-16px)]">
				<a href="#" class="block relative overflow-hidden rounded-2xl aspect-[4/5] group/card">
					<img src="https://images.unsplash.com/photo-1460925895917-afdab827c52f?auto=format&fit=crop&q=80&w=800" alt="Data Science" class="absolute inset-0 w-full h-full object-cover transition-transform duration-500 group-hover/card:scale-110">
					<div class="absolute inset-0 bg-gradient-to-t from-black/80 via-black/20 to-transparent"></div>
					<div class="absolute bottom-0 p-6 sm:p-8 text-white">
						<span class="text-xs font-semibold uppercase tracking-wider text-blue-400">Analytics</span>
						<h3 class="text-2xl font-bold mt-2">Smart City Hub</h3>
						<p class="text-sm text-gray-300 mt-2 opacity-0 group-hover/card:opacity-100 transition-opacity duration-300">都市のインフラ情報を可視化する統合データ分析プラットフォーム。</p>
					</div>
				</a>
			</div>
			<div class="card w-[85vw] sm:w-[calc(50%-12px)] lg:w-[calc(33.333%-16px)]">
				<a href="#" class="block relative overflow-hidden rounded-2xl aspect-[4/5] group/card">
					<img src="https://images.unsplash.com/photo-1486406146926-c627a92ad1ab?auto=format&fit=crop&q=80&w=800" alt="Architecture" class="absolute inset-0 w-full h-full object-cover transition-transform duration-500 group-hover/card:scale-110">
					<div class="absolute inset-0 bg-gradient-to-t from-black/80 via-black/20 to-transparent"></div>
					<div class="absolute bottom-0 p-6 sm:p-8 text-white">
						<span class="text-xs font-semibold uppercase tracking-wider text-blue-400">Urban</span>
						<h3 class="text-2xl font-bold mt-2">Vertical Garden</h3>
						<p class="text-sm text-gray-300 mt-2 opacity-0 group-hover/card:opacity-100 transition-opacity duration-300">自然と共生する都市型高層建築のサステナブルデザイン。</p>
					</div>
				</a>
			</div>
		</div>
		<div id="dot-container" class="mt-8 flex justify-center gap-2">
		</div>
	</div>
</section>
html, body {
    margin: 0;
    padding: 0;
    background: #fff;
}
.hide-scrollbar::-webkit-scrollbar {
	display: none;
}
.hide-scrollbar {
	-ms-overflow-style: none;
	scrollbar-width: none;
}
.scroll-container {
	scroll-behavior: smooth;
	-webkit-overflow-scrolling: touch;
	scroll-snap-type: x mandatory;
}
.card {
	scroll-snap-align: center;
	flex-shrink: 0;
}
@media (min-width: 860px) {
	.card {
		scroll-snap-align: start;
	}
}
.dragging {
	cursor: grabbing;
	user-select: none;
}
.dragging a {
	pointer-events: none;
}
const carousel = document.getElementById('carousel');
const prevBtn = document.getElementById('prevBtn');
const nextBtn = document.getElementById('nextBtn');
const dotContainer = document.getElementById('dot-container');
let isDragging = false;
let startX;
let scrollLeftStart;
let dragDistance = 0;
// スライド(ドット)の計算と生成
function setupPagination() {
	const cards = Array.from(carousel.querySelectorAll('.card'));
	const containerWidth = carousel.clientWidth;
	const cardWidth = cards[0].offsetWidth;
	// 1画面に収まる枚数を計算
	const visibleCards = Math.round(containerWidth / cardWidth);
	// 合計スライド数(表示開始可能な位置の数)
	const totalSlides = Math.max(1, cards.length - visibleCards + 1);
	// ドットの生成
	dotContainer.innerHTML = '';
	for (let i = 0; i < totalSlides; i++) {
		const dot = document.createElement('button');
		dot.className = `w-2 h-2 rounded-full transition-all duration-300 bg-gray-300 hover:bg-gray-400`;
		dot.setAttribute('aria-label', `Go to slide ${i + 1}`);
		dot.addEventListener('click', () => {
			const targetScroll = i * (cardWidth + 24); // 24はgap(gap-6)
			carousel.scrollTo({
				left: targetScroll,
				behavior: 'smooth'
			});
		});
		dotContainer.appendChild(dot);
	}
	updateActiveDot();
}
// アクティブなドットの更新
function updateActiveDot() {
	const cards = carousel.querySelectorAll('.card');
	if (cards.length === 0) return;
	const cardWidth = cards[0].offsetWidth + 24;
	const currentScroll = carousel.scrollLeft;
	const activeIndex = Math.round(currentScroll / cardWidth);
	const dots = dotContainer.querySelectorAll('button');
	dots.forEach((dot, index) => {
		if (index === activeIndex) {
			dot.classList.add('bg-blue-600', 'w-8');
			dot.classList.remove('bg-gray-300', 'w-2');
		} else {
			dot.classList.remove('bg-blue-600', 'w-8');
			dot.classList.add('bg-gray-300', 'w-2');
		}
	});
	// ボタンの有効/無効
	if (prevBtn && nextBtn) {
		prevBtn.disabled = currentScroll <= 5;
		nextBtn.disabled = currentScroll + carousel.clientWidth >= carousel.scrollWidth - 5;
	}
}
// ナビゲーションボタン
prevBtn.addEventListener('click', () => {
	const cardWidth = carousel.querySelector('.card').offsetWidth + 24;
	carousel.scrollBy({
		left: -cardWidth,
		behavior: 'smooth'
	});
});
nextBtn.addEventListener('click', () => {
	const cardWidth = carousel.querySelector('.card').offsetWidth + 24;
	carousel.scrollBy({
		left: cardWidth,
		behavior: 'smooth'
	});
});
// ドラッグ&スワイプ機能
carousel.addEventListener('mousedown', (e) => {
	isDragging = true;
	carousel.classList.add('dragging');
	startX = e.pageX - carousel.offsetLeft;
	scrollLeftStart = carousel.scrollLeft;
	dragDistance = 0;
});
window.addEventListener('mousemove', (e) => {
	if (!isDragging) return;
	e.preventDefault();
	const x = e.pageX - carousel.offsetLeft;
	const walk = (x - startX) * 1.5;
	carousel.scrollLeft = scrollLeftStart - walk;
	dragDistance = Math.abs(walk);
});
window.addEventListener('mouseup', () => {
	isDragging = false;
	carousel.classList.remove('dragging');
});
// リンクのクリック防止 (ドラッグ中のみ)
carousel.querySelectorAll('a').forEach(link => {
	link.addEventListener('click', (e) => {
		if (dragDistance > 10) {
			e.preventDefault();
		}
	});
});
// イベントリスナー
carousel.addEventListener('scroll', updateActiveDot);
window.addEventListener('resize', () => {
	setupPagination();
});
// 初期化
window.addEventListener('load', setupPagination);
https://cdn.tailwindcss.com
横スクロールをベースにしたカードカルーセルUIで、スナップスクロールとドラッグ操作によりスムーズな閲覧体験を実現しています。

表示領域に応じてカードの表示数が変化するレスポンシブ設計で、PC・タブレット・スマホすべてに対応可能です。

ドットナビゲーションによる現在位置の可視化や、ボタン操作による移動機能も備えており、実用的なプロジェクト一覧やギャラリーUIとしてそのまま活用できる構成です。

【プロンプト有】CSSとJSで作る、スクロール連動の没入型メディアヒーローUI

<div class="hero-viewport">
	<div class="background-image" id="bgImage"></div>
	<div class="text-layer">
		<div class="title-wrap">
			<span class="title-part" id="titleLeft">没入型</span>
			<span class="title-part" id="titleRight">ビジュアル体験</span>
		</div>
		<div class="info-text" id="dateText">デジタルショーケース</div>
		<div class="scroll-hint" id="scrollHint">スクロールして展開</div>
		<div class="final-content" id="finalContent">
			<p>スクロール操作に応じてメディアが拡大し、視覚的に魅力的な体験を提供するUI</p>
		</div>
	</div>
	<div class="media-container">
		<div class="media-card" id="mediaCard">
			<div class="video-overlay"></div>
			<video id="heroVideo" autoplay loop muted playsinline poster="https://kumonosu.net/wp-content/uploads/2026/04/moorpheus-beach-418742.jpg">
				<source src="https://kumonosu.net/wp-content/uploads/2026/04/344380.mp4" type="video/mp4">
			</video>
		</div>
	</div>
</div>
:root {
	--bg-color: #000;
	--text-color: #fff;
	--transition-speed: 0.1s;
}
* {
	margin: 0;
	padding: 0;
	box-sizing: border-box;
}
body {
	background-color: var(--bg-color);
	color: var(--text-color);
	font-family: "Helvetica Neue", Arial, "Hiragino Kaku Gothic ProN", "Hiragino Sans", Meiryo, sans-serif;
	overflow-x: hidden;
	height: 300vh;
}
.hero-viewport {
	position: fixed;
	top: 0;
	left: 0;
	width: 100%;
	height: 100vh;
	overflow: hidden;
	display: flex;
	justify-content: center;
	align-items: center;
}
.background-image {
	position: absolute;
	top: 0;
	left: 0;
	width: 100%;
	height: 100%;
	background-image: url('https://kumonosu.net/wp-content/uploads/2026/04/moorpheus-beach-418742.jpg');
	background-size: cover;
	background-position: center;
	z-index: 1;
}
.media-container {
	position: relative;
	z-index: 10;
	width: 100%;
	height: 100%;
	display: flex;
	justify-content: center;
	align-items: center;
	pointer-events: none;
}
.media-card {
	position: relative;
	width: 70vw;
	height: 40vw;
	max-width: 900px;
	max-height: 500px;
	overflow: hidden;
	border-radius: 24px;
	box-shadow: 0 20px 50px rgba(0, 0, 0, 0.5);
	transform: scale(0.6);
	will-change: transform, width, height, border-radius;
}
video {
	width: 100%;
	height: 100%;
	object-fit: cover;
}
.video-overlay {
	position: absolute;
	top: 0;
	left: 0;
	width: 100%;
	height: 100%;
	background: rgba(0, 0, 0, 0.3);
	z-index: 11;
}
.text-layer {
	position: absolute;
	width: 100%;
	height: 100%;
	top: 0;
	left: 0;
	z-index: 20;
	display: flex;
	flex-direction: column;
	justify-content: center;
	align-items: center;
	pointer-events: none;
}
.title-wrap {
	display: flex;
	font-size: clamp(2rem, 8vw, 5rem);
	font-weight: 900;
	line-height: 1.2;
	text-transform: uppercase;
	white-space: nowrap;
}
.title-part {
	display: inline-block;
	transition: transform var(--transition-speed) linear;
}
.info-text {
	margin-top: 20px;
	font-size: 1.2rem;
	letter-spacing: 0.2em;
	transition: transform var(--transition-speed) linear, opacity 0.3s;
}
.scroll-hint {
	position: absolute;
	bottom: 40px;
	font-size: 0.9rem;
	opacity: 0.8;
	animation: bounce 2s infinite;
}
@keyframes bounce {
	0%, 20%, 50%, 80%, 100% {
		transform: translateY(0);
	}
	40% {
		transform: translateY(-10px);
	}
	60% {
		transform: translateY(-5px);
	}
}
.final-content {
	position: absolute;
	z-index: 30;
	opacity: 0;
	transform: translateY(30px);
	text-align: center;
	max-width: 600px;
	padding: 20px;
	pointer-events: none;
}
.final-content h2 {
	font-size: 2.5rem;
	margin-bottom: 20px;
}
.final-content p {
	font-size: 1.1rem;
	line-height: 1.8;
}
@media (max-width: 768px) {
	.media-card {
		width: 90vw;
		height: 60vw;
	}
	.info-text {
		font-size: 0.9rem;
	}
}
const mediaCard = document.getElementById('mediaCard');
const bgImage = document.getElementById('bgImage');
const titleLeft = document.getElementById('titleLeft');
const titleRight = document.getElementById('titleRight');
const dateText = document.getElementById('dateText');
const scrollHint = document.getElementById('scrollHint');
const finalContent = document.getElementById('finalContent');
// スクロールイベントの監視
window.addEventListener('scroll', () => {
	updateAnimation();
});
// モバイルのスワイプ操作はブラウザのデフォルトスクロールに委ねるが、
// 必要に応じて進行度を調整
function updateAnimation() {
	// スクロール進行度の計算 (0 to 1)
	const maxScroll = document.documentElement.scrollHeight - window.innerHeight;
	const progress = Math.min(window.scrollY / maxScroll, 1);
	// 1. ビデオカードの拡大と角丸の解除
	// 進行度 0% (scale 0.6) -> 100% (scale 1.5くらいで画面を覆う)
	const scaleVal = 0.6 + (progress * 1.2);
	const radiusVal = 24 * (1 - progress);
	mediaCard.style.transform = `scale(${scaleVal})`;
	mediaCard.style.borderRadius = `${radiusVal}px`;
	// 2. 背景画像のフェードアウト
	bgImage.style.opacity = 1 - (progress * 2); // 早めに消す
	// 3. タイトルの左右スライド分割
	// 進行度に応じて左右に150%ずつ移動
	const slideVal = progress * 150;
	titleLeft.style.transform = `translateX(-${slideVal}%)`;
	titleRight.style.transform = `translateX(${slideVal}%)`;
	titleLeft.style.opacity = 1 - (progress * 2);
	titleRight.style.opacity = 1 - (progress * 2);
	// 4. 日付とヒントのフェードアウトとスライド
	dateText.style.opacity = 1 - (progress * 3);
	dateText.style.transform = `translateY(${progress * -50}px)`;
	scrollHint.style.opacity = 1 - (progress * 4);
	// 5. 最終コンテンツの表示 (progressが後半になったら表示)
	if (progress > 0.8) {
		const contentProgress = (progress - 0.8) * 5; // 0 to 1
		finalContent.style.opacity = contentProgress;
		finalContent.style.transform = `translateY(${(1 - contentProgress) * 20}px)`;
		finalContent.style.pointerEvents = "auto";
	} else {
		finalContent.style.opacity = 0;
		finalContent.style.transform = `translateY(20px)`;
		finalContent.style.pointerEvents = "none";
	}
}
// 初期実行
updateAnimation();
// リサイズ時の再計算対応
window.addEventListener('resize', updateAnimation);
スクロール量に応じて動画が拡大し、背景やテキストが段階的に変化する没入型ヒーローUIです。
初期状態ではカード状に表示されたメディアが、スクロールとともに画面全体へ広がり、同時にタイトルや補足テキストがフェード・スライドして消えていきます。

最終的にコンテンツが表示される流れにより、ストーリー性のある導線を構築できます。シンプルな構造ながら視覚的なインパクトが強く、LPやプロダクト紹介のファーストビューに適した実装です。