다중 선택 구성요소 빌드

사용자 환경을 정렬하고 필터링하기 위해 반응형이고 적응형이며 액세스 가능한 다중 선택 구성요소를 빌드하는 방법에 관한 기본적인 개요입니다.

이 게시물에서는 다중 선택 구성요소를 빌드하는 방법에 관한 생각을 공유하고자 합니다. 이 demo

<ph type="x-smartling-placeholder">
</ph> <ph type="x-smartling-placeholder">
</ph> 데모

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

개요

사용자에게 상품이 표시되는 경우가 많고, 때로는 많은 상품이 표시되는 경우도 있습니다. 그렇지 않은 경우에는 더 많은 트래픽이 발생하지 않도록 선택 과부하를 유발합니다. 이 선택지를 줄이는 한 가지 방법으로 필터링 UI에 관해 알아봅니다. 다음을 수행합니다. 사용자가 선택하거나 선택 해제할 수 있는 상품 속성을 표시하여 결과 감소 선택 과부하를 줄일 수 있습니다

상호작용 수

모든 사용자와 사용자 모두에게 필터 옵션의 신속한 순회를 가능하게 하는 것이 목표입니다. 다양한 입력 유형을 지원합니다. 이 광고는 적응형 배너의 구성 요소 쌍입니다. 데스크톱, 키보드용 체크박스의 기존 사이드바 및 스크린 리더, 그리고 <select multiple> 있습니다.

밝은 테마와 어두운 데스크톱의 사이드바를 보여주는 비교 스크린샷
체크박스와 다중 선택 요소가 있는 모바일 iOS 및 Android 비교

데스크톱이 아닌 터치에 내장된 다중 선택 기능을 사용하기로 한 덕분에 작업이 줄어들고 작업이 가능해지지만, 저는 하나의 구성요소로 전체 반응형 환경을 빌드하는 것보다 코드 부채가 적은 적절한 경험을 제공할 수 있다고 생각합니다.

터치

터치 구성요소는 공간을 절약하고 있습니다. 체크박스의 전체 사이드바를 하나의 창으로 접어서 공간을 절약합니다. <select> 내장 오버레이 터치 환경입니다. 입력의 정확성을 높이기 위해 대규모 터치 오버레이 환경을 구현할 수 있습니다.

가
Android, iPhone 및 Android의 Chrome에서 다중 선택 요소의 스크린샷 미리보기
iPad iPad와 iPhone의 경우 다중 선택이 열려 있고 각각
고유한 환경을 조성할 수 있습니다.

키보드 및 게임패드

다음은 키보드에서 <select multiple>를 사용하는 방법을 보여주는 데모입니다.

내장된 다중 선택 기능은 스타일을 지정할 수 없으며 컴팩트한 형식으로만 제공됩니다. 많은 옵션을 표시하기에 적합하지 않은 레이아웃입니다. Google Kubernetes Engine에서 작은 상자에 많은 옵션이 표시되지 않나요? 크기는 변경할 수 있지만 여전히 체크박스 사이드바만큼 유용하지 않습니다.

마크업

두 구성요소 모두 동일한 <form> 요소에 포함됩니다. 결과 체크박스든 다중 선택이든 이 양식이 그리드를 필터링하지만 서버에 제출할 수도 있습니다.

<form>

</form>

체크박스 구성요소

체크박스 그룹은 <fieldset> 드림 요소를 추가하고 <legend> HTML이 이런 식으로 구성되면 스크린 리더와 FormData를 통해 요소의 관계를 자동으로 이해할 수 있습니다.

<form>
  <fieldset>
    <legend>New</legend>
    … checkboxes …
  </fieldset>
</form>

그룹화가 적용된 상태에서 <label><input type="checkbox">를 추가합니다. 확인할 수 있습니다 내 코드를 <div>에 래핑했으므로 CSS gap 속성이 라벨이 여러 줄로 이동할 때 간격을 균등하게 유지하고 정렬을 유지할 수 있습니다.

<form>
  <fieldset>
    <legend>New</legend>
    <div>
      <input type="checkbox" id="last 30 days" name="new" value="last 30 days">
      <label for="last 30 days">Last 30 Days</label>
    </div>
    <div>
      <input type="checkbox" id="last 6 months" name="new" value="last 6 months">
      <label for="last 6 months">Last 6 Months</label>
    </div>
   </fieldset>
</form>

범례 및
  fieldset 요소: 색상 및 요소 이름을 표시합니다.

<select multiple> 구성요소

<select> 요소의 거의 사용되지 않는 기능은 다음과 같습니다. multiple 이 속성이 <select> 요소와 함께 사용되면 사용자는 다음 작업을 할 수 있습니다. 목록에서 여러 개를 선택합니다. 라디오 목록에서 상호작용을 변경하는 것과 같습니다. 체크박스를 선택합니다.

<form>
  <select multiple="true" title="Filter results by category">
    …
  </select>
</form>

<select> 내에 라벨을 지정하고 그룹을 만들려면 다음을 사용합니다. <optgroup> 요소를 추가하고 label 속성과 값을 지정합니다. 이 요소 및 속성은 값은 <fieldset><legend> 요소와 유사합니다.

<form>
  <select multiple="true" title="Filter results by category">
    <optgroup label="New">
      …
    </optgroup>
  </select>
</form>

이제 <option> 드림 필터의 요소입니다.

<form>
  <select multiple="true" title="Filter results by category">
    <optgroup label="New">
      <option value="last 30 days">Last 30 Days</option>
      <option value="last 6 months">Last 6 Months</option>
    </optgroup>
  </select>
</form>

다중 선택 요소의 데스크톱 렌더링 스크린샷

카운터로 입력을 추적하여 보조 기술에 정보를 제공합니다.

상태 역할 이 사용자 환경에 사용되어 스크린 리더 및 기타 보조 기술용 필터 YouTube 동영상 살펴보겠습니다 통합은 HTML로 시작하며 role="status"

<div role="status" class="sr-only" id="applied-filters"></div>

이 요소는 콘텐츠 변경사항을 소리 내 읽습니다. 업데이트된 콘텐츠를 CSS와 함께 카운터 사용자가 체크박스와 상호작용할 때 정보를 얻을 수 있습니다 이를 위해서는 먼저 입력 및 상태 요소의 상위 요소에 이름이 있는 카운터

aside {
  counter-reset: filters;
}

기본적으로 개수는 0이며 이는 훌륭하며 어떤 값도 :checked입니다. 기본적으로 사용됩니다.

다음으로 새로 만든 카운터를 증가시키기 위해 :checked<aside> 요소 사용자가 입력 상태를 변경하면 filters 카운터가 합산됩니다.

aside :checked {
  counter-increment: filters;
}

CSS는 이제 체크박스 UI와 상태 역할에 대한 일반적인 통계를 인식합니다. 요소가 비어 있으며 값을 기다리고 있습니다. CSS에서 통계를 관리하고 있으므로 인코더-디코더는 counter() 드림 함수를 사용하여 pseudo의 값에 액세스할 수 있습니다. 요소 콘텐츠의 하위 요소로 추가합니다.

aside #applied-filters::before {
  content: counter(filters) " filters ";
}

이제 상태 역할 요소의 HTML에 '필터 2개'가 표시됩니다. 화면에 추가 사용할 수 있습니다 좋은 출발이지만 YouTube에서 할 수 있습니다. 예를 들어 필터가 업데이트된 결과입니다. 이 작업은 JavaScript에서 할 것입니다. 카운터가 할 수 있는 범위를 벗어납니다.

활성 필터 수를 알려주는 MacOS 스크린 리더 스크린샷

수습 과정에 대한 기대감

CSS 알고리즘은 CSS의 편리성과 Nesting-1을 사용할 수 있습니다. 로직을 하나의 블록으로 구성할 수 있습니다 이식성이 뛰어나고 중앙 집중화되어 읽고 업데이트할 수 있습니다.

aside {
  counter-reset: filters;

  & :checked {
    counter-increment: filters;
  }

  & #applied-filters::before {
    content: counter(filters) " filters ";
  }
}
드림

레이아웃

이 섹션에서는 두 구성요소 간의 레이아웃을 설명합니다. 대부분의 레이아웃 스타일은 데스크톱 체크박스 구성요소에 사용됩니다.

양식

사용자의 가독성과 가시성을 최적화하기 위해 양식에 최대 기본적으로 각 문자에 대해 광선 너비를 필터 라벨입니다. 이 양식은 그리드 레이아웃과 gap 속성을 사용하여 fieldsets.

form {
  display: grid;
  gap: 2ch;
  max-inline-size: 30ch;
}

<select> 요소

라벨 및 체크박스 목록이 모두 모바일에서 너무 많은 공간을 차지합니다. 따라서 레이아웃이 변경할 사용자의 기본 포인팅 기기가 표시되는지 확인합니다. 경험할 수 있습니다.

@media (pointer: coarse) {
  select[multiple] {
    display: block;
  }
}

coarse은 사용자가 상호작용할 수 없음을 나타냅니다. 높은 정밀도로 기본 입력 장치로 화면을 처리하는 데 사용할 수 있습니다. 휴대기기에서 포인터 값은 기본 상호작용인 coarse인 경우가 많습니다. 터치입니다. 데스크톱 기기에서는 포인터 값이 일반적이므로 fine인 경우가 많습니다. 마우스 또는 기타 고정밀 입력 장치를 연결해야 합니다.

필드 세트는

<legend>가 있는 <fieldset>의 기본 스타일과 레이아웃은 다음과 같이 고유합니다.

필드 집합 및 범례의 기본 스타일 스크린샷

일반적으로 하위 요소의 간격을 맞추기 위해 gap 속성을 사용하지만 고유한 <legend>의 배치로 인해 균일한 간격의 세트를 만들기 어려움 50% 증가했습니다. gap 대신 인접 형제 요소 선택기margin-block-start가 사용됩니다.

fieldset {
  padding: 2ch;

  & > div + div {
    margin-block-start: 2ch;
  }
}

이렇게 하면 <legend>가 자녀 <div>

입력 사이의 여백 간격을 보여주지만 범례는 보여주지 않는 스크린샷

필터 라벨 및 체크박스

<fieldset>의 직접 하위 요소로서 양식의 최대 너비 내에 있음 30ch, 라벨 텍스트가 너무 길면 줄바꿈될 수 있습니다. 텍스트 줄바꿈도 좋지만 그렇지 않습니다. Flexbox는 이러한 상황에 적합합니다.

fieldset > div {
  display: flex;
  gap: 2ch;
  align-items: baseline;
}
드림 <ph type="x-smartling-placeholder">
</ph> 체크표시가 정렬되는 방식을 보여주는 스크린샷
    텍스트 첫 줄을 여러 줄로 줄바꿈하는 시나리오입니다.
Codepen에서 더보기

애니메이션 그리드

레이아웃 애니메이션은 Isotope로 만듭니다. 가 대화형 정렬 및 필터를 위한 강력한 성능의 플러그인입니다.

자바스크립트

깔끔한 애니메이션 대화형 그리드를 조정하는 데 도움이 될 뿐 아니라 거친 가장자리 몇 개를 다듬는 데 사용됩니다.

사용자 입력 정규화

이 디자인에는 입력을 제공하는 두 가지 방법이 있는 하나의 양식이 있습니다. 하지 마세요 직렬화하여 있습니다. 그러나 일부 JavaScript를 사용하면 정규화합니다.

DevTools JavaScript 콘솔의 스크린샷
  정규화된 데이터 결과를 보여줍니다.

<select> 요소 데이터 구조를 그룹화된 체크박스에 정렬하도록 선택했습니다. 있습니다. 이를 위해 input 드림 이벤트 리스너가 <select> 요소에 추가되었는데, 이때 리스너가 selectedOptions 매핑되기 때문입니다.

document.querySelector('select').addEventListener('input', event => {
  // make selectedOptions iterable then reduce a new array object
  let selectData = Array.from(event.target.selectedOptions).reduce((data, opt) => {
    // parent optgroup label and option value are added to the reduce aggregator
    data.push([opt.parentElement.label.toLowerCase(), opt.value])
    return data
  }, [])
})

이제 양식을 제출해도 됩니다. 이 데모의 경우 Isotope를 사용하여 선택할 수 있습니다

상태 역할 요소 완료 중

요소가 체크박스를 기준으로 필터 수를 집계하고 발표함 전화 통화를 할 때 도움이 되었던 광고의 수를 추가로 공유하는 것이 결과를 확인하고 <select> 요소 선택 항목도 계산되도록 합니다.

<select> 요소 선택사항이 counter()에 반영됨

데이터 정규화 섹션에서 입력 시 리스너가 이미 생성되어 있습니다. 위치 이 함수의 끝에 선택한 필터의 수와 결과의 수를 알 수 있습니다. 값은 상태 역할 요소에 전달할 수 있습니다. 이렇게.

let statusRoleElement = document.querySelector('#applied-filters')
statusRoleElement.style.counterSet = selectData.length

결과가 role="status" 요소에 반영됨

:checked는 선택한 필터 수를 상태 역할 요소를 지원하지만 필터링된 결과 수를 확인할 수 없습니다. JavaScript는 체크박스와의 상호작용을 관찰하고 그리드에 <select> 요소처럼 textContent를 추가합니다.

document
  .querySelector('aside form')
  .addEventListener('input', e => {
    // isotope demo code
    let filterResults = IsotopeGrid.getFilteredItemElements().length
    document.querySelector('#applied-filters').textContent = `giving ${filterResults} results`
})

이 작업을 통해 '필터 2개를 통해 25개 결과를 제공'이라는 발표가 마무리됩니다.

결과를 알리는 MacOS 스크린 리더 스크린샷

이제 Google의 우수한 보조 기술 환경이 모든 어떻게 상호작용하는지 알 수 있습니다.

결론

이제 제가 어떻게 했는지 알게 되셨으니 어떻게 하면 좋을까요?‽ 보상

접근방식을 다각화하고 웹에서 빌드하는 방법을 모두 알아보겠습니다. 데모를 만들고 링크를 트윗하여 추가하면 됩니다. 아래 커뮤니티 리믹스 섹션을 공유해 주세요

커뮤니티 리믹스

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