미디어 스크롤러 구성요소 빌드

TV, 휴대전화, 데스크톱 등의 반응형 가로 스크롤뷰를 빌드하는 방법에 관한 기본 개요입니다.

이 게시물에서는 최소한의 기능으로 반응성이 뛰어나고 액세스가 용이하며 여러 브라우저와 플랫폼(예: TV)에서 작동하는 웹용 가로 스크롤 환경을 만드는 방법에 관한 생각을 공유하고자 합니다. 데모를 사용해 보세요.

데모

동영상을 선호하는 경우 이 게시물의 YouTube 버전을 확인하세요.

개요

미디어 또는 제품의 썸네일을 호스팅하기 위한 가로 스크롤 레이아웃을 빌드합니다. 이 구성요소는 단순한 <ul> 목록으로 시작하지만 CSS를 사용하여 이미지를 표시하고 그리드에 스냅하여 만족스럽고 부드러운 스크롤 환경으로 변환됩니다. 로빙 색인 상호작용을 용이하게 하기 위해 JavaScript가 추가되어 키보드 사용자가 100개가 넘는 항목을 건너뛰는 데 도움이 됩니다. 또한 실험용 미디어 쿼리인 prefers-reduced-data는 미디어 스크롤러를 가벼운 제목 스크롤러 환경으로 전환하는 데 사용됩니다.

접근성 마크업으로 시작하기

미디어 스크롤러는 몇 가지 핵심 구성요소, 즉 항목이 있는 목록으로 이루어져 있습니다. 가장 단순한 형태의 목록은 전 세계를 여행할 수 있으며 모든 사람이 명확하게 소비할 수 있습니다. 이 페이지에 도달한 사용자는 목록을 둘러보고 링크를 클릭하여 상품을 볼 수 있습니다. 이것이 바로 접근 가능한 기지입니다.

<ul> 요소가 포함된 목록을 전송합니다.

<ul class="horizontal-media-scroller">
  <li></li>
  <li></li>
  <li></li>
  ...
<ul>

<a> 요소를 사용하여 목록 항목을 대화형으로 만듭니다.

<li>
  <a href="#">
    ...
  </a>
</li>

<figure> 요소를 사용하여 이미지와 자막을 의미론적으로 표현합니다.

<figure>
  <picture>
    <img alt="..." loading="lazy" src="https://picsum.photos/500/500?1">
  </picture>
  <figcaption>Legends</figcaption>
</figure>

<img>에서 alt 속성과 loading 속성을 확인하세요. 미디어 스크롤러의 대체 텍스트는 썸네일에 추가 컨텍스트를 제공하는 데 도움이 되는 UX 기회이거나 이미지가 로드되지 않은 경우 대체 텍스트로 사용되거나 스크린 리더와 같은 보조 기술을 사용하는 사용자에게 음성 UI를 제공합니다. 규정을 준수하는 대체 텍스트를 위한 5가지 황금률을 자세히 알아보세요.

loading 속성은 이미지가 뷰포트 내에 있을 때만 이 이미지 소스를 가져와야 한다고 신호를 보내는 방법으로 lazy 키워드를 허용합니다. 이는 대규모 목록에 매우 유용합니다. 사용자가 스크롤하여 화면에 표시된 항목의 이미지만 다운로드하기 때문입니다.

사용자의 색 구성표 환경설정 지원

color-scheme<meta> 태그로 사용하여 페이지가 밝은 사용자 에이전트 스타일과 어두운 사용자 에이전트 스타일을 모두 원한다고 브라우저에 알립니다. 무료 어두운 모드 또는 밝은 모드 중 무엇을 보느냐에 따라 선택할 수 있습니다.

<meta name="color-scheme" content="dark light">

메타 태그는 가능한 가장 이른 신호를 제공하므로 사용자에게 어두운 테마 환경설정이 있다면 브라우저에서 어두운 기본 캔버스 색상을 선택할 수 있습니다. 즉, 사이트의 페이지 간에 탐색할 때 로드 사이에 흰색 캔버스 배경이 깜박이지 않습니다. 로드 사이에 원활한 어두운 테마가 적용되어 눈이 훨씬 더 편안해집니다.

https://web.dev/color-scheme/에서 토마스 슈타이너의 자세한 내용을 알아보세요.

콘텐츠 추가

위의 ul > li > a > figure > picture > img 콘텐츠 구조를 고려할 때 다음 작업은 스크롤할 이미지와 제목을 추가하는 것입니다. 데모에는 정적 자리표시자 이미지와 텍스트가 포함되어 있지만 좋아하는 데이터 소스에서 가져와도 됩니다.

CSS로 스타일 추가

이제 CSS가 이 일반 콘텐츠 목록을 사용하여 환경으로 변환할 차례입니다. Netflix, 앱 스토어 등 많은 사이트와 앱에서 가로 스크롤 영역을 사용하여 뷰포트에 카테고리와 옵션을 넣습니다.

스크롤러 레이아웃 만들기

레이아웃에서 콘텐츠가 잘리거나 줄임표를 사용하여 텍스트가 잘리는 것을 피하는 것이 중요합니다. 많은 TV 세트에는 이와 같은 미디어 스크롤러가 있지만 콘텐츠를 생략하는 경우가 너무 많습니다. 이 레이아웃은 그렇지 않습니다. 또한 미디어 콘텐츠가 열 크기를 재정의할 수 있으므로 하나의 레이아웃으로 여러 가지 흥미로운 조합을 유연하게 처리할 수 있습니다.

스크롤 행 2개가 표시되었습니다. 하나에는 말줄임표가 없으므로 더 길고 각 제목을 완전히 읽을 수 있습니다. 다른 하나는 더 짧으며 많은 제목이 생략 부호로 잘립니다.

컨테이너를 사용하면 기본 크기를 맞춤 속성으로 제공하여 열 크기를 재정의할 수 있습니다. 이 그리드 레이아웃은 열 크기에 관해 고정된 견해를 가지고 있으며 간격과 방향만 관리합니다.

.horizontal-media-scroller {
  --size: 150px;

  display: grid;
  grid-auto-flow: column;
  gap: calc(var(--gap) / 2); /* parent owned value for children to be relative to*/
  margin: 0;
}

그런 다음 <picture> 요소에서 맞춤 속성을 사용하여 기본 가로세로 비율인 상자를 만듭니다.

.horizontal-media-scroller {
  --size: 150px;

  display: grid;
  grid-auto-flow: column;
  gap: calc(var(--gap) / 2);
  margin: 0;

  & picture {
    inline-size: var(--size);
    block-size: var(--size);
  }
}

몇 가지 사소한 스타일만 추가하면 미디어 스크롤러의 기본 틀을 완성할 수 있습니다.

.horizontal-media-scroller {
  --size: 150px;

  display: grid;
  grid-auto-flow: column;
  gap: calc(var(--gap) / 2);
  margin: 0;

  overflow-x: auto;
  overscroll-behavior-inline: contain;

  & > li {
    display: inline-block; /* removes the list-item bullet */
  }

  & picture {
    inline-size: var(--size);
    block-size: var(--size);
  }
}

overflow를 설정하면 목록을 스크롤하고 키보드로 탐색할 수 있도록 <ul>가 설정됩니다. 그러면 각 직접 하위 <li> 요소에서 새 디스플레이 유형 inline-block을 가져와 ::marker를 삭제합니다.

하지만 이미지는 아직 응답하지 않으며, 이미지 안에 있는 상자 밖으로 바로 버려집니다. 지연 로드 시 사용할 몇 가지 크기, 맞춤, 테두리 스타일, 배경 그라데이션을 사용하세요.

img {
  /* smash into whatever box it's in */
  inline-size: 100%;
  block-size: 100%;

  /* don't squish but do cover the space */
  object-fit: cover;

  /* soften the edges */
  border-radius: 1ex;
  overflow: hidden;

  /* if empty, show a gradient placeholder */
  background-image:
    linear-gradient(
      to bottom,
      hsl(0 0% 40%),
      hsl(0 0% 20%)
    );
}

스크롤 패딩

페이지 콘텐츠에 대한 정렬과 더 넓은 화면 스크롤 표시 영역 영역은 조화롭고 최소한의 구성요소에 중요합니다.

서체 및 레이아웃 선과 정렬되는 전체 크기 스크롤 레이아웃을 실행하려면 scroll-padding와 일치하는 padding를 사용하세요.

.horizontal-media-scroller {
  --size: 150px;

  display: grid;
  grid-auto-flow: column;
  gap: calc(var(--gap) / 2);
  margin: 0;

  overflow-x: auto;
  overscroll-behavior-inline: contain;

  padding-inline: var(--gap);
  scroll-padding-inline: var(--gap);
  padding-block: calc(var(--gap) / 2); /* make space for scrollbar and focus outline */
}

가로 스크롤 패딩 버그 수정 위의 예는 스크롤 컨테이너를 패딩하는 것이 얼마나 쉬운지 보여줍니다. 하지만 여기에는 해결되지 않은 호환성 문제가 있습니다(Chromium 91 이상에서 수정됨). 여기에서 약간의 기록을 확인하세요. 간단히 말하자면 스크롤 뷰에서 패딩이 항상 고려되지는 않았습니다.

마지막 목록 항목의 인라인 끝쪽에 상자가 강조 표시되어 패딩과 요소의 너비가 동일하여 원하는 정렬이 생성되었음을 보여줍니다.

브라우저가 스크롤러 끝에 패딩을 추가하도록 속이기 위해 각 목록의 마지막 숫자를 타겟팅하고 원하는 패딩 크기의 가상 요소를 추가합니다.

.horizontal-media-scroller > li:last-of-type figure {
  position: relative;

  &::after {
    content: "";
    position: absolute;

    inline-size: var(--gap);
    block-size: 100%;

    inset-block-start: 0;
    inset-inline-end: calc(var(--gap) * -1);
  }
}

논리적 속성을 사용하면 미디어 스크롤러가 모든 작성 모드 및 문서 방향에서 작동할 수 있습니다.

스크롤 스냅

오버플로가 있는 스크롤 컨테이너는 한 줄의 CSS로 맞춰지는 표시 영역이 될 수 있으며, 하위 요소에서 표시 영역과 정렬되는 방식을 지정합니다.

.horizontal-media-scroller {
  --size: 150px;

  display: grid;
  grid-auto-flow: column;
  gap: calc(var(--gap) / 2);
  margin: 0;

  overflow-x: auto;
  overscroll-behavior-inline: contain;

  padding-inline: var(--gap);
  scroll-padding-inline: var(--gap);
  padding-block-end: calc(var(--gap) / 2);

  scroll-snap-type: inline mandatory;

  & figure {
    scroll-snap-align: start;
  }
}

포커스

이 구성요소는 TV, 앱 스토어 등에서 큰 인기를 얻고 있는 것에서 아이디어를 얻었습니다. 많은 비디오 게임 플랫폼에서는 이 스크롤러와 매우 유사한 미디어 스크롤러를 기본 홈 화면 레이아웃으로 사용합니다. 포커스는 단순한 추가 기능이 아니라 중요한 UX 요소입니다. 소파에 앉아 리모컨으로 이 미디어 스크롤러를 사용한다고 가정해 보겠습니다. 상호작용을 약간 개선해 보세요.

.horizontal-media-scroller a {
  outline-offset: 12px;

  &:focus {
    outline-offset: 7px;
  }

  @media (prefers-reduced-motion: no-preference) {
    & {
      transition: outline-offset .25s ease;
    }
  }
}

이렇게 하면 포커스 윤곽선 스타일 7px이 상자에서 멀리 설정되어 멋진 공간이 확보됩니다. 사용자가 모션 감소에 관한 모션 환경설정을 하지 않은 경우 오프셋이 전환되어 포커스 이벤트에 미묘한 모션이 적용됩니다.

이동 색인

게임패드 및 키보드 사용자는 이러한 긴 스크롤 콘텐츠 및 옵션 목록에서 특히 주의해야 합니다. 이를 해결하기 위한 일반적인 패턴을 로빙 색인이라고 합니다. 항목의 컨테이너에 키보드 포커스가 있지만 한 번에 하나의 하위 요소만 포커스를 보유할 수 있는 경우입니다. 한 번에 하나의 포커스 가능한 항목을 표시하는 이 환경은 탭을 50번 이상 눌러 끝까지 이동하는 대신 긴 항목 목록을 우회할 수 있도록 설계되었습니다.

데모의 첫 번째 스크롤러에는 300개의 항목이 있습니다. 모든 요소를 넘겨서 다음 섹션으로 넘어가는 것보다 훨씬 나을 수 있습니다.

이 환경을 만들려면 JavaScript가 키보드 이벤트와 포커스 이벤트를 관찰해야 합니다. 이 사용자 환경을 쉽게 구현할 수 있도록 npm에 소규모 오픈소스 라이브러리를 만들었습니다. 스크롤러 3개에 이를 사용하는 방법은 다음과 같습니다.

import {rovingIndex} from 'roving-ux';

rovingIndex({
  element: someElement
});

이 데모는 스크롤러에 관한 문서를 쿼리하고 스크롤러 각각에 대해 rovingIndex() 함수를 호출합니다. 포커스 타겟이 직계 자손이 아닌 경우 목록 컨테이너와 같은 로빙 환경을 가져오기 위해 요소에 rovingIndex()를 전달하고 타겟 쿼리 선택기를 전달합니다.

document.querySelectorAll('.horizontal-media-scroller')
  .forEach(scroller =>
    rovingIndex({
      element: scroller,
      target: 'a',
}))

이 효과에 관한 자세한 내용은 오픈소스 라이브러리 roving-ux를 참고하세요.

가로세로 비율

이 게시물을 작성하는 시점에서 aspect-ratio 지원은 Firefox에서 플래그 뒤에 있지만 Chromium 브라우저 또는 셋톱박스에서는 사용할 수 있습니다. 미디어 스크롤러 그리드 레이아웃은 방향과 간격만 지정하기 때문에 크기는 가로세로 비율 지원을 확인하는 미디어 쿼리 내에서 변경될 수 있습니다. 일부 동적 미디어 스크롤러에 대한 점진적 개선

가로세로 비율이 4:4인 상자가 16:9 및 4:3에 사용된 다른 디자인 비율 옆에 표시되어 있음

@supports (aspect-ratio: 1) {
  .horizontal-media-scroller figure > picture {
    inline-size: auto; /* for a block-size driven ratio */
    aspect-ratio: 1; /* boxes by default */

    @nest section:nth-child(2) & {
      aspect-ratio: 16/9;
    }

    @nest section:nth-child(3) & {
      /* double the size of the others */
      block-size: calc(var(--size) * 2);
      aspect-ratio: 4/3;

      /* adjust size to fit more items into the viewport */
      @media (width <= 480px) {
        block-size: calc(var(--size) * 1.5);
      }
    }
  }
}

브라우저가 aspect-ratio 문법을 지원하면 미디어 스크롤러 사진이 aspect-ratio 크기 조정으로 업그레이드됩니다. 초안 중첩 문법을 사용하면 각 사진은 첫 번째, 두 번째 또는 세 번째 행인지에 따라 가로세로 비율을 변경합니다. 중첩 구문을 사용하면 다른 크기 조정 로직과 함께 바로 일부 표시 영역 조정을 설정할 수 있습니다.

이 CSS를 사용하면 더 많은 브라우저 엔진에서 이 기능을 사용할 수 있으므로 관리하기 쉽지만 시각적으로 더 매력적인 레이아웃이 렌더링됩니다.

데이터 감소 선호

다음 기법은 Canary플래그 뒤에서만 사용할 수 있지만, CSS 몇 줄로 페이지 로드 시간과 데이터 사용을 상당히 줄일 수 있는 방법을 공유하고자 합니다. 5단계prefers-reduced-data 미디어 쿼리를 사용하면 기기가 데이터 절약 모드와 같은 데이터 감소 상태에 있는지 물을 수 있습니다. 그렇다면 문서를 수정할 수 있으며, 이 경우 이미지를 숨길 수 있습니다.

ALT_TEXT_HERE

figure {
  @media (prefers-reduced-data: reduce) {
    & {
      min-inline-size: var(--size);

      & > picture {
        display: none;
      }
    }
  }
}

콘텐츠는 계속 탐색할 수 있지만 대용량 이미지가 다운로드되는 비용은 없습니다. 다음은 prefers-reduced-data CSS를 추가하기 전의 사이트입니다.

(요청 7개, 131ms에 리소스 100kb)

ALT_TEXT_HERE

prefers-reduced-data CSS를 추가한 후의 사이트 실적은 다음과 같습니다.

ALT_TEXT_HERE

(요청 71개, 1.07초 동안 리소스 1.2MB)

요청이 64개 감소했습니다. 즉, 이 브라우저 탭의 뷰포인트 내 이미지 (와이드스크린 디스플레이에서 테스트)가 약 60개, 페이지 로드 속도가 약 80%, 전송되는 데이터가 10% 감소했습니다. 매우 강력한 CSS입니다.

결론

이제 제가 어떻게 했는지 알았으니 어떻게 하시겠어요? 🙂

접근 방식을 다양화하고 웹에서 빌드하는 모든 방법을 알아보겠습니다. Codepen을 만들거나 자체 데모를 호스팅한 후 트윗으로 보내주시면 아래의 커뮤니티 리믹스 섹션에 추가해 드리겠습니다.

소스

커뮤니티 리믹스

아직 표시할 내용이 없습니다.