[UIUX] 컴포넌트 레이어

Bora Im·2024년 3월 4일
0

이야기는 Select 컴포넌트에서 출발한다.
HTML Select가 아닌 일반 Tags와 Button 컴포넌트를 이용해 커스텀하게 만든 녀석이고,
UI 관련 아래 variant, size, placement 정도의 props를 가지고 있다.
*각각 형태(appearance), 크기, 방향

<div class="root">
  <Button class="select">선택</Button>
  <div class="dropdown">
    <ul class="list">
      <li class="item">
        <Button class="option">항목 1</Button>
      </li>
      ...
    </ul>
  </div>
</div>

마크업은 대략 위와 같고,
root 기준으로(relative) dropdown 영역의 위치를 잡아주었다(absolute).

size prop에 따라 select와 각 option의 높이값을 md/lg/xl 40/48/60으로 잡아주고,
placement prop은 드롭다운이 펼쳐지는 방향으로
"bottom"일 경우 top값, "top"일 경우 bottom값으로 사이 간격(8px)을 더한 calc(100% + 8px)을 주어 구현했다.

🚨근데 이제? 이슈 발생..

Select 컴포넌트는(*내가 만든) 다양한 환경과 위치에 자리하게 되는데,
overflow 안에서 절대 자유로울 수 없다..
드롭다운 레이어가 absolute임에도 불구하고, 부모 영역에 스크롤이 생기거나, 댕강 허리가 잘려버림 🥲

사실 이건 Select 컴포넌트에만 국한된 이슈가 아니고,
컴포넌트 내 최상위(root) 영역을 기준으로 하위 레이어의 위치를 잡는 모든 것이 그러하다.
Date(Range), Tooltip, Context, Popover 등등..

자, 해결 방법은? ⛏️

간단하다. 웹뷰 전체에서 자유로우면 된다.!

  • 1) 마크업이 body 바로 하위의 가장 바깥에 위치하거나
  • 2) 마크업이 어느 곳에 있든 위치값이 어느 요소에 종속되지 않거나
    • 고정 위치(fixed position) : 뷰포트(viewport)를 기준으로 위치를 설정하는 방식

남들은 어케 했는지 레퍼런스를 살펴보자.

MUI

Select, Popover, Modal 등의 컴포넌트를 살펴보면, 레이어 마크업(MuiPaper)이
버튼(MuiBox)과는 별개로 body가 닫히기 직전 위치에 추가/제거 되는 것을 확인할 수 있다.

Select

  • Select active 시,
    • html overflow: hidden, 레이어를 감싼 영역에 position: fixed; inset: 0
      👉 스크롤, 클릭 차단
    • 웹뷰 resize 시 레이어 위치값(top,left) 업데이트 (뷰포트 기준)
    • 본체(버튼)의 위치가 변경되었을 때 레이어에 영향 없음. (유기적 동작 X)

Popper

  • Popper active 시,
    • 웹뷰 resize 시 위치값(translate x,y) 업데이트 (웹문서 기준)
    • 스크롤 시 호출한 요소(버튼)와 잘 붙어있음.

Ant

Select 컴포넌트를 살펴봤을 때, MUI와 마찬가지로 컴포넌트 레이어 마크업이
body가 닫히기 직전 위치에 추가 되는 것을 확인할 수 있다.
*다만, hidden 클래스를 가진 채로 추가된 후, toggle class 해주는 방식.
.ant-select-dropdown-hidden {display: none}

Select

  • Select가 focus를 잃으면 닫힘(inactive)
  • 웹뷰 resize 시 레이어 위치값(top,left) 업데이트 (웹문서 기준)
  • 스크롤 시 본체(버튼)와 잘 붙어있음.

일반적으로 방법 1) 을 사용하는 경향.

레퍼런스는 충분히 봤지만,
하나의 컴포넌트의 마크업이 웹문서 내 여러 곳에 흩어져있는 걸 선호하지 않는 상태(?).
*고집불통

초기에 컴포넌트를 설계할 때, 컴포넌트 간의 조합은 최소화하고 컴포넌트와 모듈 CSS를 1:1로 두어 해당 컴포넌트의 모든 스타일링을 한곳(Select.module.scss)에서 관리하고 있기 때문에
레이어 마크업을 외부에 만드는 개념이 아직 생소하다. *관리(control)가 제대로 될까?😟

2) 를 밀고 나가 보자! 고정 위치(fixed position) 📌

  • 레이어에 position: fixed를 준다. 👉 뷰포트 기준
  • 인라인 스타일로 x,y축 좌표를 준다.
    • 요소의 크기/위치 정보를 알려주는 getBoundingClientRect() 메소드를 통해
      부모(컴포넌트)의 크기/위치값을 가져와 각각 top, left, minWidth 적용.
    • 부모(컴포넌트) 기준 0,0 좌표로부터 size에 따른 높이 + 간격(8px) 고정값 transform 적용.

추가 UX 정책(rules)이 필요하다.

  • 스크롤 가능 여부: ⭕
  • 스크롤에 따른 좌표값 업데이트 여부: ❌
  • 웹뷰 resize 시 레이어 좌표값 업데이트 여부: ❌
  • 웹뷰 resize, 스크롤 시 레이어 비활성화(inactive) 여부: ⭕

🎉 ta-da!

멋지게 자기 주장을 하는 요녀석

기특하게도 잘 빠져나온다..🤧

0개의 댓글