본문으로 건너뛰기
wooncloud

네이티브 select 화살표를 전 플랫폼에서 통일하기 (iOS 는 왜 양방향 화살표일까)

iOS Safari 에서만 양방향 화살표로 보이는 select 를 appearance 리셋으로 통일하고, data-uri SVG 에는 CSS 변수가 먹지 않아 DOM 오버레이를 쓰게 된 이유를 정리했습니다.

·4 min read·— views··

같은 <select> 마크업인데 기기마다 드롭다운 화살표 모양이 달랐습니다. 데스크톱 Chrome 과 안드로이드 Chrome 은 아래 방향 화살표(⌄)인데, iOS Safari 만 위아래 양방향 화살표(↕)였습니다.

코드가 틀린 건 아닙니다. 브라우저와 OS 가 native form control 을 각자 다르게 그리는 것뿐이죠. 디자인을 맞추고 싶으면 직접 그려야 합니다.

먼저 기본 모양부터 지웁니다

select {
  appearance: none;
  -webkit-appearance: none; /* iOS Safari 의 ↕ 제거에 필수 */
  -moz-appearance: none;
  padding-right: 28px;      /* 커스텀 화살표 자리 */
}

appearance: none 이 OS 기본 화살표를 없앱니다. 그다음 화살표를 직접 얹으면 되는데, 방법이 둘입니다.

방법 A, background-image 에 SVG data-uri

select {
  background-image: url("data:image/svg+xml,<svg ...><path stroke='%23888' .../></svg>");
  background-repeat: no-repeat;
  background-position: right 10px center;
}

간단하지만 함정이 하나 있습니다. 바로 아래에서 다룹니다.

방법 B, DOM 오버레이

<span style={{ position: "relative", display: "inline-flex" }}>
  <select style={{ appearance: "none", paddingRight: 28 }}>…</select>
  <ChevronDown
    style={{ position: "absolute", right: 10, top: "50%",
             transform: "translateY(-50%)", pointerEvents: "none" }}
    color="var(--icon-color)"
  />
</span>

pointer-events: none 을 줘서 화살표가 클릭을 가로채지 않게 하면 select 가 정상으로 동작합니다.

data-uri SVG 에는 CSS 변수가 안 먹습니다

디자인 시스템이 색을 CSS 변수(var(--c-gray))로 관리한다면, 방법 A 의 data-uri stroke 에 그 변수를 넣어도 적용되지 않습니다.

/* 작동 안 함: data-uri 안의 var() 는 페이지 CSS 변수를 못 본다 */
background-image: url("data:image/svg+xml,<svg><path stroke='var(--c-gray)'/></svg>");

data-uri 로 불러온 SVG 는 별도 문서(resource document)라서, 임베드한 페이지의 CSS 커스텀 프로퍼티를 상속하지 않습니다. currentColor 도 안 먹는 경우가 많습니다.

결국 data-uri 방식은 색을 하드코딩해야 하고, 다크모드에서 화살표만 안 바뀌는 버그로 이어집니다.

그래서 색을 토큰이나 다크모드에 묶고 싶다면 방법 B(실제 DOM 의 인라인 SVG 오버레이)를 씁니다. 실제 DOM 요소의 stroke 와 color 는 페이지 CSS 변수를 정상적으로 해석하거든요.

메모

폼 컨트롤 모양이 기기마다 다르면 십중팔구 native appearance 차이입니다. appearance: none 으로 지우고 직접 그리면 됩니다.

화살표 색을 디자인 토큰에 묶어야 하면 DOM 오버레이로, 그 오버레이에는 pointer-events: none 을 잊지 않는 것까지 한 세트입니다.

참고