안녕하세요! 프론트엔드 개발자 여러분을 위한 강사입니다.
오늘은 그동안 우리를 정말 많이 괴롭혀왔던 UI 요소죠? 바로 '캐러셀(Carousel, 슬라이드 갤러리)'을 자바스크립트 단 한 줄 없이 순수 CSS만으로 완벽하게 구현하는 방법에 대해 MDN 공식 문서를 통해 배워보겠습니다.
이전에는 JS로 transform: translateX 값을 일일이 계산하고, 리사이즈 이벤트 달고, 접근성 챙기느라 코드가 정말 지저분해졌는데, 이제는 브라우저가 네이티브로 다 알아서 해줍니다! 제 실무 경험을 팍팍 녹여서 꿀팁과 함께 아주 쉽고 재밌게 설명해 드릴게요. 자, 시작해 볼까요?
CSS 오버플로우(overflow) 모듈은 브라우저가 생성하고 개발자가 스타일을 지정할 수 있는 스크롤 버튼과 스크롤 마커를 사용해서 아주 유연한 순수 CSS 캐러셀을 만들 수 있는 기능들을 정의하고 있어요. 이 가이드에서는 이런 최신 기능들을 사용해서 캐러셀을 어떻게 만드는지 자세히 설명해 드립니다.
👨🏫 강사님의 꿀팁:
이 문서는 최신 CSS 스펙인::scroll-button과::scroll-marker등을 다룹니다. 아직 모든 브라우저에서 완벽하게 지원되지 않을 수 있으니 실무 적용 시에는 항상 Can I Use 같은 사이트에서 브라우저 호환성을 먼저 체크하는 습관을 들이세요!
캐러셀(Carousels)은 웹에서 정말 흔하게 볼 수 있는 기능이에요. 프레젠테이션 슬라이드, 광고 배너, 주요 뉴스 기사, 핵심 제품 특징 등 여러 항목을 담고 있는 스크롤 가능한 콘텐츠 영역의 형태를 띠고 있죠.
사용자는 클릭이나 내비게이션 버튼을 누르거나 화면을 스와이프해서 항목들을 넘겨볼 수 있습니다. 이 내비게이션에는 보통 다음 요소들이 포함됩니다:
캐러셀의 아주 핵심적인 특징은 페이지네이션(pagination)입니다. 콘텐츠가 하나로 쭉 이어져서 스크롤되는 것이 아니라, 마치 책을 넘기듯 독립적인 조각들 사이를 이동하는 느낌을 줘야 해요. 한 번에 한 항목만 보여줄 수도 있고, 캐러셀의 한 "페이지" 화면에 여러 항목을 보여줄 수도 있습니다. 여러 항목이 보일 때는 "다음"이나 "이전" 버튼을 누를 때마다 완전히 새로운 항목 그룹을 보여줄 수도 있고, 리스트의 한쪽 끝에 새 항목을 하나 추가하면서 반대쪽 항목은 시야에서 밀어내는 식으로 움직일 수도 있죠.
기존에는 자바스크립트로 캐러셀을 구현하기가 꽤나 까다롭고 버그가 나기 쉬웠습니다(brittle). 스크롤 마커와 그것이 나타내는 항목을 연결해 주는 스크립트가 필요했고, 동시에 스크롤 버튼이 제대로 동작하도록 상태를 계속 업데이트해 줘야만 했거든요.
하지만 다행히도, 이제 우리는 자바스크립트를 전혀 쓰지 않고 CSS 캐러셀 기능들만을 이용해서 내비게이션 컨트롤이 완벽하게 연결된 캐러셀을 만들 수 있게 되었습니다!
CSS 캐러셀 기능들은 오로지 CSS와 HTML만으로 캐러셀을 만들 수 있게 해주는 가상 요소(pseudo-elements)와 가상 클래스(pseudo-classes)를 제공합니다. 스크롤링과 링크 참조 처리의 대부분을 브라우저가 직접, 매우 유연하고 일관된 방식으로 알아서 처리해 주죠. 이 기능들은 다음과 같습니다:
::scroll-button()::scroll-marker-group::scroll-marker::scroll-marker-group 안에 차곡차곡 모이게 됩니다.:target-current:target-before 와 :target-after::column::scroll-marker와 함께 써서 각 단마다 스크롤 마커를 하나씩 만들어줄 수 있어요.👨🏫 강사님의 꿀팁:
방금 나온 가상 요소들은 정말 마법 같습니다. 과거에는 JS로div태그를 동적으로 생성해서 마커를 만들었는데, 이제는 브라우저가 요소의 상태를 감지해서 DOM 구조 밖에서(CSS 렌더링 트리에서) 알아서 버튼과 마커를 만들어줍니다. HTML이 훨씬 깔끔해진다는 뜻이죠!
첫 번째 예제는 각 항목이 전체 화면(페이지)을 꽉 채우는 단일 페이지 캐러셀입니다. 화면 하단 내비게이션으로 사용할 스크롤 마커가 있고, 사용자가 이전/다음 페이지로 이동할 수 있도록 양옆에 스크롤 버튼이 배치되어 있어요.
우리는 캐러셀 레이아웃을 잡기 위해 flexbox를 사용할 거고요, 페이지가 깔끔하게 딱딱 떨어지도록 리스트에 스크롤 스냅(scroll snapping)을 설정할 겁니다. 그리고 앵커 포지셔닝(anchor positioning)을 이용해서 스크롤 버튼과 마커의 위치를 캐러셀을 기준으로 멋지게 잡아볼 거예요.
HTML 구조는 제목 태그(heading) 하나와 순서 없는 리스트(ul)로 이루어져 있습니다. 각 리스트 아이템(li)에는 예시용 콘텐츠와 함께 우리가 커스텀으로 만든 data- 속성(스타일링 부분에서 어떻게 쓰이는지 설명할게요)이 들어있습니다:
<h1>CSS carousel single item per page</h1>
<ul>
<li data-accName="Item 1">
<h2>Page 1</h2>
</li>
<li data-accName="Item 2">
<h2>Page 2</h2>
</li>
<li data-accName="Item 3">
<h2>Page 3</h2>
</li>
<li data-accName="Item 4">
<h2>Page 4</h2>
</li>
</ul>
flexbox를 사용해서 아이템들을 한 줄로 길게 배치해 보겠습니다. <ul>이 플렉스 컨테이너가 되고, 자식 요소인 <li> 아이템들이 가로로 나열되면서 각각이 캐러셀의 전체 너비를 차지하게 될 거예요.
리스트(<ul>)가 뷰포트 전체 너비를 꽉 채우도록 너비(width)를 100vw로 주겠습니다. 높이(height)는 300px로 주고 약간의 패딩(padding)도 더할게요. 그런 다음 플렉스박스로 리스트를 정렬합니다. display 값을 flex로 주면 자식 아이템들이 기본적으로 한 줄(row 방향)로 표시되고, 각 아이템 사이의 간격(gap)은 4vw로 설정해 줍니다.
* {
box-sizing: border-box;
}
body {
margin: 0;
font-family: "Helvetica", "Arial", sans-serif;
}
h1 {
text-align: center;
font-size: 1.7rem;
}
ul {
width: 100vw;
height: 300px;
padding: 20px;
display: flex;
gap: 4vw;
}
이제 리스트 아이템(<li>)을 꾸며볼 차례입니다. 앞부분의 선언들은 기본적인 모양을 잡아주는 것들이고요. 여기서 가장 중요한 건 바로 flex 속성에 0 0 100%를 준 것입니다! 이 속성은 각 아이템이 컨테이너(<ul>)의 너비와 무조건 똑같이 늘어나도록 강제합니다. 그 결과 내용물들이 컨테이너 바깥으로 흘러넘치게(overflow) 되고, 뷰포트는 가로 스크롤이 생기게 되죠.
li {
list-style-type: none;
background-color: #eeeeee;
border: 1px solid #dddddd;
padding: 20px;
flex: 0 0 100%;
}
li:nth-child(even) {
background-color: cyan;
}
추가로, 스크롤되는 시각적 효과를 훨씬 더 잘 보여주기 위해 :nth-child()를 이용해서 짝수 번째 리스트 아이템들의 배경색을 다르게 주었습니다.
이 섹션에서는 <ul>에 overflow 값을 설정해서 요소를 스크롤 컨테이너로 변신시켜 볼 거예요. 그런 다음 CSS 스크롤 스냅(scroll snapping)을 적용해서 콘텐츠를 스크롤할 때 리스트가 각 아이템의 정중앙에 '착' 하고 자석처럼 달라붙게(snap) 만들 겁니다.
우선 <ul>에 overflow-x 값을 scroll로 줍니다. 이렇게 하면 브라우저 전체 창이 스크롤되는 게 아니라 리스트 내부에서만 가로 스크롤이 동작하게 돼요.
그 다음엔 각 "페이지"에 맞게 스냅되도록 CSS 스크롤 스냅을 사용합니다. 리스트를 스크롤 스냅 컨테이너로 만들기 위해 scroll-snap-type 값을 x mandatory로 설정해 줍니다. 여기서 x 키워드는 가로 방향으로 스냅하겠다는 뜻이고, mandatory 키워드는 스크롤 동작이 끝날 때 컨테이너가 반드시 스냅 타겟(아이템) 중 하나에 무조건 달라붙어야 한다는 강력한 규칙을 의미해요.
ul {
overflow-x: scroll;
scroll-snap-type: x mandatory;
}
👨🏫 강사님의 꿀팁:
scroll-snap-type에서mandatory대신proximity를 쓸 수도 있어요.mandatory는 무조건 가장 가까운 요소로 강제 이동시키는 반면,proximity는 스크롤을 멈춘 곳이 요소의 경계와 충분히 가까울 때만 스냅됩니다. 캐러셀에서는 페이지가 중간에 걸치면 안 되니까mandatory가 훨씬 적합하죠!
이제 리스트 아이템(<li>)에 scroll-snap-align 값을 center로 줍니다. 그러면 리스트를 스크롤했을 때 뷰포트의 정중앙이 아이템의 정중앙과 딱 맞게 정렬됩니다.
li {
scroll-snap-align: center;
}
여기까지 작성하면 스와이프를 하거나 스크롤바를 움직였을 때 아이템이 중간에 멈추지 않고 항상 제자리에 '착' 달라붙는 캐러셀의 기본 뼈대가 완성됩니다.
참고 (Note):
CSS 스크롤 스냅을 쓰지 않아도 CSS 캐러셀 기능 자체는 동작합니다. 하지만 스크롤 스냅을 같이 썼을 때 캐러셀이 훨씬 더 완벽하게 작동해요. 스크롤 스냅이 없으면 스크롤 버튼과 마커가 페이지 사이를 깔끔하게 이동시키지 못해서 결과물이 엉성해질 확률이 높습니다.
이제 사용자가 캐러셀 페이지 사이를 넘나들 수 있는 멋진 "이전" / "다음" 스크롤 버튼을 추가해 볼 거예요. 바로 여기서 ::scroll-button() 가상 요소를 사용합니다!
::scroll-button() 가상 요소는 스크롤 컨테이너 내부에 생성되는데요, 단 조건이 있습니다. content 속성에 none이 아닌 무언가 값이 들어있어야만 비로소 화면에 나타나요.
각 ::scroll-button()은 선택자의 괄호 안 인자에 지정된 방향으로 컨테이너 내용을 스크롤해주는 역할을 찰떡같이 수행합니다. 한 스크롤 컨테이너당 최대 4개(상, 하, 좌, 우)의 스크롤 버튼을 만들 수 있어요.
또한 * 인자를 쓰면(::scroll-button(*)) 모든 스크롤 버튼을 한 번에 잡아서 공통 스타일을 줄 수도 있습니다.
우선 모든 스크롤 버튼을 묶어서 기본적인 스타일과 상태별 스타일을 입혀볼게요. 키보드 사용자를 위해 :focus 스타일을 지정하는 건 웹 접근성을 위해 아주 중요합니다!
그리고 스크롤할 수 있는 한계치에 도달하면(더 이상 이동할 아이템이 없으면) 스크롤 버튼이 자동으로 disabled 상태로 변합니다. 우리는 :disabled 가상 클래스를 써서 이 비활성화 상태일 때의 스타일도 예쁘게 처리할 거예요.
ul::scroll-button(*) {
border: 0;
font-size: 2rem;
background: none;
color: black;
opacity: 0.7;
cursor: pointer;
}
ul::scroll-button(*):hover,
ul::scroll-button(*):focus {
opacity: 1;
}
ul::scroll-button(*):active {
translate: 1px 1px;
}
ul::scroll-button(*):disabled {
opacity: 0.2;
cursor: unset;
}
참고 (Note):
사용자가 '이게 누를 수 있는 버튼이구나' 하고 직관적으로 알 수 있도록 스크롤 버튼에cursor: pointer를 주었습니다 (일반적인 사용성(UX)과 인지적 접근성 향상에 좋아요). 그리고 비활성화(:disabled)되었을 때는 커서를 다시 해제(unset)했습니다.
다음으로, content 속성을 이용해서 왼쪽 버튼과 오른쪽 버튼에 예쁜 화살표 아이콘을 넣어줍니다. 이 속성 덕분에 실제 버튼이 브라우저에 렌더링 되는 거예요.
이때 스크린 리더 같은 접근성 도구를 위해 아이콘이 무엇을 의미하는지 문자로 된 '접근성 이름(accessible name)'도 같이 적어줘야 합니다. content 속성의 대체 텍스트 기능(/ 기호 뒤에 문자열 작성)을 사용해 볼게요.
ul::scroll-button(left) {
content: "◄" / "Previous";
}
ul::scroll-button(right) {
content: "►" / "Next";
}
👨🏫 강사님의 꿀팁:
과거에는button태그를 만들고 그 안에aria-label="Previous"같은 속성을 직접 달아줬죠. 이제는 CSS의content속성에서"텍스트" / "대체텍스트"문법을 통해 CSS만으로 스크린 리더용 텍스트를 제공할 수 있습니다. 정말 우아한 문법이죠!
버튼이 생겼으니 이제 CSS 앵커 포지셔닝(anchor positioning)을 이용해서 캐러셀을 기준으로 버튼을 알맞은 자리에 예쁘게 배치해 보겠습니다.
먼저, 리스트(<ul>)에 기준점 이름이 될 anchor-name을 정해줍니다. 그리고 각 스크롤 버튼의 position을 absolute로 설정하고, 버튼들의 position-anchor 속성을 방금 리스트에 지어준 이름으로 지정해서 두 요소를 하나로 찰떡같이 연결해 줍니다.
ul {
anchor-name: --my-carousel;
}
ul::scroll-button(*) {
position: absolute;
position-anchor: --my-carousel;
}
👨🏫 강사님의 꿀팁:
여기서 잠깐! 예전에는 버튼을 캐러셀 위로 띄우려면<ul>과 버튼들을relative속성이 들어간 거대한<div class="wrapper">로 감싸야만 했어요. 하지만 앵커 포지셔닝을 쓰면 래퍼(wrapper) 태그 없이 특정 요소(--my-carousel)를 기준으로 바로 위치를 띄울 수 있습니다. DOM 트리가 놀라울 정도로 얕고 깨끗해집니다.
실제로 버튼 위치를 옮기려면 inset 관련 속성들(top, bottom, left, right)에 값을 주면 됩니다. anchor() 함수를 써서 캐러셀 모서리를 기준으로 버튼 면의 위치를 잡습니다. 이때 버튼과 캐러셀 모서리 사이에 약간의 여백을 두기 위해 calc() 함수를 사용해요.
예를 들어, 왼쪽 스크롤 버튼의 우측 끝(right)은 캐러셀의 왼쪽 경계선(anchor(left))으로부터 안쪽으로 70px 떨어진 곳으로 이동시키는 식입니다.
ul::scroll-button(left) {
right: calc(anchor(left) - 70px);
bottom: calc(anchor(top) + 13px);
}
ul::scroll-button(right) {
left: calc(anchor(right) - 70px);
bottom: calc(anchor(top) + 13px);
}
이제 첫 번째 항목에 있을 땐 '이전' 버튼이 비활성화되고, 맨 끝에 도착하면 '다음' 버튼이 자동으로 비활성화되는 똑똑한 버튼이 완성되었습니다!
스크롤 마커는 점(버튼)들의 묶음으로, 각각의 점을 누르면 해당하는 콘텐츠 페이지 위치로 스르륵 넘어가게 해줍니다. 추가적인 내비게이션 역할뿐만 아니라, 사용자가 현재 캐러셀의 어느 위치를 보고 있는지 알려주는 인디케이터 역할도 하죠.
이 섹션에서 캐러셀에 스크롤 마커를 추가할 텐데요, 크게 다음 3가지 핵심 기능이 사용됩니다:
scroll-marker-group 속성을 줍니다. none이 아닌 값을 줘야 브라우저가 내부적으로 ::scroll-marker-group 가상 요소를 만들어냅니다. 이 속성의 값은 탭(Focus) 순서나 레이아웃 박스 순서에서 마커 그룹이 어디에 올지를 결정해요. before를 쓰면 콘텐츠 앞쪽에, after를 쓰면 콘텐츠 뒤쪽에 옵니다 (실제 DOM 구조가 바뀌는 건 아니에요!).::scroll-marker-group 가상 요소는 스크롤 컨테이너 내부에 존재하며, 스크롤 마커들을 하나로 예쁘게 묶고 레이아웃을 처리하는 '컨테이너' 역할을 합니다.::scroll-marker 가상 요소들은 자식 요소들이나 컬럼(::column) 내부에서 생겨납니다. 이 각각의 마커들은 조상 요소의 ::scroll-marker-group 안으로 쏙 빨려 들어가서 한 줄로 나란히 정렬되게 되죠.우선 리스트(<ul>)의 scroll-marker-group 속성을 after로 설정해 볼게요. 그러면 ::scroll-marker-group이 리스트의 DOM 콘텐츠 뒤쪽에(포커스와 레이아웃 박스 순서상) 배치됩니다. 즉, 스크롤 버튼들 뒤에 마커 그룹이 오게 된다는 뜻이죠.
ul {
scroll-marker-group: after;
}
다음으로 리스트에 생성된 ::scroll-marker-group 가상 요소를 아까 썼던 앵커 포지셔닝을 이용해 배치해 줍니다. 이번엔 캐러셀의 정중앙에 위치시키기 위해 justify-self 값을 anchor-center로 줄 거예요. 그룹 내부는 Flexbox로 정렬하고 justify-content: center와 gap: 20px를 주어 자식들(스크롤 마커들)이 옹기종기 가운데로 모이고 적당히 벌어지게 만듭니다.
ul::scroll-marker-group {
position: absolute;
position-anchor: --my-carousel;
top: calc(anchor(bottom) - 70px);
justify-self: anchor-center;
display: flex;
justify-content: center;
gap: 20px;
}
이제 각각의 마커(점) 자체의 모양을 다듬을 시간입니다. 다른 생성 요소(Generated content)를 스타일링할 때와 똑같이 디자인하면 돼요.
여기서 아주 중요한 포인트! 마커가 화면에 생기게 하려면 반드시 content 속성을 none 이외의 값으로 줘야 합니다. 만약 빈 문자열("")을 주면 접근성 이름이 비어버려서 스크린 리더 사용자에게 심각한 문제가 생겨요 (WCAG 접근성 위반).
모든 마커가 "점" 이라는 똑같은 이름을 가지면 혼란스러울 테니, HTML 태그에 적어뒀던 커스텀 속성(data-accName)의 값을 attr() 함수로 쏙 빼와서 각 마커의 접근성 이름으로 사용하겠습니다.
동시에 시각적으로는 글씨가 안 보이고 동그란 점 모양만 나타나도록 텍스트를 화면 밖으로 숨기는 기본 스타일(text-indent와 overflow: hidden)도 적용합니다.
li::scroll-marker {
content: attr(data-accName);
width: 16px;
height: 16px;
background-color: transparent;
border: 2px solid black;
border-radius: 50%;
overflow: hidden;
text-indent: 16px;
}
마지막으로, 사용자가 어느 위치에 있는지 시각적으로 표시하기 위해 :target-current 가상 클래스로 현재 보고 있는 페이지의 스크롤 마커를 선택합니다. 활성화된 마커는 색을 까맣게 칠해서 눈에 확 띄게 만들어 줄게요.
li::scroll-marker:target-current {
background-color: black;
}
지금까지 작성한 모든 코드가 합쳐지면 스와이프, 버튼 클릭, 하단 마커 클릭 모두 부드럽게 연동되는 완벽한 순수 CSS 슬라이더가 완성됩니다!
직접 접속하셔서 스와이프도 해보시고 탭 키를 눌러서 포커스를 이동시켜보세요. 스크롤 위치에 맞춰 마커의 불이 딱딱 들어오는 걸 확인할 수 있습니다. 자바스크립트가 단 한 줄도 들어가지 않았다는 게 믿어지시나요?
두 번째 예제는 한 화면에 항목이 여러 개 보여지는 형태의 캐러셀입니다. 물론 앞서 배운 스크롤 버튼과 스크롤 마커도 똑같이 들어가고요. 여기서 특별한 점은 바로 반응형(Responsive)이라는 겁니다. 뷰포트(브라우저 창)의 가로 길이를 조절하면 한 페이지에 들어가는 아이템 개수가 유연하게 바뀌어요!
첫 번째 단일 페이지 예제와 구조가 거의 똑같지만, 큰 차이점이 하나 있습니다. 레이아웃을 잡을 때 플렉스박스 대신 CSS 다단 레이아웃(multi-column layout)을 사용합니다. 그리고 각 아이템(<li>) 기준이 아니라, 브라우저가 생성하는 가상의 컬럼 덩어리인 ::column 단위로 스크롤 마커를 달아줄 거예요.
👨🏫 강사님의 꿀팁:
창 크기가 줄어들면 한 화면에 카드 4개가 보이다가 3개, 2개로 자연스럽게 줄어드는 반응형을 만들 때, 이 Multi-column 트릭이 진짜 예술입니다. 컬럼 단위로 스크롤 스냅을 걸기 때문에 카드가 화면 중간에 어중간하게 잘린 채로 멈추는 일(partial item)이 절대 발생하지 않거든요!
HTML 구조는 이전과 같고, 대신 한 화면에 여러 개가 나와야 하니 <li> 항목 개수만 15개로 넉넉히 늘려준 상태입니다.
플렉스박스 대신 columns 속성을 1로 설정해서 꼼수를 부려볼 겁니다. 컨테이너 너비를 강제로 꽉 채우는 1개의 단으로 구성하게 만들고, 그 내부 요소들은 줄 바꿈이 되도록 하는 것이죠. 그리고 text-align: center를 줘서 아이템들이 화면 가운데 정렬되도록 합니다.
ul {
width: 100vw;
height: 300px;
padding: 10px;
overflow-x: scroll;
scroll-snap-type: x mandatory;
columns: 1;
text-align: center;
}
이제 리스트 아이템(<li>)이 여러 개 들어갈 수 있도록 display: inline-block을 주고, 절댓값 너비(width: 200px)를 고정해 줍니다. 이렇게 하면 브라우저 창 너비에 따라서 한 컬럼에 200px짜리 블록이 1개 들어갈지, 3개 들어갈지 자동으로 계산해서 배치해 주게 됩니다.
li {
list-style-type: none;
display: inline-block;
height: 100%;
width: 200px;
background-color: #eeeeee;
border: 1px solid #dddddd;
padding: 20px;
margin: 0 10px;
text-align: left; /* ul의 가운데 정렬 무시하고 다시 왼쪽 정렬 */
}
li:nth-child(even) {
background-color: cyan;
}
이제 대망의 하이라이트입니다. 스크롤 스냅 설정(scroll-snap-align)과 스크롤 마커 생성(::scroll-marker)을 개별 <li>가 아니라 ul::column에 걸어줄 거예요. 즉, 200px짜리 아이템이 3개 묶인 '한 화면(컬럼 덩어리)' 전체가 통째로 스냅되고 덩어리 단위로 마커가 생기게 하는 거죠.
ul::column {
scroll-snap-align: center;
}
ul::column::scroll-marker {
content: "";
width: 16px;
height: 16px;
background-color: transparent;
border: 2px solid black;
border-radius: 10px;
}
마지막으로, :target-current뿐만 아니라 :target-before와 :target-after를 써서 현재 위치 이전의 점들(이미 지나간 과거 페이지)과 이후의 점들(아직 안 본 미래 페이지)의 색상을 다르게 스타일링해 보겠습니다. 트랜지션(transition)을 주면 색이 스르륵 변해서 훨씬 고급스러워져요.
ul::column::scroll-marker:target-before {
border: 2px solid gray;
}
ul::column::scroll-marker:target-current {
background-color: black;
transition: all 0.7s;
}
ul::column::scroll-marker:target-after {
border: 2px solid red;
background-color: red;
}
위의 트릭들을 모두 합치면, 브라우저 크기를 줄였다 늘려도 빈틈없이 꽉 들어차면서 부드럽게 넘어가는 반응형 캐러셀이 완성됩니다!
Playground에 들어가셔서 꼭 브라우저의 가로 폭을 줄였다 늘려보세요. 카드가 4개에서 3개, 2개로 재배치될 때마다 하단의 스크롤 마커(점) 개수도 자바스크립트 도움 없이 알아서(동적으로) 변하는 짜릿한 마법을 경험하실 수 있습니다.
이 엄청난 CSS 기능들에 대해 더 자세히 파헤쳐보고 싶다면 다음 공식 문서를 꼭 읽어보시길 권해드립니다!
어떠셨나요? 자바스크립트의 영역이라고만 생각했던 복잡한 슬라이더 제어 로직을 이제 CSS 엔진이 완벽하게 흡수해가고 있습니다. 최신 트렌드를 익혀서 실무에서 코드를 대폭 다이어트해 보세요! 질문 있으시면 언제든 편하게 물어보세요!