2025-04-21
Input Range로 이미지 비교 컴포넌트 구현하기
Input Range를 이용해 이미지를 비교할 수 있는 컴포넌트를 구현하는 방법
어떤 이미지를 비교할 때, 두 이미지를 나란히 보여주는 것보다 슬라이더를 이용해 좌우로 움직이며 비교해 보는 것이 사용자 경험이 더 좋을 수 있습니다. 이런 기능을 구현하기 위해서 우리는 라이브러리를 사용하거나 미리 구현된 컴포넌트를 가져다 쓸 수 있습니다. 하지만, 이번 글에서는 보다 쉬운 방법으로 간단하게 구현해 보겠습니다.
구현
우선, input에는 여러 가지 타입이 존재합니다.
text, number, range 등 다양한 타입이 존재하는데, 우리는 그중에서 range 타입을 사용하여 슬라이더를 구현할 것입니다.
range 타입은 가장 기본적인 슬라이더 기능을 제공하며, 사용자가 마우스로 좌우를 드래그하며 최솟값과 최댓값 사이의 값을 선택할 수 있습니다.
바로 이 점을 사용한다면 아주 쉽게 이미지 비교 컴포넌트를 구현할 수 있습니다.
기본적인 이미지를 보여주는 컴포넌트를 만들어 보겠습니다.
export default function ImageCompare({ src }: { src: string }) {
return (
<div className="w-full h-96">
<img
src={src}
alt="기본 이미지"
className="object-cover rounded-lg"
style={{ width: "100%", height: "100%" }}
/>
</div>
);
}정말 간단하게 이미지를 보여주는 컴포넌트를 만들 수 있었습니다. 이제 비교할 이미지가 있어야 하기 때문에, 두 개의 이미지를 프롭으로 받고 겹치게 해보겠습니다.
export default function ImageCompare({
beforeImage,
afterImage,
}: {
beforeImage: string;
afterImage: string;
}) {
return (
<div className="relative w-full h-96">
<img
src={beforeImage}
alt="비교할 이미지"
className="absolute top-0 left-0 object-cover rounded-lg"
style={{ width: "100%", height: "100%" }}
/>
<img
src={afterImage}
alt="비교할 이미지"
className="absolute top-0 left-0 object-cover rounded-lg"
style={{ width: "100%", height: "100%" }}
/>
</div>
);
}여기까지 구현하고 나서 개발자 도구를 열어보면, 두 개의 이미지가 겹쳐져 있는 것을 확인할 수 있습니다. 이제 이 이미지들 아래에 슬라이더를 추가해 보겠습니다.
<>
<div className="relative w-full h-96">
<img
src={beforeImage}
alt="비교할 이미지"
className="absolute top-0 left-0 object-cover rounded-lg"
style={{ width: "100%", height: "100%" }}
/>
<img
src={afterImage}
alt="비교할 이미지"
className="absolute top-0 left-0 object-cover rounded-lg"
style={{ width: "100%", height: "100%" }}
/>
</div>
<input
type="range"
min="0"
max="100"
defaultValue="50"
className="w-full h-full cursor-pointer"
/>
</>이제 슬라이더를 추가했으니, 슬라이더가 움직일 때마다 그 값을 이용해 이미지를 그만큼 잘라내어야 우리가 원하는 비교 기능을 구현할 수 있습니다.
이 방법은 어떻게 구현하느냐에 따라 여러 가지 방법이 있을 수 있지만, 가장 간단하고 마법 같은 방법은 clip-path를 이용하는 것입니다.
clip-path CSS 속성은 요소의 클리핑 범위를 지정합니다. 클리핑 범위 안의 부분은 보여지고, 바깥은 숨겨집니다. MDN - clip-path
clip-path 속성을 이용하면, 슬라이더의 값에 따라 이미지를 잘라내는 효과를 줄 수 있습니다.
우선 슬라이더의 값을 상태로 관리하기 위해 useState를 사용하여 슬라이더의 값을 관리해 보겠습니다.
import { useState } from "react";
const [sliderPos, setSliderPos] = useState(50);
const handleSliderChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setSliderPos(Number(e.target.value));
};이제 슬라이더의 값을 상태로 관리할 수 있게 되었으니, 슬라이더의 값이 바뀔 때마다 handleSliderChange 함수를 호출하여 상태를 업데이트합니다.
슬라이더의 값은 0부터 100까지의 값을 가지므로, clip-path 속성에 적용할 수 있는 값으로 변환해 주어야 합니다.
clip-path 속성은 inset 함수를 사용하여 사각형을 정의할 수 있습니다.
inset 함수는 top, right, bottom, left 값을 받아 사각형을 정의합니다.
clip-path 속성에 inset 함수를 사용하여 슬라이더의 값을 적용해 보겠습니다.
const clipPathValue = `inset(0 ${100 - sliderPos}% 0 0)`;이제 clip-path 속성을 이용하여 이미지를 잘라내는 효과를 줄 수 있습니다.
<>
<div className="relative w-full h-96">
<img
src={beforeImage}
alt="비교할 이미지"
className="absolute top-0 left-0 object-cover rounded-lg"
style={{ width: "100%", height: "100%" }}
/>
<img
src={afterImage}
alt="비교할 이미지"
className="absolute top-0 left-0 object-cover rounded-lg"
style={{
width: "100%",
height: "100%",
clipPath: clipPathValue,
}}
/>
</div>
<input
type="range"
min="0"
max="100"
defaultValue="50"
className="w-full h-full cursor-pointer"
onChange={handleSliderChange}
/>
</>

뺌! 정말 간단하게 이미지 비교 컴포넌트를 구현할 수 있었습니다. 이제 이를 바탕으로 더 많은 기능을 추가해 보거나, 다양한 스타일을 적용하여 나만의 이미지 비교 컴포넌트를 만들어보세요.
글 내용에 대해 궁금한 점이나 코드에 문제가 있다면 메일로 연락 주시면 감사하겠습니다.