TokyoAJ

도쿄아재

MEMO 2025.06.28

반응형 이미지 슬라이더 구현하기 - 바닐라 JavaScript

웹 개발에서 이미지 슬라이더는 매우 자주 사용되는 UI 컴포넌트입니다. 오늘은 바닐라 JavaScript와 CSS만을 사용해서 반응형 이미지 슬라이더를 처음부터 구현하는 방법을 알아보겠습니다.


구현 목표

  1. 바닐라 JavaScript로 구현 (라이브러리 없음)
  2. 반응형 디자인 지원
  3. 부드러운 애니메이션 효과
  4. 좌우 화살표 버튼으로 네비게이션
  5. 깔끔하고 모던한 UI

HTML 구조

먼저 슬라이더의 기본 HTML 구조를 살펴보겠습니다:

<div class="tokyoaj-slider-container">
<button class="tokyoaj-slider-btn left"><span>&#8249;</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">&#8250;</button>
</div>

구조 설명

  1. tokyoaj-slider-container: 전체 슬라이더를 감싸는 컨테이너
  2. tokyoaj-slider-wrapper: 슬라이드들을 감싸는 래퍼 (transform 애니메이션 적용)
  3. tokyoaj-slide: 개별 슬라이드 아이템
  4. 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. 반응형 디자인

  1. 화면 크기에 따라 보이는 슬라이드 개수가 자동으로 조정됩니다
  2. getVisibleSlides() 함수가 현재 컨테이너 크기를 계산하여 적절한 개수를 반환합니다

2. 부드러운 애니메이션

  1. CSS transitioncubic-bezier 함수를 사용하여 자연스러운 애니메이션을 구현했습니다
  2. transform: translateX()를 사용하여 GPU 가속을 활용합니다

3. 지능적인 위치 계산

  1. 마지막 위치에서는 마지막 슬라이드들이 컨테이너 끝에 정확히 맞춰지도록 계산합니다
  2. 첫 번째 슬라이드의 마진도 고려하여 정확한 위치를 계산합니다

4. 사용자 경험 개선

  1. 버튼 비활성화로 사용자에게 현재 상태를 명확히 알려줍니다
  2. resize 이벤트를 통해 화면 크기 변화에 실시간으로 대응합니다

코드 최적화 포인트

1. 상수 사용

const SLIDE_GAP = 16;
const FIRST_SLIDE_MARGIN = 20;

매직 넘버를 상수로 정의하여 유지보수성을 높였습니다.

2. 함수 분리

각 기능을 별도 함수로 분리하여 코드의 가독성과 재사용성을 높였습니다.

3. JSDoc 주석

/**
* 현재 화면에 보이는 슬라이드 개수 계산
* @returns {number} 보이는 슬라이드 개수
*/

함수의 목적과 반환값을 명확히 문서화했습니다.

모바일 대응

이 슬라이더는 반응형으로 설계되어 모바일 환경에서도 잘 작동합니다:

  1. 화면 크기에 따른 자동 조정
  2. 터치 이벤트 지원 (필요시 추가 구현 가능)
  3. 적절한 버튼 크기와 간격

확장 가능성

현재 구현을 기반으로 다음과 같은 기능들을 추가할 수 있습니다:

  1. 터치/스와이프 제스처 지원
  2. 자동 슬라이드 기능
  3. 인디케이터 도트
  4. 무한 루프 슬라이딩
  5. 키보드 네비게이션

마무리

바닐라 JavaScript만으로도 충분히 성능 좋고 사용자 친화적인 슬라이더를 구현할 수 있습니다. 라이브러리에 의존하지 않고 직접 구현함으로써:

  1. 성능 최적화: 불필요한 코드 없이 필요한 기능만 구현
  2. 커스터마이징: 프로젝트 요구사항에 맞게 자유롭게 수정 가능
  3. 학습 효과: JavaScript와 CSS의 핵심 개념들을 깊이 이해
  4. 유지보수: 코드의 모든 부분을 이해하고 있어 문제 해결이 용이

이 슬라이더 구현을 통해 웹 개발의 기본기를 다지고, 더 복잡한 UI 컴포넌트 개발에도 자신감을 가질 수 있을 것입니다.

댓글