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

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

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

데모

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

개요

미디어 또는 제품의 썸네일을 호스팅하기 위한 가로 스크롤 레이아웃을 빌드합니다. 구성요소는 단순한 <ul> 목록으로 시작하지만 CSS를 통해 만족스럽고 부드러운 스크롤 환경으로 변환되어 이미지를 표시하고 그리드에 맞춰집니다. 색인 탐색 상호작용을 용이하게 하기 위해 자바스크립트가 추가되어 키보드 사용자가 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>altloading 속성에 유의하세요. 미디어 스크롤러의 대체 텍스트는 썸네일에 추가 컨텍스트를 제공하거나 이미지가 로드되지 않은 경우 대체 텍스트로 제공하는 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, 앱 스토어 및 더 많은 사이트와 앱에서는 가로 스크롤 영역을 사용하여 표시 영역에 카테고리와 옵션을 포함합니다.

스크롤러 레이아웃 만들기

레이아웃에서 콘텐츠를 자르거나 생략 부호로 텍스트 잘림을 사용하지 않는 것이 중요합니다. 많은 텔레비전 세트에 이와 같은 미디어 스크롤러가 있지만 생략된 콘텐츠에 의존하는 경우가 너무 많습니다. 이 레이아웃에서는 지원되지 않습니다. 또한 미디어 콘텐츠가 열 크기를 재정의할 수 있으므로 여러 흥미로운 조합을 처리할 수 있을 정도로 하나의 레이아웃을 유연하게 만들 수 있습니다.

스크롤 행 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, App Store 등에서 큰 인기를 얻었기 때문에 영감을 받았습니다. 많은 비디오 게임 플랫폼에서 이 스크롤러와 매우 유사한 미디어 스크롤러를 기본 홈 화면 레이아웃으로 사용합니다. 여기서 초점은 작은 추가가 아닌 큰 UX 모멘트입니다. 소파에서 리모컨과 함께 이 미디어 스크롤러를 사용한다고 상상해 보세요. 상호작용을 약간 개선할 수 있습니다.

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

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

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

이렇게 하면 포커스 윤곽선 스타일 7px이 상자에서 멀어지므로 좋은 공간이 생깁니다. 사용자가 모션 감소와 관련하여 선호하는 모션이 없는 경우 오프셋이 전환되어 포커스 이벤트에 미세한 모션을 제공합니다.

Roving 색인

게임패드 및 키보드 사용자는 긴 스크롤 콘텐츠 및 옵션 목록에 특히 주의해야 합니다. 이 문제를 해결하기 위한 일반적인 패턴을 순환 색인이라고 합니다. 항목의 컨테이너에 키보드 포커스가 있지만 한 번에 하나의 하위 요소만 포커스를 보유할 수 있는 경우입니다. 한 번에 포커스 가능 항목이 하나만 있는 경우 끝에 도달하기 위해 탭을 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 몇 줄로 페이지 로드 시간과 데이터 사용을 상당히 절약할 수 있는 방법을 알려드리고자 합니다. 수준 5prefers-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을 만들거나 데모를 호스팅하고 트윗해 주시면 아래 커뮤니티 리믹스 섹션에 추가하겠습니다.

소스

커뮤니티 리믹스

표시할 항목이 없습니다.