fixed 요소만큼 높이 차지하는 CTA 버튼 구현하기
webviewReact
웹뷰에서 마주하는 여러 팁을 공유합니다.
웹뷰를 구현하다보면 아래와 같은 화면을 자주 마주하게 됩니다.
아래 사진은 토스에서 가져왔습니다.
이때 하단에 항상 위치하고 있는 버튼을 보통 CTA(Click-To-Action) 버튼이라고 부르는데요. 이러한 버튼은 일반적으로 컨텐츠 위에 위치하고 있어야하기에 position:fixed
로 구현하면 됩니다.
간단한 것 같지만 한가지 고려 해야할 점이 있습니다. 컨텐츠 영역에서 특정한 높이를 차지하고 있지 않기에 뒤에 컨텐츠를 가리게 된다는 점입니다.
그럼 어떻게 하면 뒤 컨텐츠 영역을 가리지 않고 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 버튼을 손쉽게 구현할 수 있습니다! 👏