[React] 웹사이트에 Parallax 효과 구현하기

2025. 2. 19. 18:54·React
728x90

최근에 진행한 프로젝트에서 Parallax 효과를 구현한적이 있어서 이에 대해 글로 정리해보고자 한다.


Parallax 효과란?

웹사이트를 구경하다 보면 스크롤을 내릴 때 여러 요소들이 각각 다른 속도로 움직이며 입체감을 주는 효과를 본 적이 있을 것이다. 이런 효과를 'Parallax(시차) 효과'라고 한다. 처음 이 효과를 웹사이트에서 보았을 때 굉장히 신기했다.

 

Parallax 효과는 원래 비디오 게임이나 애니메이션에서 자주 사용되던 기법이다. 배경은 느리게 움직이고 전경은 빠르게 움직여서 깊이감을 만들어내는 방식이다. 이 개념은 우리 눈이 멀리 있는 물체보다 가까이 있는 물체가 더 빨리 움직이는 것처럼 인식하는 원리를 활용한 것이라고 할 수 있다!

 

웹 개발에서 이 효과는 주로 스크롤 이벤트와 연동하여 구현된다. 사용자가 페이지를 스크롤할 때 여러 레이어가 서로 다른 속도로 움직이며 시각적 깊이감을 만들어낸다. 이를 통해 단조로울 수 있는 웹페이지에 생동감을 불어넣을 수 있다.


React에서 Parallax 효과 구현하기

그럼 이제 React에서 Parallax 효과를 구현해볼까?

React에서 Parallax 효과를 구현하기 위해서는 여러 방법이 있다.

가장 기본적인 방법은 스크롤 이벤트를 직접 처리하여 요소의 위치를 조정하는 것이다.

하지만 이 방법은 성능 이슈와 복잡한 계산이 필요하여 번거로울 수 있다.

import React, { useEffect, useState } from 'react';

function SimpleParallax() {
  const [scrollY, setScrollY] = useState(0);

  useEffect(() => {
    function handleScroll() {
      setScrollY(window.scrollY);
    }

    window.addEventListener('scroll', handleScroll);
    return () => {
      window.removeEventListener('scroll', handleScroll);
    };
  }, []);

  return (
    <div style={{ height: '2000px' }}>
      <div
        style={{
          position: 'absolute',
          top: `${100 + scrollY * 0.5}px`, // 배경은 천천히 움직임
          left: '50%',
          transform: 'translateX(-50%)',
          fontSize: '30px',
          color: 'blue',
        }}
      >
        배경 텍스트
      </div>
      <div
        style={{
          position: 'absolute',
          top: `${150 + scrollY * 0.8}px`, // 전경은 빠르게 움직임
          left: '50%',
          transform: 'translateX(-50%)',
          fontSize: '40px',
          color: 'red',
        }}
      >
        전경 텍스트
      </div>
    </div>
  );
}

export default SimpleParallax;

이 코드에서는 스크롤 이벤트를 감지하여 요소의 위치를 동적으로 변경한다.

배경 텍스트는 스크롤 값의 0.5배로, 전경 텍스트는 0.8배로 움직이게 하여 시차 효과를 만들어낸다.

하지만 이 방식은 매번 스크롤할 때마다 컴포넌트가 리렌더링되어 성능 이슈가 발생할 수 있다.


react-scroll-parallax 라이브러리

그럼 어떻게 위 문제를 해결할 수 있을까?!!!

다행히도 React 생태계에는 Parallax 효과를 쉽게 구현할 수 있는 라이브러리들이 있다.

그 중에서도 react-scroll-parallax는 사용하기 쉽고 강력한 기능을 제공한다.

 

이 라이브러리를 사용하기 위해서는 먼저 설치가 필요하다.

아래 코드를 참고하여 설치를 진행하자.

npm install react-scroll-parallax
# 또는
yarn add react-scroll-parallax

react-scroll-parallax는 다음과 같은 주요 컴포넌트들을 제공한다!

 

  • ParallaxProvider: 앱 전체에 Parallax 컨텍스트를 제공
  • Parallax: 개별 요소에 Parallax 효과를 적용
  • ParallaxBanner: 배경 이미지에 Parallax 효과를 적용하는 특화된 컴포넌트

이 다음 순서부터 차례대로 어떻게 사용하는지에 대해 설명해보겠다.


1. ParallaxProvider 설정하기

react-scroll-parallax를 사용하기 위한 첫 번째 단계는 애플리케이션의 최상위 컴포넌트에 ParallaxProvider를 설정하는 것이다!!

import React from 'react';
import { ParallaxProvider } from 'react-scroll-parallax';
import { BrowserRouter } from 'react-router-dom';
import App from './App';

function Root() {
  return (
    <ParallaxProvider>
      <BrowserRouter>
        <App />
      </BrowserRouter>
    </ParallaxProvider>
  );
}

export default Root;

 

(이 코드에서 Root 컴포넌트는 예시로 만든 컴포넌트로서 최상위 파일로 index.js 또는 App.js에서 사용하면 된다!)

이 코드에서 ParallaxProvider는 모든 하위 컴포넌트에서 Parallax 효과를 사용할 수 있게 해주는 컨텍스트 제공자이다.

일반적으로 라우터나 다른 전역 Provider들과 함께 최상위에 배치한다.


2. ParallaxBanner 컴포넌트 활용하기

ParallaxBanner는 배경 이미지나 여러 레이어로 구성된 배너를 쉽게 만들 수 있게 도와주는 컴포넌트이다.

import React from 'react';
import { ParallaxBanner } from 'react-scroll-parallax';

function HeroBanner() {
  return (
    <ParallaxBanner
      layers={[
        {
          image: 'https://source.unsplash.com/random/1920x1080?nature',
          speed: -20,
        },
        {
          children: (
            <div style={{
              position: 'absolute',
              top: '50%',
              left: '50%',
              transform: 'translate(-50%, -50%)',
              color: 'white',
              fontSize: '3rem',
              textAlign: 'center',
            }}>
              <h1>환영합니다!</h1>
              <p>Parallax 효과가 적용된 웹사이트입니다</p>
            </div>
          ),
          speed: -10,
        },
      ]}
      style={{
        height: '100vh',
      }}
    />
  );
}

export default HeroBanner;

이 예시에서는 배경 이미지와 텍스트 레이어로 구성된 전체 화면 배너를 생성한다.

배경 이미지는 speed 값 -20으로 텍스트보다 빠르게 움직이고, 텍스트 레이어는 speed 값 -10으로 조금 더 느리게 움직인다.

음수 speed 값은 스크롤 방향과 반대로 움직이는 것을 의미한다.


3. Layer 속성 이해하기

ParallaxBanner의 layers 속성은 다양한 설정을 통해 세밀한 제어가 가능하다. 주요 속성들은 다음과 같다.

  • image: 배경 이미지 URL
  • speed: 움직임 속도 (-100 ~ 100, 음수는 반대 방향)
  • expanded: 레이어 확장 여부
  • opacity: 불투명도 설정 (배열로 설정 시 스크롤에 따라 변화)
  • scale: 크기 설정 (배열로 설정 시 스크롤에 따라 변화)
  • shouldAlwaysCompleteAnimation: 애니메이션 완료 보장 여부
  • children: 레이어 내부에 렌더링할 React 요소

더 복잡한 예시를 살펴보자.

import React from 'react';
import { ParallaxBanner } from 'react-scroll-parallax';
import styled from 'styled-components';

const Content = styled.div`
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  color: white;
  text-align: center;
  width: 100%;
  max-width: 800px;
`;

function AdvancedBanner() {
  return (
    <ParallaxBanner
      layers={[
        {
          image: '/images/mountains.jpg',
          speed: -30,
          scale: [1.2, 1, 'easeOutCubic'],
          shouldAlwaysCompleteAnimation: true,
        },
        {
          speed: -15,
          opacity: [0, 1, 'easeInQuad'],
          expanded: false,
          children: (
            <div
              style={{
                position: 'absolute',
                inset: 0,
                background: 'linear-gradient(rgba(0,0,0,0.2), rgba(0,0,0,0.8))',
              }}
            />
          ),
        },
        {
          speed: 10,
          scale: [0.8, 1],
          opacity: [0, 1],
          children: (
            <Content>
              <h1>고급 Parallax 효과</h1>
              <p>
                여러 레이어와 애니메이션 속성을 조합하여
                복잡한 시각적 효과를 만들 수 있습니다.
              </p>
            </Content>
          ),
        },
      ]}
      style={{
        height: '100vh',
      }}
    />
  );
}

export default AdvancedBanner;

이 예시에서는 세 개의 레이어를 사용한다.

  1. 배경 이미지 레이어: 스크롤에 따라 축소되는 효과
  2. 그라데이션 오버레이 레이어: 스크롤에 따라 투명도가 증가
  3. 컨텐츠 레이어: 스크롤에 따라 확대되고 나타나는 효과

속도값을 음수와 양수로 다르게 설정하여, 레이어들이 서로 다른 방향으로 움직이게 함으로써 더욱 역동적인 효과를 만들어낸다.


4. 커스텀 Parallax 효과 만들기

때로는 ParallaxBanner 대신 개별 요소에 Parallax 효과를 적용하고 싶을 수 있다. 이럴 때는 Parallax 컴포넌트를 사용할 수 있다!

import React from 'react';
import { Parallax } from 'react-scroll-parallax';
import styled from 'styled-components';

const Section = styled.section`
  height: 100vh;
  display: flex;
  justify-content: center;
  align-items: center;
  background-color: #f5f5f5;
`;

const Card = styled.div`
  padding: 2rem;
  background-color: white;
  border-radius: 8px;
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
  max-width: 500px;
`;

function ParallaxSection() {
  return (
    <Section>
      <Parallax translateY={[50, -50]} opacity={[0.2, 1]}>
        <Card>
          <h2>스크롤에 따라 움직이는 카드</h2>
          <p>
            이 카드는 스크롤 위치에 따라 위아래로 움직이며, 
            투명도도 변화합니다. 스크롤을 내리면 아래에서 위로 
            올라오면서 선명해집니다.
          </p>
        </Card>
      </Parallax>
    </Section>
  );
}

export default ParallaxSection;

이 코드에서 Parallax 컴포넌트는 자식 요소(Card)에 Parallax 효과를 적용한다.

translateY 속성은 세로 방향 이동을, opacity 속성은 투명도 변화를 제어한다.

배열 형태의 값은 시작값과 끝값을 나타내며, 스크롤 위치에 따라 자동으로 보간된다.


전체 코드 및 구현화면

App.js

import { ParallaxProvider } from 'react-scroll-parallax';
import ParallaxSection from './ParallaxSection';

function App() {
    return (
        <ParallaxProvider>
            <div className="App">
                <ParallaxSection index={0} />
                <ParallaxSection index={1} />
                <ParallaxSection index={2} />
                <ParallaxSection index={3} />
            </div>
        </ParallaxProvider>
    );
}

export default App;

ParallaxSection.js

import React from 'react';
import { Parallax } from 'react-scroll-parallax';
import styled, { keyframes } from 'styled-components';

const float = keyframes`
    0% { transform: translateY(0px); }
    50% { transform: translateY(-20px); }
    100% { transform: translateY(0px); }
`;

const Section = styled.section`
    height: 100vh;
    position: relative;
    overflow: hidden;
    display: flex;
    align-items: center;
    justify-content: center;
    background-color: ${(props) => props.bgColor || '#1a1a1a'};
    perspective: 1000px;
`;

const Background = styled.div`
    position: absolute;
    top: -20%;
    left: -10%;
    width: 120%;
    height: 140%;
    background-image: ${(props) => `url(${props.bgImage})`};
    background-size: cover;
    background-position: center;
    opacity: 0.7;
    filter: blur(2px);
    transform-style: preserve-3d;
`;

const Content = styled.div`
    position: absolute;
    top: 40%;
    left: 50%;
    transform: translate(-50%, -50%);
    z-index: 1;
    color: white;
    text-align: center;
    width: 100%;
    padding: 0 20px;
`;

const Card = styled.div`
    padding: 4rem;
    background-color: rgba(0, 0, 0, 0.8);
    border-radius: 20px;
    max-width: 900px;
    margin: 0 auto;
    box-shadow: 0 20px 50px rgba(0, 0, 0, 0.5);
    backdrop-filter: blur(10px);
    border: 1px solid rgba(255, 255, 255, 0.1);
    animation: ${float} 6s ease-in-out infinite;
    transform-origin: center center;

    h2 {
        font-size: 5rem;
        margin-bottom: 2rem;
        color: ${(props) => props.accentColor || '#fff'};
        text-shadow: 0 0 20px rgba(0, 0, 0, 0.5);
        letter-spacing: 2px;
    }

    p {
        font-size: 1.8rem;
        line-height: 1.8;
        text-shadow: 0 0 10px rgba(0, 0, 0, 0.5);
        margin: 0;
    }
`;

const sections = [
    {
        title: 'Welcome to Parallax',
        text: 'Embark on a journey through space and time',
        bgImage: 'https://source.unsplash.com/1920x1080/?cosmos',
        bgColor: '#0a0a2a',
        accentColor: '#00ffaa',
    },
    {
        title: 'Deep Ocean',
        text: 'Dive into the mysterious depths of the sea',
        bgImage: 'https://source.unsplash.com/1920x1080/?underwater',
        bgColor: '#0a2a3a',
        accentColor: '#00ffff',
    },
    {
        title: 'Ancient Forest',
        text: 'Discover the secrets of primordial nature',
        bgImage: 'https://source.unsplash.com/1920x1080/?mystical-forest',
        bgColor: '#1a2a1a',
        accentColor: '#66ff99',
    },
    {
        title: 'Mountain Peak',
        text: 'Rise above the clouds to touch the sky',
        bgImage: 'https://source.unsplash.com/1920x1080/?mountain-peak',
        bgColor: '#2a1a2a',
        accentColor: '#ff66aa',
    },
];

function ParallaxSection({ index = 0 }) {
    const section = sections[index % sections.length];

    return (
        <Section bgColor={section.bgColor}>
            <Parallax translateY={[-30, 30]} scale={[1.0, 1.3]} rotate={[-5, 5]} opacity={[0.6, 1]} easing="easeInQuad">
                <Background bgImage={section.bgImage} />
            </Parallax>

            <Content>
                <Parallax
                    translateY={[-50, 50]}
                    scale={[0.9, 1.1]}
                    rotate={[3, -3]}
                    opacity={[0.8, 1]}
                    easing="easeOutQuad"
                >
                    <Card accentColor={section.accentColor}>
                        <h2>{section.title}</h2>
                        <p>{section.text}</p>
                    </Card>
                </Parallax>
            </Content>
        </Section>
    );
}

export default ParallaxSection;

 

구현화면

 

728x90

'React' 카테고리의 다른 글

[React] Create React App의 지원 종료 ⚠️  (1) 2025.02.22
[React] 반응형 웹 개발? react-responsive가 다해줘!!!  (1) 2025.02.20
[React] Protected Routes로 페이지 접근 제어하기 🔐  (0) 2025.02.18
[React] Footer 스타일링 with Flexbox, 웹에 Footer 적용해보기!  (0) 2025.02.16
[React] Naver Maps API를 활용한 지도 서비스 구현하기 *마커 커스터마이징 포함!*  (1) 2025.02.15
'React' 카테고리의 다른 글
  • [React] Create React App의 지원 종료 ⚠️
  • [React] 반응형 웹 개발? react-responsive가 다해줘!!!
  • [React] Protected Routes로 페이지 접근 제어하기 🔐
  • [React] Footer 스타일링 with Flexbox, 웹에 Footer 적용해보기!
프론트 개발자 김현중
프론트 개발자 김현중
👋반갑습니다 저는 나눔을 실천하는 개발자 꿈나무 김현중입니다⌨️🚀
  • 프론트 개발자 김현중
    삥구의 개발블로그
    프론트 개발자 김현중
  • 전체
    오늘
    어제
    • 분류 전체보기 (92)
      • 알고리즘 (5)
      • Swift (3)
      • 컴퓨터네트워크 (1)
      • React (38)
      • Docker (1)
      • SQL (8)
      • Database (2)
      • 배포 (1)
      • Spring (9)
      • TypeScript (5)
      • Next.js (12)
      • Git (1)
      • 회고 (1)
      • 컴퓨터그래픽스 (2)
      • Python (1)
      • Brew (1)
      • LangChain (1)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    appRouter
    typescript
    java
    database
    javascript
    코딩테스트
    ReactHooks
    데이터베이스
    springboot
    백준
    nextjs
    웹개발
    프론트엔드
    알고리즘
    react
    Spring
    Backend
    Next.js
    MySQL
    frontend
  • 최근 댓글

  • 최근 글

  • 250x250
  • hELLO· Designed By정상우.v4.10.1
프론트 개발자 김현중
[React] 웹사이트에 Parallax 효과 구현하기
상단으로

티스토리툴바