일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 | 31 |
- #cgimall
- javascript
- jquery
- php
- #jQuery
- #image
- 홈페이지제작
- #홈페이지제작
- 해피씨지아이
- #쇼핑몰
- 솔루션
- 해피CGI
- #happycgi
- #업종별
- 홈페이지
- #해피CGI
- #CSS
- CGIMALL
- CSS
- #솔루션
- #홈페이지
- 이미지
- happycgi
- 게시판
- 사이트제작
- #웹솔루션
- #이미지
- #동영상
- #뉴스
- 웹솔루션
- Today
- Total
웹솔루션개발 25년 노하우! 해피CGI의 모든것
[해피CGI][cgimall] Card Carousel -카드 슬라이더 본문
#카드 슬라이더 #회전형 카드 목록 #카드형 이미지 롤링 #카드 회전 뷰어
카드 형식의 콘텐츠를 좌우로 부드럽게 넘길 수 있도록 구성된 이 캐러셀은,
반응형 디자인과 터치/마우스 인터랙션을 지원하여 다양한 환경에서 시각적으로 깔끔한 콘텐츠 탐색을 제공합니다.

HTML 구조
<h1 class="about-title">OUR TEAM</h1>
<div class="carousel-container">
<button class="nav-arrow left">‹</button>
<div class="carousel-track">
<div class="card" data-index="0">
</div>
<div class="card" data-index="1">
</div>
<div class="card" data-index="2">
</div>
<div class="card" data-index="3">
</div>
<div class="card" data-index="4">
</div>
<div class="card" data-index="5">
</div>
</div>
<button class="nav-arrow right">›</button>
</div>
<div class="member-info">
<h2 class="member-name">David Kim</h2>
<p class="member-role">Founder</p>
</div>
<div class="dots">
<div class="dot active" data-index="0"></div>
<div class="dot" data-index="1"></div>
<div class="dot" data-index="2"></div>
<div class="dot" data-index="3"></div>
<div class="dot" data-index="4"></div>
<div class="dot" data-index="5"></div>
</div>
CSS 소스
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
}
body {
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
background-color: #f5f5f5;
overflow: hidden;
}
.about-title {
font-size: 7.5rem;
font-weight: 900;
text-transform: uppercase;
letter-spacing: -0.02em;
position: absolute;
top: 45px;
left: 50%;
transform: translateX(-50%);
pointer-events: none;
white-space: nowrap;
font-family: "Arial Black", "Arial Bold", Arial, sans-serif;
background: linear-gradient(
to bottom,
rgb(8 42 123 / 35%) 30%,
rgb(255 255 255 / 0%) 76%
);
-webkit-background-clip: text;
background-clip: text;
color: transparent;
}
.carousel-container {
width: 100%;
max-width: 1200px;
height: 450px;
position: relative;
perspective: 1000px;
margin-top: 80px;
}
.carousel-track {
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
position: relative;
transform-style: preserve-3d;
transition: transform 0.8s cubic-bezier(0.25, 0.46, 0.45, 0.94);
}
.card {
position: absolute;
width: 280px;
height: 380px;
background: white;
border-radius: 20px;
overflow: hidden;
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.15);
transition: all 0.8s cubic-bezier(0.25, 0.46, 0.45, 0.94);
cursor: pointer;
}
.card img {
width: 100%;
height: 100%;
object-fit: cover;
transition: all 0.8s cubic-bezier(0.25, 0.46, 0.45, 0.94);
}
.card.center {
z-index: 10;
transform: scale(1.1) translateZ(0);
}
.card.center img {
filter: none;
}
.card.left-2 {
z-index: 1;
transform: translateX(-400px) scale(0.8) translateZ(-300px);
opacity: 0.7;
}
.card.left-2 img {
filter: grayscale(100%);
}
.card.left-1 {
z-index: 5;
transform: translateX(-200px) scale(0.9) translateZ(-100px);
opacity: 0.9;
}
.card.left-1 img {
filter: grayscale(100%);
}
.card.right-1 {
z-index: 5;
transform: translateX(200px) scale(0.9) translateZ(-100px);
opacity: 0.9;
}
.card.right-1 img {
filter: grayscale(100%);
}
.card.right-2 {
z-index: 1;
transform: translateX(400px) scale(0.8) translateZ(-300px);
opacity: 0.7;
}
.card.right-2 img {
filter: grayscale(100%);
}
.card.hidden {
opacity: 0;
pointer-events: none;
}
.member-info {
text-align: center;
margin-top: 40px;
transition: all 0.5s ease-out;
}
.member-name {
color: rgb(8, 42, 123);
font-size: 2.5rem;
font-weight: 700;
margin-bottom: 10px;
position: relative;
display: inline-block;
}
.member-name::before,
.member-name::after {
content: "";
position: absolute;
top: 100%;
width: 100px;
height: 2px;
background: rgb(8, 42, 123);
}
.member-name::before {
left: -120px;
}
.member-name::after {
right: -120px;
}
.member-role {
color: #848696;
font-size: 1.5rem;
font-weight: 500;
opacity: 0.8;
text-transform: uppercase;
letter-spacing: 0.1em;
padding: 10px 0;
margin-top: -15px;
position: relative;
}
.dots {
display: flex;
justify-content: center;
gap: 10px;
margin-top: 60px;
}
.dot {
width: 12px;
height: 12px;
border-radius: 50%;
background: rgba(8, 42, 123, 0.2);
cursor: pointer;
transition: all 0.3s ease;
}
.dot.active {
background: rgb(8, 42, 123);
transform: scale(1.2);
}
.nav-arrow {
position: absolute;
top: 50%;
transform: translateY(-50%);
background: rgba(8, 42, 123, 0.6);
color: white;
width: 40px;
height: 40px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
z-index: 20;
transition: all 0.3s ease;
font-size: 1.5rem;
border: none;
outline: none;
padding-bottom: 4px;
}
.nav-arrow:hover {
background: rgba(0, 0, 0, 0.8);
transform: translateY(-50%) scale(1.1);
}
.nav-arrow.left {
left: 20px;
padding-right: 3px;
}
.nav-arrow.right {
right: 20px;
padding-left: 3px;
}
@media (max-width: 768px) {
.about-title {
font-size: 4.5rem;
}
.card {
width: 200px;
height: 280px;
}
.card.left-2 {
transform: translateX(-250px) scale(0.8) translateZ(-300px);
}
.card.left-1 {
transform: translateX(-120px) scale(0.9) translateZ(-100px);
}
.card.right-1 {
transform: translateX(120px) scale(0.9) translateZ(-100px);
}
.card.right-2 {
transform: translateX(250px) scale(0.8) translateZ(-300px);
}
.member-name {
font-size: 2rem;
}
.member-role {
font-size: 1.2rem;
}
.member-name::before,
.member-name::after {
width: 50px;
}
.member-name::before {
left: -70px;
}
.member-name::after {
right: -70px;
}
}
JS 소스
const teamMembers = [
{ name: "Emily Kim", role: "Founder" },
{ name: "Michael Steward", role: "Creative Director" },
{ name: "Emma Rodriguez", role: "Lead Developer" },
{ name: "Julia Gimmel", role: "UX Designer" },
{ name: "Lisa Anderson", role: "Marketing Manager" },
{ name: "James Wilson", role: "Product Manager" }
];
const cards = document.querySelectorAll(".card");
const dots = document.querySelectorAll(".dot");
const memberName = document.querySelector(".member-name");
const memberRole = document.querySelector(".member-role");
const leftArrow = document.querySelector(".nav-arrow.left");
const rightArrow = document.querySelector(".nav-arrow.right");
let currentIndex = 0;
let isAnimating = false;
function updateCarousel(newIndex) {
if (isAnimating) return;
isAnimating = true;
currentIndex = (newIndex + cards.length) % cards.length;
cards.forEach((card, i) => {
const offset = (i - currentIndex + cards.length) % cards.length;
card.classList.remove(
"center",
"left-1",
"left-2",
"right-1",
"right-2",
"hidden"
);
if (offset === 0) {
card.classList.add("center");
} else if (offset === 1) {
card.classList.add("right-1");
} else if (offset === 2) {
card.classList.add("right-2");
} else if (offset === cards.length - 1) {
card.classList.add("left-1");
} else if (offset === cards.length - 2) {
card.classList.add("left-2");
} else {
card.classList.add("hidden");
}
});
dots.forEach((dot, i) => {
dot.classList.toggle("active", i === currentIndex);
});
memberName.style.opacity = "0";
memberRole.style.opacity = "0";
setTimeout(() => {
memberName.textContent = teamMembers[currentIndex].name;
memberRole.textContent = teamMembers[currentIndex].role;
memberName.style.opacity = "1";
memberRole.style.opacity = "1";
}, 300);
setTimeout(() => {
isAnimating = false;
}, 800);
}
leftArrow.addEventListener("click", () => {
updateCarousel(currentIndex - 1);
});
rightArrow.addEventListener("click", () => {
updateCarousel(currentIndex + 1);
});
dots.forEach((dot, i) => {
dot.addEventListener("click", () => {
updateCarousel(i);
});
});
cards.forEach((card, i) => {
card.addEventListener("click", () => {
updateCarousel(i);
});
});
document.addEventListener("keydown", (e) => {
if (e.key === "ArrowLeft") {
updateCarousel(currentIndex - 1);
} else if (e.key === "ArrowRight") {
updateCarousel(currentIndex + 1);
}
});
let touchStartX = 0;
let touchEndX = 0;
document.addEventListener("touchstart", (e) => {
touchStartX = e.changedTouches[0].screenX;
});
document.addEventListener("touchend", (e) => {
touchEndX = e.changedTouches[0].screenX;
handleSwipe();
});
function handleSwipe() {
const swipeThreshold = 50;
const diff = touchStartX - touchEndX;
if (Math.abs(diff) > swipeThreshold) {
if (diff > 0) {
updateCarousel(currentIndex + 1);
'웹프로그램밍 자료실 > HTML 자료' 카테고리의 다른 글
[해피CGI][cgimall] Death Stranding inspired menu (0) | 2025.07.09 |
---|---|
[해피CGI][cgimall] 마우스 오버 버튼 효과 Minimalist Button Hover Effect (0) | 2025.06.20 |
[해피CGI][cgimall] 마우스 효과가 들어간 네비게이션 커서 이펙트 Navigation Cursor Effect (0) | 2025.06.19 |
[해피CGI][cgimall] CSS Gooey Menu (Version 3) (0) | 2025.05.21 |
[해피CGI][cgimall] Pure SVG Loader Animation -SVG 동적 로딩 애니메이션 (0) | 2025.05.20 |