본문 바로가기
React

[React] react-scroll을 활용한 부드러운 앵커 스크롤 (Anchor Scroll) 구현하기

by teamnova 2025. 7. 14.
728x90

 

 

안녕하세요 

오늘은 React 환경에서  react-scroll 라이브러리를 활용해  
클릭 시 부드럽게 섹션으로 이동하는 스크롤 내비게이션을 만들어보겠습니다. 

 

 

 

 

1. 먼저 생성돼 있는 react 프로젝트로 이동합니다.

cd [my-react-project]

 

Tailwind CSS 가 사용될 예정이니 아래 링크를 참고해 Tailwind css 를 설치해주세요 

 

Installing with Vite - Installation

Integrate Tailwind CSS with frameworks like Laravel, SvelteKit, React Router, and SolidJS.

tailwindcss.com

 

2. react-scroll 설치

npm install react-scroll

- 이 라이브러리를 통해 스크롤 이벤트를 제어하고, 섹션 감지 및 부드러운 이동 효과를 줄 수 있습니다.

 

 

3. Tailwind CSS 설정

/* src/index.css */
@import "tailwindcss";

- Tailwind CSS v4 이상이라면 따로 @tailwind base;, @tailwind utilities; 같은 구문 없이도
index.css에 아래와 같이 작성만 되어 있으면 자동 적용됩니다

 

 

 

4. Header.jsx 

import { Link } from 'react-scroll';

function Header() {
  return (
    <header className="fixed top-0 w-full bg-white shadow-md z-50">
      <div className="max-w-5xl mx-auto px-6 py-4 flex justify-between items-center">
        <h1 className="text-xl font-bold text-indigo-600">OOO.dev</h1>
        <nav className="space-x-6 text-gray-700 font-medium">
          <Link
            to="home"
            spy={true}
            smooth={true}
            offset={-80}
            duration={500}
            className="cursor-pointer hover:text-indigo-500 transition-colors"
          >
            Home
          </Link>
          <Link
            to="about"
            spy={true}
            smooth={true}
            offset={-80}
            duration={500}
            className="cursor-pointer hover:text-indigo-500 transition-colors"
          >
            About
          </Link>
          <Link
            to="projects"
            spy={true}
            smooth={true}
            offset={-80}
            duration={500}
            className="cursor-pointer hover:text-indigo-500 transition-colors"
          >
            Projects
          </Link>
          <Link
            to="contact"
            spy={true}
            smooth={true}
            offset={-80}
            duration={500}
            className="cursor-pointer hover:text-indigo-500 transition-colors"
          >
            Contact
          </Link>
        </nav>
      </div>
    </header>
  );
}

export default Header;

 

react-scroll 의 주요 구성요소는 아래와 같습니다. 

- to : 이동할 대상 id (ex: "projects")

- smooth : 부드러운 스크롤 효과 (true/false)

- offset : 위치 보정 값 (예: 고정된 헤더 높이만큼 -80)

- spy : 현재 보이는 섹션 감지하여 className에 적용

- duration  : 스크롤 지속 시간 (ms 단위)

 

 

 

 

**참고: 프로젝트 구조는 아래와 같습니다. 

 

 

 

5. Hero.jsx

import { Link } from 'react-scroll';

function Hero() {
  return (
    <section id="home" className="min-h-screen flex flex-col justify-center items-center text-center bg-gray-50 pt-20 px-6">
      <h2 className="text-5xl font-bold text-gray-900 mb-4">Hi, I'm OOO 👋</h2>
      <p className="text-lg text-gray-600 mb-6">
        I build full-stack web & AI-powered apps that feel natural to use.
      </p>
      <Link
        to="projects"
        spy={true}
        smooth={true}
        offset={-80}
        duration={500}
        className="bg-indigo-600 text-white px-6 py-3 rounded-lg text-lg hover:bg-indigo-500 transition cursor-pointer"
      >
        View My Work
      </Link>
    </section>
  );
}

export default Hero;

 

 

 

6. Contact.jsx 

import { Link } from 'react-scroll';

function Contact() {
  return (
    <section id="contact" className="min-h-screen bg-white py-20 px-6">
      <div className="max-w-4xl mx-auto">
        <div className="text-center mb-16">
          <h2 className="text-4xl font-bold text-gray-900 mb-4">Get In Touch</h2>
          <p className="text-lg text-gray-600 max-w-2xl mx-auto">
            I'm always interested in hearing about new opportunities and exciting projects. 
            Let's work together to bring your ideas to life!
          </p>
        </div>
        
        <div className="grid md:grid-cols-2 gap-12">
          <div>
            <h3 className="text-2xl font-semibold text-gray-900 mb-6">Let's Connect</h3>
            <div className="space-y-6">
              <div className="flex items-center space-x-4">
                <div className="w-12 h-12 bg-indigo-100 rounded-full flex items-center justify-center">
                  <span className="text-xl">📧</span>
                </div>
                <div>
                  <h4 className="font-semibold text-gray-900">Email</h4>
                  <p className="text-gray-600">OOO@example.com</p>
                </div>
              </div>
              
              <div className="flex items-center space-x-4">
                <div className="w-12 h-12 bg-indigo-100 rounded-full flex items-center justify-center">
                  <span className="text-xl">📱</span>
                </div>
                <div>
                  <h4 className="font-semibold text-gray-900">Phone</h4>
                  <p className="text-gray-600">123-4567</p>
                </div>
              </div>
              
              <div className="flex items-center space-x-4">
                <div className="w-12 h-12 bg-indigo-100 rounded-full flex items-center justify-center">
                  <span className="text-xl">📍</span>
                </div>
                <div>
                  <h4 className="font-semibold text-gray-900">Location</h4>
                  <p className="text-gray-600">Seoul, Korea</p>
                </div>
              </div>
            </div>
            
            <div className="mt-8">
              <h4 className="font-semibold text-gray-900 mb-4">Follow Me</h4>
              <div className="flex space-x-4">
                <a href="#" className="w-10 h-10 bg-indigo-600 rounded-full flex items-center justify-center text-white hover:bg-indigo-500 transition">
                  <span>📘</span>
                </a>
                <a href="#" className="w-10 h-10 bg-indigo-600 rounded-full flex items-center justify-center text-white hover:bg-indigo-500 transition">
                  <span>🐙</span>
                </a>
                <a href="#" className="w-10 h-10 bg-indigo-600 rounded-full flex items-center justify-center text-white hover:bg-indigo-500 transition">
                  <span>💼</span>
                </a>
              </div>
            </div>
          </div>
          
          <div>
            <h3 className="text-2xl font-semibold text-gray-900 mb-6">Send a Message</h3>
            <form className="space-y-6">
              <div>
                <label htmlFor="name" className="block text-sm font-medium text-gray-700 mb-2">
                  Name
                </label>
                <input
                  type="text"
                  id="name"
                  className="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-indigo-500 focus:border-transparent"
                  placeholder="Your name"
                />
              </div>
              
              <div>
                <label htmlFor="email" className="block text-sm font-medium text-gray-700 mb-2">
                  Email
                </label>
                <input
                  type="email"
                  id="email"
                  className="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-indigo-500 focus:border-transparent"
                  placeholder="your@email.com"
                />
              </div>
              
              <div>
                <label htmlFor="message" className="block text-sm font-medium text-gray-700 mb-2">
                  Message
                </label>
                <textarea
                  id="message"
                  rows={4}
                  className="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-indigo-500 focus:border-transparent"
                  placeholder="Tell me about your project..."
                ></textarea>
              </div>
              
              <button
                type="submit"
                className="w-full bg-indigo-600 text-white py-3 px-6 rounded-lg text-lg hover:bg-indigo-500 transition"
              >
                Send Message
              </button>
            </form>
          </div>
        </div>
        
        <div className="text-center mt-16">
          <Link
            to="home"
            spy={true}
            smooth={true}
            offset={-80}
            duration={500}
            className="inline-flex items-center space-x-2 text-indigo-600 hover:text-indigo-500 transition cursor-pointer"
          >
            <span>↑</span>
            <span>Back to Top</span>
          </Link>
        </div>
      </div>
    </section>
  );
}

export default Contact;

 

 

 

7.App.jsx

마지막으로 진입 코드입니다. 

import Header from "./components/Header";
import Hero from "./components/Hero";
import About from "./components/About";
import Projects from "./components/Projects";
import Contact from "./components/Contact";

function App() {
  return (
    <>
      <Header />
      <Hero />
      <About />
      <Projects />
      <Contact />
    </>
  );
}

export default App;

 

 

 

결과물입니다. 

 

 

위처럼 부드럽게 화면이 넘어가는 효과를 간단하게 구현해보았습니다.

현재는 단순히 화면만 넘어가는 구조이지만, 상세 페이지를 연결해 포트폴리오 사이트에 활용할 수도 있습니다.