스토리 구성요소 빌드

웹의 Instagram 스토리와 유사한 환경을 구축하는 방법에 관한 기본적인 개요입니다.

이 게시물에서는 반응성이 좋고 키보드 탐색을 지원하며 여러 브라우저에서 작동하는 웹용 스토리 구성요소를 빌드하는 방법을 공유하고자 합니다.

데모

이 스토리 구성요소를 직접 빌드하는 실습 데모를 보려면 스토리 구성요소 Codelab을 확인하세요.

동영상을 선호한다면 이 게시물의 YouTube 버전을 참조하세요.

개요

스토리 UX의 대표적인 두 가지로는 Snapchat Stories와 Instagram Stories가 있습니다. 일반적으로 UX 용어에서 스토리는 여러 구독을 탐색하기 위한 모바일 전용 탭 중심 패턴입니다. 예를 들어 Instagram에서 사용자는 친구의 스토리를 열고 그 안의 사진들을 살펴봅니다. 보통 한 번에 이렇게 많은 친구를 만듭니다. 기기의 오른쪽을 탭하면 친구의 다음 스토리로 건너뜁니다. 사용자가 오른쪽으로 스와이프하면 다른 친구로 건너뜁니다. 스토리 구성요소는 캐러셀과 상당히 비슷하지만, 1차원 배열과 달리 다차원 배열을 탐색할 수 있습니다. 마치 각 캐러셀 안에 캐러셀이 있는 것과 같습니다. 🤯

카드를 사용하여 시각화된 다차원 배열입니다. 왼쪽에서 오른쪽으로 보라색 테두리 카드가 쌓이고, 각 카드 안에는 청록색 테두리가 1개 있는 카드가 있습니다. 목록의 목록입니다.
첫 번째 친구 캐러셀
두 번째 '스택' 캐러셀
👍 목록(일명 다차원 배열) 목록

작업에 적합한 도구 선택

저는 이 구성요소가 몇 가지 중요한 웹 플랫폼 기능 덕에 매우 간단하게 빌드할 수 있었습니다. 이제부터 살펴보겠습니다.

CSS 그리드

레이아웃은 콘텐츠를 랭글링하는 강력한 방법을 갖추고 있기 때문에 CSS 그리드를 그리 어렵지 않은 것으로 나타났습니다.

친구 레이아웃

기본 .stories 구성요소 래퍼는 모바일 중심 가로 스크롤 뷰입니다.

.stories {
  inline-size: 100vw;
  block-size: 100vh;

  display: grid;
  grid: 1fr / auto-flow 100%;
  gap: 1ch;

  overflow-x: auto;
  scroll-snap-type: x mandatory;
  overscroll-behavior: contain;
  touch-action: pan-x;
}

/* desktop constraint */
@media (hover: hover) and (min-width: 480px) {
  max-inline-size: 480px;
  max-block-size: 848px;
}
Chrome DevTools의 기기 모드를 사용하여 그리드로 만든 열 강조표시

grid 레이아웃을 자세히 살펴보겠습니다.

  • 모바일의 표시 영역을 명시적으로 100vh100vw로 채우고 데스크톱의 크기를 제한합니다.
  • /는 행 및 열 템플릿을 분리합니다.
  • auto-flowgrid-auto-flow: column로 번역됩니다.
  • 자동 흐름 템플릿은 100%이며 이 경우에는 스크롤 창 너비와 같습니다.

휴대전화에서는 행 크기가 표시 영역 높이이고 각 열이 표시 영역 너비가 된다고 생각하면 됩니다. Snapchat Stories 및 Instagram Stories 예에서 각 열은 친구의 스토리가 됩니다. 친구 스토리가 표시 영역 밖에서 계속되도록 하여 스크롤할 위치를 확보하려고 합니다. 그리드는 각 친구 스토리의 HTML 레이아웃에 필요한 열을 많이 만들어 동적인 반응형 스크롤 컨테이너를 만듭니다. 그리드 덕분에 전체 효과를 집중할 수 있었습니다.

스태킹

친구마다 페이지로 나누기 지원 상태의 스토리가 필요합니다. 애니메이션과 다른 재미있는 패턴에 대비하여 스택을 선택했습니다. 쌓아 올린다는 것은 옆으로 내려다보는 것이 아니라 샌드위치를 내려다보는 것과 같습니다.

CSS 그리드를 사용하면 행과 열이 별칭 ([story])을 공유하는 단일 셀 그리드 (정사각형)를 정의할 수 있으며, 그러면 각 하위 요소가 별칭이 지정된 단일 셀 공간에 할당됩니다.

.user {
  display: grid;
  grid: [story] 1fr / [story] 1fr;
  scroll-snap-align: start;
  scroll-snap-stop: always;
}
.story {
  grid-area: story;
  background-size: cover;
  …
}

이렇게 하면 HTML이 스택 순서를 제어하고 모든 요소가 계속 흐릅니다. absolute 위치 지정 또는 z-index로 아무것도 할 필요가 없고 height: 100% 또는 width: 100%로 박스를 올바르게 지정할 필요가 없다는 점에 유의하세요. 상위 그리드는 이미 스토리 사진 표시 영역의 크기를 정의했으므로 이러한 스토리 구성요소 중 어느 것도 이를 채우도록 지시하지 않아도 됩니다.

CSS 스크롤 스냅 포인트

CSS 스크롤 스냅 포인트 사양을 사용하면 스크롤 시 간편하게 표시 영역에 요소를 고정할 수 있습니다. 이러한 CSS 속성이 존재하기 전에는 자바스크립트를 사용해야 했고, 적어도 말하기는 어려웠습니다. 사라 드라스너의 CSS 스크롤 스냅 포인트 소개에서 사용 방법을 자세히 알아보세요.

scroll-snap-points 스타일을 사용하거나 사용하지 않은 경우 가로 스크롤 없으면 사용자가 평소대로 자유롭게 스크롤할 수 있습니다. 덕분에 브라우저가 각 항목에 부드럽게 놓여 있습니다.
parent
.stories {
  display: grid;
  grid: 1fr / auto-flow 100%;
  gap: 1ch;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  overscroll-behavior: contain;
  touch-action: pan-x;
}
오버스크롤이 있는 상위 요소는 맞추기 동작을 정의합니다.
어린이
.user {
  display: grid;
  grid: [story] 1fr / [story] 1fr;
  scroll-snap-align: start;
  scroll-snap-stop: always;
}
하위 요소는 맞추기 대상을 선택합니다.

저는 다음과 같은 이유로 Scroll Snap Points를 선택했습니다.

  • 무료 접근성. 스크롤 스냅 포인트 사양에는 기본적으로 왼쪽 화살표오른쪽 화살표 키를 누르면 맞추기 포인트를 통해 이동해야 한다고 나와 있습니다.
  • 사양 향상. Scroll Snap Points 사양은 계속해서 새로운 기능을 추가하고 개선되고 있으므로 스토리 구성요소는 앞으로 계속 개선될 것입니다.
  • 구현의 용이성. 스크롤 스냅 포인트는 사실상 터치 중심의 가로 페이지로 나누기 사용 사례에 맞게 빌드되었습니다.
  • 무료 플랫폼 스타일 관성. 이상한 스크롤 및 휴면 스타일을 가질 수 있는 정규화된 관성과는 달리 모든 플랫폼은 해당 스타일로 스크롤되고 멈춥니다.

교차 브라우저 호환성

Opera, Firefox, Safari, Chrome, Android, iOS에서 테스트했습니다. 다음은 기능 및 지원에 차이점이 있는 웹 기능에 관한 간략한 설명입니다.

하지만 일부 CSS가 적용되지 않아 현재 일부 플랫폼에서는 UX 최적화를 놓치고 있습니다. 이러한 기능을 관리할 필요가 없어서 좋았고, 언젠가 다른 브라우저와 플랫폼에도 지원될 거라 확신했습니다.

scroll-snap-stop

캐러셀은 CSS 스크롤 스냅 포인트 사양을 만들게 된 주요 UX 사용 사례 중 하나였습니다. 스토리와 달리 캐러셀은 사용자가 상호작용한 후 항상 각 이미지에서 중지할 필요는 없습니다. 캐러셀을 빠르게 둘러보는 것도 좋습니다. 반면 스토리는 하나씩 탐색하는 것이 가장 좋으며 이것이 scroll-snap-stop에서 제공하는 기능입니다.

.user {
  scroll-snap-align: start;
  scroll-snap-stop: always;
}

이 게시물을 작성하는 시점에서는 scroll-snap-stop가 Chromium 기반 브라우저에서만 지원됩니다. 업데이트는 브라우저 호환성을 확인하세요. 하지만 막는 것은 아닙니다. 이는 지원되지 않는 브라우저에서 사용자가 실수로 친구를 건너뛸 수 있음을 의미합니다. 따라서 사용자는 좀 더 주의해야 합니다. 또는 Google에서는 건너뛴 친구가 읽음으로 표시되지 않도록 자바스크립트를 작성해야 합니다.

자세히 알아보려면 사양을 참고하세요.

overscroll-behavior

갑자기 모달 뒤의 콘텐츠를 스크롤하기 시작할 때 모달을 스크롤한 적이 있나요? overscroll-behavior를 사용하면 개발자가 스크롤을 트랩하고 떠나지 않습니다. 모든 종류의 장소에 적합합니다. 내 스토리 구성요소에서는 이를 사용하여 추가적인 스와이프 및 스크롤 동작이 구성요소에서 벗어나지 않도록 합니다.

.stories {
  overflow-x: auto;
  overscroll-behavior: contain;
}

Safari와 Opera는 이 두 가지를 지원하지 않으며 괜찮습니다. 이러한 사용자는 익숙한 오버스크롤 환경을 경험하게 되며 이러한 개선사항을 눈치채지 못할 수도 있습니다. 저는 개인적으로 광팬이에요. 그리고 제가 구현하는 거의 모든 오버스크롤 기능에 이 기능을 추가하고 싶어요. 이렇게 하면 무해한 추가 기능이므로 UX만 개선할 수 있습니다.

scrollIntoView({behavior: 'smooth'})

사용자가 탭하거나 클릭하여 친구의 이야기 모음 끝에 도달하면 스크롤 스냅 지점 집합에서 다음 친구로 이동할 차례입니다. JavaScript를 사용하여 다음 친구를 참조하고 이 친구를 스크롤하여 표시하도록 요청할 수 있었습니다. 이 API의 기본사항은 훌륭하게 지원됩니다. 모든 브라우저에서 스크롤을 했습니다. 하지만 모든 브라우저에서 'smooth'를 수행하지는 않습니다. 즉, 맞춰지는 대신 스크롤하여 뷰로 이동합니다.

element.scrollIntoView({
  behavior: 'smooth'
})

Safari는 여기에서 behavior: 'smooth'를 지원하지 않는 유일한 브라우저입니다. 업데이트는 브라우저 호환성을 확인하세요.

실습

이제 내가 어떻게 했는지 알았으니 어떻게 할 건가요? 접근 방식을 다양화하고 웹에서 빌드하는 모든 방법을 알아보겠습니다 Glitch를 만들고 내 버전을 트윗하면 아래의 커뮤니티 리믹스 섹션에 추가합니다.

커뮤니티 리믹스