웹에서 Instagram 스토리와 유사한 환경을 빌드하는 방법에 관한 기본 개요입니다.
이 게시물에서는 반응형이고 키보드 탐색을 지원하며 여러 브라우저에서 작동하는 웹용 스토리 구성요소를 빌드하는 방법을 공유하고자 합니다.
이 스토리 구성요소를 직접 빌드하는 방법을 실습으로 확인하려면 스토리 구성요소 Codelab을 확인하세요.
동영상을 선호하는 경우 이 게시물의 YouTube 버전을 참고하세요.
개요
스토리 UX의 인기 있는 두 가지 예는 Snapchat 스토리와 Instagram 스토리 (플릿은 말할 것도 없음)입니다. 일반적인 UX 용어로 스토리는 일반적으로 여러 구독을 탐색하기 위한 모바일 전용 탭 중심 패턴입니다. 예를 들어 Instagram에서 사용자가 친구의 스토리를 열고 스토리에 있는 사진을 살펴봅니다. 일반적으로 한 번에 여러 명의 친구에게 이 작업을 실행합니다. 사용자가 기기의 오른쪽을 탭하면 해당 친구의 다음 스토리로 건너뜁니다. 사용자가 오른쪽으로 스와이프하면 다른 친구로 건너뜁니다. 스토리 구성요소는 캐러셀과 매우 유사하지만 단일 차원 배열이 아닌 다차원 배열을 탐색할 수 있습니다. 마치 각 캐러셀 내에 캐러셀이 있는 것처럼 보입니다. 🤯
작업에 적합한 도구 선택
몇 가지 중요한 웹 플랫폼 기능 덕분에 이 구성요소를 빌드하는 것이 매우 간단했습니다. 그 내용을 살펴보겠습니다.
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;
}
grid
레이아웃을 살펴보겠습니다.
- 모바일에서는
100vh
및100vw
로 뷰포트를 명시적으로 채우고 데스크톱에서는 크기를 제한합니다. /
: 행 및 열 템플릿을 구분합니다.auto-flow
는grid-auto-flow: column
로 변환됩니다.- 자동 흐름 템플릿은
100%
이며, 이 경우 스크롤 창 너비입니다.
휴대전화에서는 행 크기가 표시 영역 높이이고 각 열이 표시 영역 너비라고 생각하면 됩니다. Snapchat 스토리 및 Instagram 스토리 예시를 계속해서 살펴보면 각 열은 친구의 스토리입니다. 스크롤할 수 있는 공간이 있도록 친구 스토리가 표시 영역 외부에서 계속 이어지도록 합니다. 그리드는 각 친구 스토리에 맞게 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 Scroll Snap Points 사양을 사용하면 스크롤 시 요소를 표시 영역에 고정하는 것이 간단합니다. 이러한 CSS 속성이 존재하기 전에는 JavaScript를 사용해야 했으며, 적어도 까다로웠습니다. 사용 방법을 자세히 알아보려면 사라 드라스너의 CSS 스크롤 스냅 포인트 소개를 확인하세요.
.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; }
스크롤 스냅 포인트를 선택한 이유는 다음과 같습니다.
- 무료 액세스 스크롤 스냅 포인트 사양에 따르면 왼쪽 화살표 키와 오른쪽 화살표 키를 누르면 기본적으로 스냅 포인트를 통해 이동해야 합니다.
- 성장하는 사양. 스크롤 스냅 포인트 사양은 항상 새로운 기능과 개선사항이 추가되고 있으므로 앞으로 내 스토리 구성요소가 점점 더 개선될 것입니다.
- 구현 용이성 스크롤 스냅 포인트는 터치 중심의 가로 페이지로 나누기 사용 사례를 위해 실제로 빌드됩니다.
- 자유로운 플랫폼 스타일의 관성 모든 플랫폼은 기이한 스크롤 및 정지 스타일을 가질 수 있는 정규화된 관성에 반대하여 자체 스타일로 스크롤하고 정지합니다.
교차 브라우저 호환성
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 기반 브라우저에서만 지원됩니다. 업데이트는 브라우저 호환성을 참고하세요. 하지만 차단되지는 않습니다. 지원되지 않는 브라우저에서는 사용자가 실수로 친구를 건너뛸 수 있다는 의미입니다. 따라서 사용자는 더 주의해야 하거나 건너뛴 친구가 조회된 것으로 표시되지 않도록 JavaScript를 작성해야 합니다.
자세한 내용은 사양을 참고하세요.
overscroll-behavior
모달을 스크롤하다가 갑자기 모달 뒤의 콘텐츠가 스크롤되기 시작한 적이 있나요?
overscroll-behavior
를 사용하면 개발자가 스크롤을 가두고 스크롤이 벗어나지 않도록 할 수 있습니다. 다양한 경우에 사용할 수 있습니다. 내 스토리 구성요소는 이를 사용하여 추가 스와이프 및 스크롤 동작이 구성요소를 벗어나지 않도록 합니다.
.stories {
overflow-x: auto;
overscroll-behavior: contain;
}
Safari와 Opera는 이 기능을 지원하지 않는 두 가지 브라우저였으며 이는 전혀 문제가 되지 않습니다. 이러한 사용자에게는 평소와 같이 오버스크롤 환경이 제공되며 이 개선사항을 눈치채지 못할 수도 있습니다. 저는 개인적으로 이 기능을 좋아하며 구현하는 거의 모든 오버스크롤 기능에 포함하는 것을 좋아합니다. 이 기능은 UX를 개선하는 데만 도움이 되는 무해한 추가 기능입니다.
scrollIntoView({behavior: 'smooth'})
사용자가 탭하거나 클릭하여 친구의 스토리 세트 끝에 도달하면 스크롤 스냅 포인트 세트에서 다음 친구로 이동해야 합니다. JavaScript를 사용하여 다음 친구를 참조하고 스크롤하여 표시되도록 요청할 수 있었습니다. 이 기본사항에 대한 지원은 훌륭합니다. 모든 브라우저에서 스크롤하여 볼 수 있었습니다. 하지만 모든 브라우저가 'smooth'
를 실행한 것은 아닙니다. 즉, 스크롤하여 뷰로 이동한 것입니다.
element.scrollIntoView({
behavior: 'smooth'
})
여기서 behavior: 'smooth'
를 지원하지 않는 유일한 브라우저는 Safari였습니다. 업데이트는 브라우저 호환성을 참고하세요.
실습
이제 제가 어떻게 했는지 알았으니 어떻게 하시겠어요? 접근 방식을 다양화하고 웹에서 빌드하는 모든 방법을 알아보겠습니다. Glitch를 만들고 내 버전을 트윗해 주시면 아래의 커뮤니티 리믹스 섹션에 추가해 드리겠습니다.
커뮤니티 리믹스
- @geoffrich_와 Svelte: 데모 및 코드
- Vue를 사용한 @GauteMeekOlsen: 데모 + 코드
- Lit를 사용한 @AnaestheticsApp: 데모 및 코드