avatar
morethan-log

fixed 요소만큼 높이 차지하는 CTA 버튼 구현하기

webviewReact
Jun 29
·
4 min read

웹뷰에서 마주하는 여러 팁을 공유합니다.

웹뷰를 구현하다보면 아래와 같은 화면을 자주 마주하게 됩니다.

아래 사진은 토스에서 가져왔습니다.

until-680

이때 하단에 항상 위치하고 있는 버튼을 보통 CTA(Click-To-Action) 버튼이라고 부르는데요. 이러한 버튼은 일반적으로 컨텐츠 위에 위치하고 있어야하기에 position:fixed로 구현하면 됩니다.

간단한 것 같지만 한가지 고려 해야할 점이 있습니다. 컨텐츠 영역에서 특정한 높이를 차지하고 있지 않기에 뒤에 컨텐츠를 가리게 된다는 점입니다.

until-681

그럼 어떻게 하면 뒤 컨텐츠 영역을 가리지 않고 CTA 버튼을 만들 수 있을까요?

가장 단순한 방법으로는 최하단에 높이를 차지하는 요소를 두면 됩니다.

const Example = () => {
  return (
    <div>
      content
      <Footer />
      <div style={{ height: 60 }} />
      {/* 내부적으로 60px의 높이를 가진 fixed element를 렌더하고 있음*/}
      <CTAButton />
    </div>
  )
}

export default Example

위와 같은 방식은 잘 동작하겠지만, 아래와 같은 문제점들을 마주할 수 있습니다.

바로 버튼의 높이가 동적으로 바뀌는 것에 대응할 수 없다는 것입니다.

이를 해결하기 위해서는 ResizeObserver 라는 API를 사용하면 됩니다.

해당API를 사용하면 요소의 사이즈 변화를 감지하여 해당 높이를 가져올 수 있고, 이를 spacer에 주입해줄 수 있습니다.

const Example = () => {
  const targetRef = useRef<HTMLDivElement>(null)
  const spacerRef = useRef<HTMLDivElement>(null)

  const observer = new ResizeObserver(([entry]) => {
    if (spacerRef.current) {
      spacerRef.current.style.height = `${
        entry.target.getBoundingClientRect().height
      }px`
    }
  })

  useEffect(() => {
    if(!targetRef.current) return

    const el = targetRef.current

    observer.observe(el)

    return () => {
      observer.unobserve(el)
    }
  }, [])
  
  return (
    <div>
      content
      <Footer />
      <div style={{ height: 60 }} />
      {/* 내부적으로 60px의 높이를 가진 fixed element를 렌더하고 있음*/}
      <CTAButton />
    </div>
  )
}

export default Example

이러한 CTA 버튼이나 Appber처럼 fixed요소만큼 너비를 차지해야하는 경우들이 자주 발생하기에 useSpacer라는 hook으로 분리해 보겠습니다.

import { useRef, useEffect } from "react";

export const useSpacer = () => {
  const targetRef = useRef<HTMLDivElement>();
  const spacerRef = useRef<HTMLDivElement>(null);

  const observer = new ResizeObserver(([entry]) => {
    if (spacerRef.current) {
      spacerRef.current.style.height = `${entry.target.getBoundingClientRect().height}px`;
    }
  });

  useEffect(() => {
    if(!targetRef.current) return

    const el = targetRef.current

    observer.observe(el)

    return () => {
      observer.unobserve(el)
    }
  }, [])

  return { spacerRef, targetRef };
};

이제 CTA 버튼을 손쉽게 구현할 수 있습니다! 👏


- 컬렉션 아티클






몰댄민입니다