들어가며: select도 이제 자유롭게 디자인할 수 있습니다

웹 폼에서 가장 기본적인 UI 요소 중 하나인 <select>는 오랫동안 '스타일링이 거의 불가능한 요소'로 악명이 높았습니다. 브라우저마다 제각각인 기본 드롭다운 디자인을 억지로 바꾸려면 JavaScript로 커스텀 드롭다운을 처음부터 만들어야 했죠. 하지만 이제 CSS만으로 select의 외형, 드롭다운 위치, option 내부 레이아웃까지 완전히 제어할 수 있는 시대가 왔습니다.

이 글에서는 다음 세 가지 실전 예제를 통해 커스터마이징 select의 핵심 기술을 익혀보겠습니다.

  1. 폴더 스택 – option을 곡선으로 쌓아 올리는 애니메이션
  2. 카드 덱 – 부채꼴로 펼쳐지는 카드 피커
  3. 원형 이모지 피커 – 삼각함수로 배치하는 방사형 선택 UI

참고: 이 기능은 현재 Chromium 기반 브라우저(Chrome, Edge 등)에서만 동작합니다. Firefox나 Safari에서는 기본 select로 폴백되므로 점진적 향상(Progressive Enhancement) 관점에서 도입해보세요.

함께 보면 좋은 글: 프레임워크 의존에서 벗어나기 2025 웹 개발의 미래를 본 개발자 컨퍼런스 리포트

Customizable HTML select element with CSS styled dropdown options Coding Session Visual

예제 1: 곡선으로 쌓이는 폴더 스택

1단계: 기본 HTML 마크업

각 option에 <span>을 넣어 선택된 항목의 텍스트 스타일링을 따로 할 수 있게 합니다.

<select>
  <option><span>Documents</span></option>
  <option><span>Photos</span></option>
  <option><span>Music</span></option>
  <option><span>Videos</span></option>
  <option><span>Downloads</span></option>
  <option><span>Desktop</span></option>
  <option><span>Projects</span></option>
  <option><span>Backups</span></option>
  <option><span>Trash</span></option>
</select>

2단계: 커스텀 select 활성화 (appearance: base-select)

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

appearance: base-select 한 줄이면 select의 버튼, 드롭다운, option 모두에 대한 스타일링 권한을 얻습니다.

3단계: 버튼 스타일링 & picker 아이콘 제거

select {
  background: linear-gradient(
    135deg,
    rgba(40, 40, 50, 0.4) 0%,
    rgba(60, 60, 70, 0.25) 50%,
    rgba(50, 50, 60, 0.35) 100%
  );
  backdrop-filter: blur(12px) saturate(180%);
  box-shadow:
    0 8px 32px rgba(0, 0, 0, 0.2),
    inset 0 1px 1px rgba(255, 255, 255, 0.15),
    inset 0 -1px 1px rgba(0, 0, 0, 0.1);
  border: 1px solid rgba(255, 255, 255, 0.2);
  color: white;
  min-inline-size: 12rem;
}

select::picker-icon {
  display: none;
}

4단계: 드롭다운 컨테이너 투명하게 만들기

::picker(select) {
  background: transparent;
  border: none;
  box-shadow: none;
  overflow: visible;
}

이제 각 option이 드롭다운 영역 밖으로 자유롭게 배치될 수 있습니다.

5단계: 체크마크와 option 꾸미기

option::checkmark {
  content: "●";
  color: #222;
}

option::before {
  content: "📁";
  margin-right: 0.5rem;
}

6단계: sibling-index()로 곡선 효과 만들기

option {
  --rotation-offset: -4deg;
  rotate: 0deg;
  transition: rotate 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
  transition-delay: calc((sibling-index() - 1) * 0.01s);
  transform-origin: right calc(sibling-index() * -1.5rem);
}

select:open option {
  rotate: calc(sibling-index() * -1 * var(--rotation-offset));
}

@starting-style {
  select:open option {
    rotate: 0deg;
  }
}

sibling-index()는 option의 형제 인덱스를 반환하는 새로운 CSS 함수입니다. 아직 모든 브라우저에서 지원하지 않으므로 사용 전에 Can I Use를 확인하세요.

이제 select를 열면 폴더가 하나씩 곡선으로 펼쳐지는 애니메이션을 볼 수 있습니다!

Developer coding CSS custom select picker on laptop screen Dev Environment Setup

예제 2: 부채꼴로 펼쳐지는 카드 덱

핵심 아이디어: sibling-count()로 중앙 기준 회전

option {
  --card-fan-rotation: 7deg;
  --card-fan-spread: -11vmin;
  --option-index: calc(sibling-index() - 1);
  --center: calc(sibling-count() / 2);
  --offset-from-center: calc(var(--option-index) - var(--center));

  rotate: calc(var(--offset-from-center) * var(--card-fan-rotation));
  translate: calc(var(--offset-from-center) * var(--card-fan-spread)) 0;
  transform-origin: center 75vmin;
}

애니메이션을 위한 @property 활용

@property --card-fan-rotation {
  syntax: '<angle>';
  inherits: false;
  initial-value: 7deg;
}

option {
  --card-fan-rotation: 0deg;
  transition: --card-fan-rotation 0.2s ease-out;
}

select:open option {
  --card-fan-rotation: initial;
}

@starting-style {
  select:open option {
    --card-fan-rotation: 0deg;
  }
}

예제 3: 원형 이모지 피커

드롭다운 위치를 버튼 중심으로 변경

::picker(select) {
  top: calc(anchor(top) - var(--radius));
  left: calc(anchor(left) - var(--radius));
  width: calc(var(--radius) * 2 + var(--option-size));
  height: calc(var(--radius) * 2 + var(--option-size));
}

삼각함수로 option 배치

option {
  position: absolute;
  --angle: calc((sibling-index() - 2) * (360deg / (sibling-count() - 1)) - 90deg);
  top: 50%;
  left: 50%;
  translate:
    calc(-50% + cos(var(--angle)) * var(--radius))
    calc(-50% + sin(var(--angle)) * var(--radius));
}

CSS cos()sin() 함수 덕분에 복잡한 JavaScript 계산 없이 원형 배치가 가능해졌습니다.

Web developer implementing animated select menu with CSS transitions Technical Structure Concept

실무 적용 시 주의사항

  1. 브라우저 호환성: 이 기능은 Chromium 기반 브라우저 전용입니다. Safari와 Firefox에서는 appearance: base-select가 무시되므로 기본 select로 폴백됩니다. 반드시 점진적 향상 전략을 취하세요.
  2. 접근성: 커스터마이징 select는 기본 select의 접근성(키보드 네비게이션, 스크린 리더)을 그대로 유지합니다. 하지만 시각적 효과가 과하면 사용성을 해칠 수 있으니 prefers-reduced-motion 미디어 쿼리를 고려하세요.
  3. sibling-index() 지원: 아직 초안 단계의 CSS 함수이므로 프로덕션에서 사용할 때는 폴리필이나 대체 스타일을 준비하는 것이 좋습니다.

다음 단계 학습 방향

  • CSS Anchor Positioning 공식 문서 읽어보기 (anchor(), position-area)
  • @starting-style at-rule의 다양한 활용 사례 탐구
  • CSS @property 로 커스텀 속성 애니메이션 마스터하기

참고 자료: 이 글의 내용은 CSS-Tricks 원문을 바탕으로 재구성하였습니다.

함께 보면 좋은 글: 리액트 서버 컴포넌트, DoS 및 소스코드 노출 취약점 주의보 (CVE-2025-55184 등)

본 콘텐츠는 신뢰할 수 있는 출처를 바탕으로 AI 도구를 활용하여 초안이 작성되었으며, 편집자의 검토를 거쳐 발행되었습니다. 전문가의 조언을 대체하지 않습니다.