웹 개발에서 이미지 슬라이더는 매우 자주 사용되는 UI 컴포넌트입니다. 오늘은 바닐라 JavaScript와 CSS만을 사용해서 반응형 이미지 슬라이더를 처음부터 구현하는 방법을 알아보겠습니다.
구현 목표
- 바닐라 JavaScript로 구현 (라이브러리 없음)
- 반응형 디자인 지원
- 부드러운 애니메이션 효과
- 좌우 화살표 버튼으로 네비게이션
- 깔끔하고 모던한 UI
HTML 구조
먼저 슬라이더의 기본 HTML 구조를 살펴보겠습니다:
<div class="tokyoaj-slider-container">
<button class="tokyoaj-slider-btn left"><span>‹</span></button>
<div class="tokyoaj-slider-wrapper">
<div class="tokyoaj-slide" style="margin-left: 20px;">
<img src="poster/image1.png" alt="Slide 1">
<div class="slide-info">
<h3>Slide 1</h3>
</div>
</div>
<!-- 추가 슬라이드들... -->
</div>
<button class="tokyoaj-slider-btn right">›</button>
</div>
구조 설명
tokyoaj-slider-container
: 전체 슬라이더를 감싸는 컨테이너tokyoaj-slider-wrapper
: 슬라이드들을 감싸는 래퍼 (transform 애니메이션 적용)tokyoaj-slide
: 개별 슬라이드 아이템tokyoaj-slider-btn
: 좌우 네비게이션 버튼
CSS 스타일링
컨테이너 및 래퍼 스타일
/* 슬라이더 컨테이너 */
.tokyoaj-slider-container {
position: relative;
margin: 40px auto;
overflow: hidden;
}
/* 슬라이더 래퍼 */
.tokyoaj-slider-wrapper {
display: flex;
gap: 16px;
transition: transform 0.4s cubic-bezier(0.4, 0, 0.2, 1);
}
슬라이드 아이템 스타일
/* 슬라이드 아이템 */
.tokyoaj-slide {
box-sizing: border-box;
width: 270px;
}
.tokyoaj-slide img {
display: block;
width: 270px;
height: 385px;
border-radius: 10px;
}
/* 슬라이드 정보 */
.slide-info {
margin-top: 8px;
text-align: center;
color: white;
}
네비게이션 버튼 스타일
/* 슬라이더 버튼 */
.tokyoaj-slider-btn {
position: absolute;
top: 200px;
transform: translateY(-50%);
z-index: 2;
display: flex;
align-items: center;
justify-content: center;
width: 40px;
height: 40px;
background: rgba(0, 0, 0, 0.5);
color: #fff;
border: none;
border-radius: 50%;
font-size: 1.5rem;
cursor: pointer;
}
.tokyoaj-slider-btn.left {
left: 16px;
}
.tokyoaj-slider-btn.right {
right: 16px;
}
JavaScript 구현
상수 및 변수 정의
// ===== 상수 정의 =====
const SLIDE_GAP = 16;
const FIRST_SLIDE_MARGIN = 20;
// ===== DOM 요소 선택 =====
const wrapper = document.querySelector('.tokyoaj-slider-wrapper');
const slides = document.querySelectorAll('.tokyoaj-slide');
const btnLeft = document.querySelector('.tokyoaj-slider-btn.left');
const btnRight = document.querySelector('.tokyoaj-slider-btn.right');
const container = document.querySelector('.tokyoaj-slider-container');
// ===== 상태 변수 =====
let currentIndex = 0;
핵심 함수들
1. 화면에 보이는 슬라이드 개수 계산
function getVisibleSlides() {
if (!container || !slides.length) return 1;
const slideWidth = slides[0].offsetWidth + SLIDE_GAP;
const availableWidth = container.offsetWidth - FIRST_SLIDE_MARGIN;
return Math.floor(availableWidth / slideWidth);
}
2. 슬라이더 위치 업데이트
function updateSlider() {
const slideWidth = slides[0].offsetWidth + SLIDE_GAP;
const visibleSlides = getVisibleSlides();
const maxIndex = Math.max(0, slides.length - visibleSlides);
// 현재 인덱스가 최대값을 초과하지 않도록 조정
if (currentIndex > maxIndex) {
currentIndex = maxIndex;
}
// transform 값 계산
let translateX;
if (currentIndex === maxIndex && maxIndex > 0) {
// 마지막 위치: 마지막 슬라이드들이 컨테이너 끝에 맞춰지도록 계산
const totalWidth = slides.length * slideWidth + FIRST_SLIDE_MARGIN;
const containerWidth = container.offsetWidth;
translateX = totalWidth - containerWidth;
} else {
// 일반적인 경우
translateX = currentIndex * slideWidth;
}
// 슬라이더 이동 애니메이션 적용
[wrapper.style](<http://wrapper.style>).transform = `translateX(-${translateX}px)`;
// 버튼 활성화/비활성화 상태 업데이트
updateButtonStates(maxIndex);
}
3. 네비게이션 함수들
function moveToPrevious() {
if (currentIndex > 0) {
currentIndex = Math.max(0, currentIndex - 1);
updateSlider();
}
}
function moveToNext() {
const visibleSlides = getVisibleSlides();
const maxIndex = Math.max(0, slides.length - visibleSlides);
if (currentIndex < maxIndex) {
currentIndex++;
updateSlider();
}
}
이벤트 리스너 등록
// ===== 이벤트 리스너 등록 =====
btnLeft.addEventListener('click', moveToPrevious);
btnRight.addEventListener('click', moveToNext);
window.addEventListener('resize', updateSlider);
// ===== 초기화 =====
updateSlider();
주요 특징
1. 반응형 디자인
- 화면 크기에 따라 보이는 슬라이드 개수가 자동으로 조정됩니다
getVisibleSlides()
함수가 현재 컨테이너 크기를 계산하여 적절한 개수를 반환합니다
2. 부드러운 애니메이션
- CSS
transition
과 cubic-bezier
함수를 사용하여 자연스러운 애니메이션을 구현했습니다 transform: translateX()
를 사용하여 GPU 가속을 활용합니다
3. 지능적인 위치 계산
- 마지막 위치에서는 마지막 슬라이드들이 컨테이너 끝에 정확히 맞춰지도록 계산합니다
- 첫 번째 슬라이드의 마진도 고려하여 정확한 위치를 계산합니다
4. 사용자 경험 개선
- 버튼 비활성화로 사용자에게 현재 상태를 명확히 알려줍니다
resize
이벤트를 통해 화면 크기 변화에 실시간으로 대응합니다
코드 최적화 포인트
1. 상수 사용
const SLIDE_GAP = 16;
const FIRST_SLIDE_MARGIN = 20;
매직 넘버를 상수로 정의하여 유지보수성을 높였습니다.
2. 함수 분리
각 기능을 별도 함수로 분리하여 코드의 가독성과 재사용성을 높였습니다.
3. JSDoc 주석
/**
* 현재 화면에 보이는 슬라이드 개수 계산
* @returns {number} 보이는 슬라이드 개수
*/
함수의 목적과 반환값을 명확히 문서화했습니다.
모바일 대응
이 슬라이더는 반응형으로 설계되어 모바일 환경에서도 잘 작동합니다:
- 화면 크기에 따른 자동 조정
- 터치 이벤트 지원 (필요시 추가 구현 가능)
- 적절한 버튼 크기와 간격
확장 가능성
현재 구현을 기반으로 다음과 같은 기능들을 추가할 수 있습니다:
- 터치/스와이프 제스처 지원
- 자동 슬라이드 기능
- 인디케이터 도트
- 무한 루프 슬라이딩
- 키보드 네비게이션
마무리
바닐라 JavaScript만으로도 충분히 성능 좋고 사용자 친화적인 슬라이더를 구현할 수 있습니다. 라이브러리에 의존하지 않고 직접 구현함으로써:
- 성능 최적화: 불필요한 코드 없이 필요한 기능만 구현
- 커스터마이징: 프로젝트 요구사항에 맞게 자유롭게 수정 가능
- 학습 효과: JavaScript와 CSS의 핵심 개념들을 깊이 이해
- 유지보수: 코드의 모든 부분을 이해하고 있어 문제 해결이 용이
이 슬라이더 구현을 통해 웹 개발의 기본기를 다지고, 더 복잡한 UI 컴포넌트 개발에도 자신감을 가질 수 있을 것입니다.
댓글