맞춤 선택 선택 도구 레이아웃

CSS 속성 appearance: base-select를 사용하면 일반 HTML 요소와 마찬가지로 <select> 요소와 선택 도구(::picker(select)를 통해)의 스타일을 지정할 수 있습니다. Grid 또는 Flexbox와 같은 최신 CSS 레이아웃 기법과 결합하면 기존의 세로로 쌓인 목록에서 벗어나 커스텀 JS 없이도 풍부한 시각적 환경을 만들 수 있습니다. 예를 들어 display: grid를 사용하여 옵션을 카드의 2D 그리드로 스타일 지정할 수 있습니다.

이는 색상 선택 도구, 그림 이모티콘 선택기 또는 목록보다 풍부한 시각적 메뉴가 더 효과적인 제품 옵션에 적합합니다.

구현 방법

1. 기본 스타일 지정 활성화

<select> 요소와 내부 선택 도구 가상 요소 select::picker(select) 모두에 appearance: base-select를 적용합니다.

select.grid-picker {
  &, &::picker(select) {
    appearance: base-select;
  }
}

2. 선택 도구 컨테이너 스타일 지정

select:open::picker(select)를 타겟팅하고 display: grid (또는 display: flex)를 적용합니다. 다른 컨테이너와 마찬가지로 열과 간격을 정의합니다.

select.grid-picker:open::picker(select) {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 1rem;
}

중요: :open는 필수 항목입니다. select::picker(select)의 스타일을 지정하면 선택기가 닫혀 있어도 선택기가 표시됩니다.

3. 옵션 스타일 지정

<option> 요소를 타겟팅하여 그리드 항목 또는 카드로 스타일을 지정합니다. 내부에 이미지, SVG 또는 복잡한 레이아웃을 추가할 수 있습니다.

/* Style options as grid cards */
.grid-picker option {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  /* padding, border-radius, background, etc. */
}

4. 선택한 옵션의 스타일 지정

선택한 옵션의 스타일을 지정하려면 option:checked를 사용합니다. 예를 들면 다음과 같습니다.

.grid-picker option:checked {
  position: relative;
  border: 2px solid var(--primary-color);
  background-color: oklab(from var(--primary-color) l a b / 8%);
}

다른 UI 컨트롤과 마찬가지로 색상만으로 상태를 전달하지 말고 여러 시각적 표시기 (예: 색상, 테두리 두께, 체크표시)를 사용하여 선택된 옵션을 전달합니다.

5. (선택사항) 선택한 옵션 체크표시 스타일 지정

기본적으로 브라우저는 체크표시를 모든 <option>의 첫 번째 하위 요소로 렌더링합니다.

content: "✓" / ""가 있는 ::before처럼 동작하며, 작성자가 제공한 ::before가 있는 경우 그 앞에 렌더링됩니다.

옵션이 선택되지 않으면 visibility: hidden를 통해 체크표시가 숨겨집니다.

::checkmark 가상 요소를 사용하여 스타일을 지정하거나, 스타일 지정만으로 선택을 전달하거나 맞춤 표시기를 사용하려는 경우 완전히 숨길 수 있습니다.

예를 들어 옵션의 오른쪽 상단에 배치하려면 다음과 같이 하면 됩니다.

select.grid-picker {
  > option::checkmark {
    /* Hide the checkmark for unselected options */
    display: none;
  }

  > option:checked {
    position: relative;

    &::checkmark {
      position: absolute;
      inset-block-start: -.4em;
      inset-inline-end: -.5em;
      display: flex;
      align-items: center;
      justify-content: center;
      box-sizing: border-box;
      min-inline-size: 1.6em;
      aspect-ratio: 1;
      padding-right: 0.12em;
      padding-left: 0.05em;
      border-radius: 50%;
      background: var(--primary-color);
      color: white;
      font-size: 70%;
      font-weight: bold;
    }
  }
}

도움말: 체크표시 주위에 컨테이너 (예: 원)를 그릴 때는 모양을 고려한 시각적 중앙 정렬을 위해 위쪽으로 약간 이동합니다 (여기서는 padding-bottom 및 padding-left 사용). 이 경우 padding-inline-start 또는 padding-block-end를 사용하지 마세요. 체크표시의 모양은 쓰기 모드에 따라 변경되지 않지만 padding-inline-start 또는 padding-block-end는 변경되기 때문입니다.

6. (선택사항) 선택한 옵션 표시 맞춤설정

기본적으로 <select>는 선택한 옵션의 텍스트 전용 버전을 표시합니다. 선택한 값의 리치 콘텐츠를 표시하려면 <button> 내에서 <selectedcontent>를 사용하거나 선택한 옵션을 다르게 표시합니다 (예: 특정 세부정보 숨기기).

<selectedcontent>는 다른 콘텐츠 요소와 마찬가지로 선택 도구의 일부가 되므로 주변에 <button> 없이 <selectedcontent>를 사용하지 않습니다.

권장사항

  • 레이아웃 동작을 테스트합니다. appearance: base-select를 설정하면 가장 긴 옵션 너비를 기준으로 선택 항목의 크기를 조정하는 기본 브라우저 동작이 삭제됩니다. 레이아웃 변경을 방지하려면 고정 너비를 설정하거나 flex/grid 제약 조건을 사용해야 할 수 있습니다.
  • <select>에 name 속성과 연결된 <label>가 있는지 확인합니다. 이렇게 하면 맞춤 UI를 사용하더라도 스크린 리더가 구성요소에 액세스할 수 있고 표준 양식 제출이 올바르게 작동합니다.
  • 옵션에 표준 value 속성을 사용하여 양식 제출이 이전과 동일하게 작동하도록 합니다.

접근성

네이티브 <select>는 선형 위/아래 화살표 탐색만 처리하므로 왼쪽/오른쪽은 열린 선택 도구에서 아무 작업도 하지 않으며 위/아래는 행과 열에 관계없이 항목을 순차적으로 탐색합니다.

그리드를 따르는 공간 탐색을 구현하려면 화살표 키를 사용할 때 keydown를 가로채고 눌린 방향에서 가장 가까운 옵션으로 포커스를 라우팅하면 됩니다 (예: getBoundingClientRect() 사용). 적절한 다음/이전 항목을 결정하려면 grid-template-columns 또는 grid-column와 같은 CSS 문자열을 파싱하는 대신 실제 도형 (예: getBoundingClientRect())에서 작동하는 DOM 메서드를 사용하세요. 이러한 문자열은 복잡한 그리드, 하위 그리드, RTL, 기타 레이아웃 시나리오에서 취약하고 오류가 발생하기 쉽습니다. 그렇다고 해서 불필요하게 과도하게 설계하지 마세요. 레이아웃에 대해 알고 있는 불변량을 사용하여 이 로직을 단순화하세요.

참고: 이 내용은 키보드 탐색에만 적용됩니다. <select> 및 ::picker()에는 여전히 기본 역할 (menu 또는 listbox)이 있으며, 이 역할은 재정의할 수 없고 role="grid"가 있는 요소를 포함할 수 없습니다. 선택 도구 내에 role="grid"가 있는 래퍼를 중첩하는 것은 실제로 작동하지만 유효하지 않으며 AT 사용자에게 혼란을 줄 수 있습니다. 경우에 따라 <optgroup>를 사용하여 옵션을 그룹화하면 role="grid" 없이도 우수한 스크린 리더 UX를 생성할 수 있습니다. 그렇지 않으면 스크린 리더 사용자를 위해 원하는 UX를 달성하기 위해 팝오버 API, 앵커 위치 지정, role="grid"를 사용하는 맞춤 솔루션으로 전환해야 할 수 있습니다.

대체 전략

맞춤설정 가능한 <select>의 대체 및 브라우저 지원

아직 appearance: base-select를 지원하지 않는 브라우저의 경우 <select> 요소가 표준 운영체제 드롭다운으로 원활하게 다운그레이드됩니다.

  • 텍스트가 아닌 콘텐츠 무시: 이전 브라우저는 <option> 태그 내의 HTML 태그 (예: <svg> 또는 <div>)를 제거하고 텍스트 노드만 렌더링합니다. <option>의 텍스트 콘텐츠가 그 자체로 읽기 쉽고 의미가 있는지 확인합니다.
  • HTML 구조 처리: 표준 파서는 <select> 내의 <button> 및 <selectedcontent> 태그를 무시하거나 잘못된 것으로 처리할 수 있습니다. 표준 텍스트를 읽을 수 있는 대체로 간주하는 경우 점진적 개선을 위해 무거운 JavaScript 폴리필이 반드시 필요한 것은 아닙니다.
document.addEventListener("DOMContentLoaded", () => {
  // Check if browser supports base-select value
  if (!CSS.supports("appearance", "base-select")) {
    // Custom select overrides are not supported natively.
  }
});