
메인 랜딩 페이지의 사용자 경험(UX)을 향상시키기 위해 애니메이션 효과를 추가하였습니다.
이를 위해 여러 애니메이션 라이브러리를 비교한 후, Framer Motion을 최종 선택하여 적용하였습니다.
랜딩 페이지에 애니메이션을 적용하는 방법은 다양하지만, 개발 생산성과 유지보수성을 고려했을 때 Framer Motion이 가장 적합하다고 판단했습니다.
아래는 애니메이션 적용을 위한 여러 방법을 비교한 내용입니다.
✅ 브라우저의 기본 API를 사용하여 세밀한 제어 가능
🚨 여러 컴포넌트마다 Intersection Observer를 직접 설정해야 하므로 코드 중복 증가
🚨 애니메이션 로직을 직접 작성해야 해서 CSS 또는 JS 애니메이션 구현 부담 증가
✅ useInView 훅을 제공하여 Intersection Observer를 쉽게 사용할 수 있음
✅ 코드 재사용성이 높아 다양한 컴포넌트에서 활용 가능
🚨 뷰포트 진입 여부만 감지할 수 있고, 애니메이션 기능은 포함되지 않음
🚨 CSS 전환 효과나 다른 애니메이션 라이브러리와 별도로 조합해야 하는 번거로움이 있음
✅ 전체 페이지 스크롤 및 스냅 효과 구현에 최적화
🚨 개별 요소의 등장 애니메이션 적용이 어려움
🚨 랜딩 페이지의 다양한 인터랙션 구현에는 적합하지 않음
✅ 선언적 API → JSX에서 initial, animate, whileInView 등을 사용하여 간결하게 애니메이션 적용 가능
✅ Intersection Observer 기능 내장 → whileInView를 통해 별도 설정 없이 뷰포트 진입 시 애니메이션 실행
✅ 풍부한 애니메이션 옵션 → 전환 효과, 레이아웃 애니메이션, 제스처 지원
✅ Next.js 및 React와 높은 호환성 → SSR 환경에서도 안정적으로 작동
🚨 외부 라이브러리에 대한 의존성 증가
🚨 다양한 기능을 제공하므로 고급 기능 학습이 필요할 수 있음 (단, 기본 사용법은 직관적임)
애니메이션을 적용하기 위해 Intersection Observer 직접 구현, react-intersection-observer, react-fullpage 등을 고려했으나,
간결한 코드, 내장된 뷰포트 감지 기능, 강력한 애니메이션 옵션을 갖춘 Framer Motion이 가장 적합하다고 판단하였습니다.
랜딩 페이지 내 다양한 요소에 애니메이션을 적용하여 보다 동적인 사용자 경험을 제공하였습니다.
import { motion } from 'framer-motion';
<motion.div
initial={{ opacity: 0, y: -50 }} // 초기 상태: 투명 + 위쪽 위치
animate={{ opacity: 1, y: 0 }} // 최종 상태: 불투명 + 원래 위치
transition={{ duration: 0.8 }} // 애니메이션 지속 시간 0.8초
>
{/* 헤더 내용 */}
</motion.div>
✅ 초기 상태에서 불투명(0) & 위쪽(-50px) → 서서히 나타나면서 원래 위치로 이동
✅ 애니메이션 지속 시간(duration: 0.8)을 적용하여 부드러운 효과 제공
| Framer motion 적용 전 | Framer motion 적용 후 |
|---|---|
![]() | ![]() |
✅ 왼쪽에서 등장하는 요소 → leftVariant
✅ 오른쪽에서 등장하는 요소 → rightVariant
// 왼쪽 등장 애니메이션 variant
const leftVariant = {
hidden: { opacity: 0, x: -100 }, // 초기 상태: 투명 & 왼쪽 위치
visible: { opacity: 1, x: 0 }, // 최종 상태: 불투명 & 원래 위치
};
// 오른쪽 등장 애니메이션 variant
const rightVariant = {
hidden: { opacity: 0, x: 100 },
visible: { opacity: 1, x: 0 },
};
import { motion } from 'framer-motion';
<motion.div
initial="hidden"
whileInView="visible" // 뷰포트에 들어오면 애니메이션 실행
viewport={{ once: true, amount: 0.5 }} // 한 번만 실행, 50% 노출 시 트리거
transition={{ duration: 0.7 }} // 애니메이션 지속 시간
variants={leftVariant} // {rightVariant} 사용 시 오른쪽 등장 애니메이션
>
{/* 섹션 내용 */}
</motion.div>
✅ 스크롤 시 요소가 화면에 들어올 때 부드럽게 등장
✅ whileInView → 뷰포트에 진입하면 자동으로 애니메이션 실행
✅ viewport={{ once: true, amount: 0.5 }} → 한 번만 실행, 요소가 화면의 50% 이상 보일 때 트리거
| Framer motion 적용 전 | Framer motion 적용 후 |
|---|---|
![]() | ![]() |
import { motion } from 'framer-motion';
<motion.div
initial={{ opacity: 0, y: 50 }} // 초기 상태: 투명 & 아래쪽 위치
whileInView={{ opacity: 1, y: 0 }} // 뷰포트 진입 시 애니메이션 실행
viewport={{ once: true, amount: 0.5 }} // 한 번만 실행, 50% 보일 때 트리거
transition={{ duration: 0.8 }}
>
{/* 푸터 내용 */}
</motion.div>
| Framer motion 적용 전 | Framer motion 적용 후 |
|---|---|
![]() | ![]() |
✅ 초기 상태에서는 모든 요소가 보이지 않다가, 스크롤할 때 자연스럽게 등장
✅ 애니메이션을 추가함으로써 페이지가 더욱 동적이고 생동감 있게 표현됨
✅ 코드의 간결함 유지 + 선언적 API를 사용하여 유지보수성 향상
| 적용 전 | 적용 후 |
|---|---|
| ❌ 요소가 갑자기 나타나 화면 전환이 부자연스러움 | ✅ 부드러운 등장 애니메이션으로 시각적 완성도 향상 |
| ❌ 사용자가 현재 어디를 보고 있는지 모호함 | ✅ 애니메이션으로 화면 흐름을 유도하여 가독성 증가 |
| ❌ Intersection Observer를 직접 사용하면 코드가 복잡함 | ✅ Framer Motion을 활용하여 간결한 코드로 유지보수성 향상 |
Framer Motion을 활용하여 간결한 코드로 동적인 UI를 구현할 수 있었습니다.
특히, 스크롤 시 등장하는 애니메이션을 적용하여 UX를 향상시키는 데 효과적이었습니다.
👉 애니메이션을 적용하여 더 직관적이고 매력적인 랜딩 페이지를 완성할 수 있었습니다.