관리 메뉴

웹솔루션개발 25년 노하우! 해피CGI의 모든것

[해피CGI][cgimall] 인터랙티브 탄성(Elastic) 호버 메뉴 애니메이션 본문

웹프로그램밍 자료실/HTML 자료

[해피CGI][cgimall] 인터랙티브 탄성(Elastic) 호버 메뉴 애니메이션

해피CGI윤실장 2025. 12. 1. 09:23

Interactive Elastic Hover Menu Animation
인터랙티브 탄성(Elastic) 호버 메뉴 애니메이션

JavaScript와 CSS3 애니메이션을 활용하여 메뉴 버튼에 탄성(Eelastic) 형태의 변형 및 확장 효과를 구현한 인터랙션 UI입니다.
호버 시 버튼이 자연스럽게 팽창하면서 메뉴 항목이 드러나는 구조로, 유체적인 움직임을 기반으로 한 현대적인 사용자 경험을 제공합니다.
웹 포트폴리오, 서비스 네비게이션, 아이콘 기반 메뉴, 크리에이티브 인터페이스 등 다양한 영역에 적용하기 적합합니다.

HTML 구조

<div class="slider-container">

<div class="now-showing">Now in Showroom</div>

 

<div class="accordion-slider">

 

<div class="slide-content">

<div class="slide-number">01</div>

<div class="car-brand">BMW M3</div>

<div class="car-name">BMW M3 Competition</div>

<div class="car-subtitle">Twin-Turbo Inline-6 Performance</div>

<div class="car-specs">

<div class="spec-row">

<span class="spec-label">Engine:</span>

<span class="spec-value">3.0L Twin-Turbo Inline-6</span>

</div>

<div class="spec-row">

<span class="spec-label">Power:</span>

<span class="spec-value">503 HP @ 6,250 RPM</span>

</div>

<div class="spec-row">

<span class="spec-label">Torque:</span>

<span class="spec-value">650 Nm @ 2,750 RPM</span>

</div>

<div class="spec-row">

<span class="spec-label">Transmission:</span>

<span class="spec-value">8-Speed Automatic</span>

</div>

</div>

<div class="performance-badges">

<div class="badge">

<div class="badge-icon"></div>

<span>0-100: 3.9s</span>

</div>

<div class="badge">

<div class="badge-icon"></div>

<span>Top Speed: 290 km/h</span>

</div>

<div class="badge">

<div class="badge-icon"></div>

<span>Price: $73,400</span>

</div>

</div>

</div>

<div class="add-button"></div>

</div>

 

 

<div class="slide-content">

<div class="slide-number">02</div>

<div class="car-brand">Lamborghini Huracán</div>

<div class="car-name">Lamborghini Huracán</div>

<div class="car-subtitle">Naturally Aspirated V10 Excellence</div>

<div class="car-specs">

<div class="spec-row">

<span class="spec-label">Engine:</span>

<span class="spec-value">5.2L V10 Naturally Aspirated</span>

</div>

<div class="spec-row">

<span class="spec-label">Power:</span>

<span class="spec-value">610 HP @ 8,250 RPM</span>

</div>

<div class="spec-row">

<span class="spec-label">Torque:</span>

<span class="spec-value">560 Nm @ 6,500 RPM</span>

</div>

<div class="spec-row">

<span class="spec-label">Transmission:</span>

<span class="spec-value">7-Speed Dual-Clutch</span>

</div>

</div>

<div class="performance-badges">

<div class="badge">

<div class="badge-icon"></div>

<span>0-100: 3.2s</span>

</div>

<div class="badge">

<div class="badge-icon"></div>

<span>Top Speed: 325 km/h</span>

</div>

<div class="badge">

<div class="badge-icon"></div>

<span>Price: $248,295</span>

</div>

</div>

</div>

<div class="add-button"></div>

</div>

 

 

<div class="slide-content">

<div class="slide-number">03</div>

<div class="car-brand">Ferrari SF90</div>

<div class="car-name">Ferrari SF90 Stradale</div>

<div class="car-subtitle">Plug-in Hybrid Revolution</div>

<div class="car-specs">

<div class="spec-row">

<span class="spec-label">Engine:</span>

<span class="spec-value">4.0L V8 Twin-Turbo + Electric</span>

</div>

<div class="spec-row">

<span class="spec-label">Power:</span>

<span class="spec-value">1000 HP Combined</span>

</div>

<div class="spec-row">

<span class="spec-label">Torque:</span>

<span class="spec-value">800 Nm @ 6,000 RPM</span>

</div>

<div class="spec-row">

<span class="spec-label">Transmission:</span>

<span class="spec-value">8-Speed F1 DCT</span>

</div>

</div>

<div class="performance-badges">

<div class="badge">

<div class="badge-icon"></div>

<span>0-100: 2.5s</span>

</div>

<div class="badge">

<div class="badge-icon"></div>

<span>Top Speed: 340 km/h</span>

</div>

<div class="badge">

<div class="badge-icon"></div>

<span>Price: $625,000</span>

</div>

</div>

</div>

<div class="add-button"></div>

</div>

 

 

<div class="slide-content">

<div class="slide-number">04</div>

<div class="car-brand">Porsche 911</div>

<div class="car-name">Porsche 911 Turbo S</div>

<div class="car-subtitle">Twin-Turbo Flat-Six Perfection</div>

<div class="car-specs">

<div class="spec-row">

<span class="spec-label">Engine:</span>

<span class="spec-value">3.8L Twin-Turbo Flat-6</span>

</div>

<div class="spec-row">

<span class="spec-label">Power:</span>

<span class="spec-value">640 HP @ 6,750 RPM</span>

</div>

<div class="spec-row">

<span class="spec-label">Torque:</span>

<span class="spec-value">800 Nm @ 2,500 RPM</span>

</div>

<div class="spec-row">

<span class="spec-row">

<span class="spec-label">Transmission:</span>

<span class="spec-value">8-Speed PDK</span>

</div>

</div>

<div class="performance-badges">

<div class="badge">

<div class="badge-icon"></div>

<span>0-100: 2.7s</span>

</div>

<div class="badge">

<div class="badge-icon"></div>

<span>Top Speed: 330 km/h</span>

</div>

<div class="badge">

<div class="badge-icon"></div>

<span>Price: $207,000</span>

</div>

</div>

</div>

<div class="add-button"></div>

</div>

</div>

 

<button class="navigation-arrows nav-prev">‹</button>

<button class="navigation-arrows nav-next">›</button>

</div>



CSS 소스

.slider-container {

width: 100%;

max-width: 1200px;

height: 100vh;

position: relative;

overflow: hidden;

box-shadow: 0 20px 40px rgba(0, 0, 0, 0.1);

}

 

.now-showing {

position: absolute;

top: 20px;

left: 20px;

color: #9fff6b;

font-size: 14px;

font-weight: 600;

display: flex;

align-items: center;

gap: 8px;

z-index: 10;

}

 

.now-showing::before {

content: "";

width: 6px;

height: 6px;

background: #9fff6b;

border-radius: 50%;

}

 

.accordion-slider {

display: flex;

height: 100%;

position: relative;

}

 

.slide {

flex: 1;

position: relative;

cursor: pointer;

background-size: cover;

background-position: center;

background-repeat: no-repeat;

transition: all 0.8s cubic-bezier(0.4, 0, 0.2, 1);

overflow: hidden;

filter: grayscale(1);

}

 

.slide:hover {

filter: grayscale(0);

}

 

.slide.active {

flex: 2.5;

filter: grayscale(0);

}

 

.slide::before {

content: "";

position: absolute;

top: 0;

left: 0;

right: 0;

bottom: 0;

background: linear-gradient(180deg, transparent 0%, rgba(0, 0, 0, 0.8) 80%);

}

 

.slide-content {

position: absolute;

bottom: 30px;

left: 30px;

right: 30px;

color: white;

z-index: 2;

}

 

.slide.active .slide-content {

bottom: 80px;

transition: all 0.8s cubic-bezier(0.4, 0, 0.2, 1) 0.2s;

}

 

.slide-number {

font-size: 64px;

font-weight: 300;

color: rgba(255, 255, 255, 0.6);

line-height: 1;

position: absolute;

bottom: 30px;

left: 30px;

transition: all 0.8s cubic-bezier(0.4, 0, 0.2, 1);

}

 

.slide.active .slide-number {

bottom: auto;

top: -50px;

font-size: 48px;

left: 0;

}

 

.car-brand {

font-size: 16px;

font-weight: 600;

color: rgba(255, 255, 255, 0.8);

margin-bottom: 5px;

transform: rotate(-90deg);

transform-origin: left bottom;

position: absolute;

bottom: 100px;

left: 30px;

white-space: nowrap;

transition: all 0.8s cubic-bezier(0.4, 0, 0.2, 1);

}

.slide.active .car-brand {

transform: rotate(0deg);

position: static;

transform-origin: unset;

}

 

.car-name {

font-size: 28px;

font-weight: 700;

margin-bottom: 8px;

opacity: 0;

transform: translateY(30px);

transition: all 0.6s cubic-bezier(0.4, 0, 0.2, 1);

transition-delay: 0s;

}

 

.slide.active .car-name {

opacity: 1;

transform: translateY(0);

transition-delay: 0.3s;

}

 

.car-subtitle {

font-size: 16px;

color: rgba(255, 255, 255, 0.8);

margin-bottom: 20px;

opacity: 0;

transform: translateY(30px);

transition: all 0.6s cubic-bezier(0.4, 0, 0.2, 1);

transition-delay: 0s;

}

----이하 생략---



JS 소스

class AccordionSlider {

constructor() {

this.slides = document.querySelectorAll(".slide");

this.prevBtn = document.querySelector(".nav-prev");

this.nextBtn = document.querySelector(".nav-next");

this.currentIndex = -1;

 

this.init();

}

 

init() {

this.slides.forEach((slide, index) => {

slide.addEventListener("click", () => this.setActiveSlide(index));

});

 

this.prevBtn.addEventListener("click", () => this.previousSlide());

this.nextBtn.addEventListener("click", () => this.nextSlide());

 

document.addEventListener("keydown", (e) => {

if (e.key === "ArrowLeft") this.previousSlide();

if (e.key === "ArrowRight") this.nextSlide();

});

}

 

setActiveSlide(index) {

if (this.currentIndex === index) {

this.slides.forEach((slide) => slide.classList.remove("active"));

this.currentIndex = -1;

} else {

this.slides.forEach((slide) => slide.classList.remove("active"));

this.slides[index].classList.add("active");

this.currentIndex = index;

}

}

 

nextSlide() {

const nextIndex =

this.currentIndex === -1 ? 0 : (this.currentIndex + 1) % this.slides.length;

this.setActiveSlide(nextIndex);

}

 

previousSlide() {

const prevIndex =

this.currentIndex === -1

? this.slides.length - 1

: (this.currentIndex - 1 + this.slides.length) % this.slides.length;

this.setActiveSlide(prevIndex);

}

}

 

document.addEventListener("DOMContentLoaded", () => {

new AccordionSlider();

});

 

 

Comments