포지셔닝 라이브러리(Positioning Library)

지니씨·2025년 1월 11일
0

프론트엔드

목록 보기
86/86
  • 요소를 화면에 동적으로 배치, 충돌 방지, 스크롤/뷰포트 경계 관리 등
  • 툴팁, 모달/팝업, 드롭다운, 드로워 등 컴포넌트 구현에 활용

floating-ui

  • https://floating-ui.com/docs/getting-started
  • 라이브러리 종류
    • @floating-ui/dom web with vanilla JS
    • @floating-ui/react, @floating-ui/react-native, @floating-ui/vue,
    • @floating-ui/core JS를 실행할 수 있는 다른 플랫폼 (e.g. Canvas, WebGL)
  • 기본 사용 예제 코드
    function update() {
      computePosition(button, tooltip, {
        // ... options ...
      }).then(({x, y, placement, middlewareData}) => {
        // ... positioning logic ...
      });
    }
  • 참고
    • chakra-ui 에서 사용

computePosition

  • 플로팅 요소의 크기는 배치 전후에 변하지 않아야 함
  • 플로팅 요소는 computePosition() 호출전 다음 스타일을 가져야 DOM 트리의 어느 곳에나 플로팅 요소를 배치하고, 조상 컨테이너의 CSS 스타일에 관계없이 올바르게 배치할 수 있음
    #floating {
      position: absolute;
      width: max-content; //  (or a fixed value)
      top: 0;
      left: 0;
    }

computePosition() 함수

  • Promise를 반환, 반환된 좌표(x, y)를 사용하여 플로팅 요소에 스타일 적용
  • 단일 호출로 끝나므로 스크롤, 윈도우 크기 변경 등에 대한 동적 위치 변경은 autoUpdate를 사용하여 처리
  • 리턴값 타입
    interface ComputePositionReturn {
      x: number;
      y: number;
      placement: Placement;
      strategy: Strategy;
      middlewareData: MiddlewareData;
    }

Options

  • placement
    • 기본 bottom
    • 'top-start' | 'top' | 'top-end' | 'right-start' | 'right' | 'right-end' | 'bottom-start' | 'bottom' | 'bottom-end' | 'left-start' | 'left' | 'left-end'
    • middleware 의 offset 을 통해 커스텀 위치 조정 가능
  • strategy
    • 기본 ``
    • 'absolute' | 'fixed';
  • middleware
    • 아래 항목에서 자세히 설명

Middleware

  • 플로팅 요소의 위치를 변경하는 객체들
  • 필수 속성 name, fn 과 선택적 속성 options 를 가지는 객체들
  • computePosition() 호출과 렌더링을 위한 데이터의 최종 반환 사이에서 동작
  • 선언된 순서에 따라 실행
  • fndata라는 선택적 속성 반환 가능, middlewareData 속성으로 접근 가능
  • 리턴값 타입
    interface MiddlewareState {
      x: number;
      y: number;
      initialPlacement: Placement;
      placement: Placement;
      strategy: Strategy;
      middlewareData: MiddlewareData;
      elements: Elements;
      rects: ElementRects;
      platform: Platform;
    }
  • 호출 순서
    const middleware = [
      offset(),
      // ...
      arrow({element: arrowElement}),
      hide(),
    ];

Placement modifiers

  • offset()
    • middleware 중 가장 먼저 호출되어야 함
    • 플로팅 요소와 트리거 요소 간의 거리 또는 마진 지정
    • options
  • inline()
    • 하이퍼링크나 범위 선택과 같은 참조 요소에 유용
    • flip() 사용 전 호출
    • options

visibility optimizers

  • shift()
    • 플로팅 요소의 콘텐츠 길이로 인해 정상적으로 보이지 않는다면 자동으로 플로팅 요소 이동, 옵션 객체를 전달하여 추가 수정 가능
    • options
  • flip()
    • 플로팅 요소가 지정된 placement 로 노출되었으나 정상적으로 보이지 않는다면 자동으로 위치 변경
    • autoPlacement()의 대안이므로 둘 중 하나만 사용할 수 있음
    • options
  • autoPlacement()
    • 플로팅 요소에 어떤 배치가 가장 적합할지 모르거나 명시적으로 지정할 필요가 없을 때 유용
    • flip()의 대안이므로 둘 중 하나만 사용할 수 있음
    • options
  • size()
    • 플로팅 요소의 크기를 변경할 수 있는 데이터 제공
    • e.g. 최대 크기가 지정되지 않은 경우 플로팅 요소가 뷰포트(or 클리핑 컨텍스트)보다 너무 크지 않게 조정
    • e.g. 플로팅 요소의 크기를 참조 요소의 너비/높이와 일치시킬 수 있음
    • flip() 과 함께 사용 시
      • size, flip 은 동일한 padding 값 사용해야 함
      • flip 다음으로 size 사용
      • flip 전에 size 사용해야 한다면, 허용 가능한 최소 크기와 위치 설정
    • 드롭다운 레이어의 콘텐츠 너비와 상관없이 참조 영역의 너비와 맞추는 예제
      size({
        apply({rects, elements}) {
          Object.assign(elements.floating.style, {
            minWidth: `${rects.reference.width}px`,
          });
        },
      });
    • 플로팅 요소에 maxHeight 스타일을 그대로 두면 플로팅 요소가 확장되는 경우 문제가 발생할 수 있음, apply 함수에서 scrollHeightavailableHeight보다 작은 경우 maxHeight 값을 제거해 이슈 방지
    • options

Data providers

  • arrow()
    • middleware 중 가장 나중에 호출
    • 플로팅 요소에 DOM 추가 필요, 화살표 영역이 될 요소를 인자로 넘겨줘야 함
    • 스타일을 바로 적용하지않고 middlewareData로 통해 데이터만 제공, 스타일 추가 처리 필요
    • options
  • hide()
    • middleware 중 가장 나중에 호출
    • 특정 상황에서 플로팅 요소 숨길 수 있는 데이터 제공
    • e.g. 트리거 요소가 보이지 않게되면 플로팅 요소도 보이지 않게 처리
    • options
  • size() visibility optimizers 에서 설명

custom

autoUpdate

  • 화면을 스크롤하거나 크기를 조정할 때와 동적인 상황에서도 플로팅 요소가 참조 요소에 고정된 상태를 유지하려면 필요할 때 위치를 지속적으로 업데이트해야 함, 이 문제를 해결하기 위해 autoUpdate()는 필요할 때 computePosition()을 호출하는 업데이트 함수를 자동으로 호출하는 리스너를 추가
  • 업데이트는 일반적으로 약 1ms 정도 소요
  • 성능 저하를 방지하기위해 플로팅 요소 노출이 끝날 때 cleanup 함수 실행을 통해 auto update 를 중지해야 함
  • options
    • ancestorScroll true
    • ancestorResize true
    • elementResize true
    • layoutShift true
    • animationFrame false
      : 모든 애니메이션 프레임에서 플로팅 요소의 위치를 업데이트할지 여부
      : 참조 요소가 transforms 으로 애니메이션이 동작되고 있거나, 조상 플로팅 요소의 스크롤 컨텍스트를 벗어날 때 중첩된 플로팅 요소가 고정되어있을 때에는 사용 주의

detectOverflow

  • 플로팅 또는 참조 요소가 클리핑 컨테이너나 커스텀 경계를 넘는지 감지
  • visibility optimizers middleware (shift, flip, autoPlacement, size) 에서 충돌 감지를 위해 이 기능 사용
  • 커스텀 미들웨어에서 활용

Virtual Elements

  • 사용자 정의 참조 영역을 기준으로 플로팅 요소를 배치하여 컨텍스트 메뉴, 범위 선택, 커서 따라가기 등에 유용
  • 가장 기본적인 가상 요소는 실제 요소와 유사한 getBoundingClementRect 메서드를 가진 일반 객체

Misc

  • z-index stacking
    • 가이드 X, 사용자가 알아서 처리
    • z-index 충돌 자동 해결을 위한 feature 논의중
  • 조상 영역에 의해 플로팅 요소가 잘릴 때
    • 클리핑을 유발하는 영역 외부에 플로팅 요소 위치
    • fixed strategy 활용
  • 플로팅 요소의 너비가 뷰포트를 넘어설 때
    • 폴로팅 요소에 max-width 스타일 지정을 통해 너비 제한
    • size 미들웨어 활용
  • 단위
    • 플로팅 UI는 픽셀 단위와 완전히 호환됨, rem과 같은 상대적인 단위를 사용하는 경우 offset 미들웨어를 통해 단위 변경
    computePosition(reference, floating, {
      // 1rem => 16px
      middleware: [offset(remToPx(1))],
    });

popper

floating-ui 사용 권장, 마이그레이션 시 참고

  • Floating-UI는 Popper 보다 하위 수준의 라이브러리
    • gzipped 기준 7.1k -> 5.9k
  • Popper 보다 추가적인 처리가 필요
    • Popper에서는 createPopper()를 호출하면 자동으로 Popper 요소가 배치되었으나, Floating-UI는 middleware를 자동으로 추가하지 않고 원하는대로 사용할 수 있는 순수한 데이터만 반환, 스타일 추가도 직접해야 함
    • Popper 는 스크롤 및 크기 조정에서 위치를 업데이트하기 위해 리스너를 자동 추가했으나, Floating-UI는 직접 추가해야 함
  • Floating-UI는 Popper 와 달리 기본적으로 ResizeObserver 리스너를 추가하여 추가 업데이트 엣지 케이스를 처리 함
  • createPopper() -> computePosition()를 사용하여 위치 계산
  • placement, strategy
    • Popper 와 동일하게 세번째 옵션 객체로 전달
    • auto placement 는 middleware 에서 처리
  • modifiers -> middleware

Tippy.js

  • Popper.js를 기반으로 만들어진 툴팁 전용 라이브러리
  • 간단한 툴팁을 빠르게 구현할 때 유용
profile
하루 모아 평생 🧚🏻

0개의 댓글

관련 채용 정보