릴 레이아웃

Reel layout

줄바꿈 없이 가로로만 스크롤되는 한 줄 레이아웃. 넷플릭스 썸네일 행이 전형적인 예입니다.

다른 이름: Every Layout ReelHorizontal scroller
···
html
<div class="frame">
  <div class="reel" id="reel">
    <div class="card">1</div><div class="card">2</div><div class="card">3</div>
    <div class="card">4</div><div class="card">5</div><div class="card">6</div>
  </div>
</div>
css
.frame{width:min(80%,440px);box-sizing:border-box;border:1px solid var(--line);border-radius:12px;padding:12px;background:var(--bg)}
.reel{display:flex;gap:8px;overflow-x:auto;scroll-snap-type:x mandatory;scrollbar-width:none;
  -webkit-mask-image:linear-gradient(90deg,transparent,#000 6%,#000 94%,transparent);
  mask-image:linear-gradient(90deg,transparent,#000 6%,#000 94%,transparent)}
.reel::-webkit-scrollbar{display:none}
.card{flex:0 0 auto;width:64px;height:64px;border-radius:10px;background:var(--accent);scroll-snap-align:start;
  display:grid;place-items:center;color:#fff;font-weight:800;font-size:16px}
.card:nth-child(even){background:var(--accent-3)}
js
const reel = document.getElementById('reel');
let dir = 1;
function tick() {
  const max = reel.scrollWidth - reel.clientWidth;
  reel.scrollLeft += dir * 0.7;
  if (reel.scrollLeft >= max - 1) dir = -1;
  if (reel.scrollLeft <= 1) dir = 1;
  requestAnimationFrame(tick);
}
requestAnimationFrame(tick);

기본은 `display: flex`에 `overflow-x: auto`, 그리고 자식마다 `flex: 0 0 auto`(줄어들지도 늘어나지도 않고 자기 크기를 유지)입니다. `flex-wrap`을 주지 않으므로 아이템이 한 줄에서 절대 떨어지지 않고, 컨테이너보다 전체 길이가 길어지면 그만큼 가로 스크롤이 생깁니다.

`scroll-snap-type: x mandatory`를 부모에, `scroll-snap-align: start`를 자식에 주면 스크롤이 끝났을 때 아이템 경계에 딱 맞춰 멈춥니다 — 드래그나 스와이프가 어중간한 위치에서 멈추지 않게 하는 장치입니다. 스크롤바 자체는 `scrollbar-width: none`(Firefox)·`::-webkit-scrollbar { display: none }`(Chromium 계열)로 숨기고, 대신 좌우 끝에 `mask-image` 그라디언트를 줘서 "더 스크롤할 게 있다"는 신호를 은은하게 남기는 경우가 많습니다.

세로 방향 릴(예: 사진 스토리 목록)도 축만 바꾸면 똑같이 동작합니다. 다만 릴 안의 콘텐츠가 키보드·스크린 리더로도 하나씩 접근 가능해야 하므로, 순수 장식용 캐러셀이 아니라면 각 아이템이 포커스 가능한 요소(링크·버튼)여야 접근성이 깨지지 않습니다.

언제 쓰나

항목 수가 가변적이고 "한눈에 다 안 보여도 되는" 추천 목록, 카테고리 탭, 갤러리 썸네일에 씁니다. 핵심 내비게이션처럼 반드시 다 보여야 하는 항목에는 적합하지 않습니다.