글 목록

많이 쓰는 스크롤 애니메이션 24가지, 직접 움직여 보며 이해하기

페이드인부터 스크롤 스파이까지, 자주 쓰는 스크롤 애니메이션 24가지를 이름별로 정리하고 글 안에서 바로 움직여 볼 수 있게 만들었습니다. 코드도 함께 볼 수 있습니다.

목차

    랜딩 페이지의 독창적인 스크롤 효과를 접할 때 명칭을 알지 못해 관련 정보 검색이나 AI 활용에 어려움을 겪는 경우가 많습니다. 이에 실무에서 빈번하게 활용되는 스크롤 애니메이션 24종을 명칭별로 분류하였으며, 본 게시물을 통해 각 효과를 직접 확인하고 경험하실 수 있도록 구성하였습니다.

    출현 효과 01–08

    해당 요소가 화면에 진입하는 시점에 1회 재생되는 효과입니다. 주로 IntersectionObserver를 통해 요소의 가시 여부를 감지하고, CSS transition을 활용하여 애니메이션을 구현합니다.

    01 페이드인 · Scroll-triggered fade-in

    해당 요소가 화면에 진입할 시, 하단에서 상단으로 부드럽게 부상하며 페이드인 효과가 적용됩니다.

    01 페이드인

    IntersectionObserver를 통해 뷰포트 진입 여부를 감지하여 is-visible 클래스를 부여하고, 요소의 애니메이션은 CSS transition(opacity 및 transform)으로 처리하는 방식을 권장합니다. 이는 scroll 이벤트를 매 프레임 감지하지 않아 성능 부하가 적으며, 랜딩 페이지나 블로그 카드 등 다양한 영역에 효과적으로 활용 가능합니다. 다만, JavaScript 실행 오류 시 요소가 노출되지 않을 위험이 있으므로, 초기 숨김 스타일은 JS가 활성화된 환경에서만 적용되도록 클래스(.js) 하위에 정의하는 것이 보다 안정적인 구현 방법입니다.

    02 슬라이드인 · Slide-in

    해당 요소가 좌우측 외부에서 슬라이드 형태로 진입합니다.

    02 슬라이드인

    각 방향별로 translateX 초기값만 차등 적용한 후, IntersectionObserver를 통해 요소가 화면에 진입하면 클래스를 부여하여 제자리(transform: none)로 복귀하도록 구현하십시오. 좌우를 번갈아 배치하면 타임라인이나 기능 소개 섹션에 시각적 리듬감을 더할 수 있습니다. 단, 이동 거리가 클 경우 가로 스크롤바가 발생할 수 있으므로 상위 요소에 overflow-x: clip 설정을 권장합니다.

    03 스태거 · Stagger animation

    카드 묶음이 일괄적으로 출력되지 않고 순차적으로 하나씩 나타나고 있습니다.

    03 스태거

    각 카드에 CSS 변수 --i로 순번을 지정하고, transition-delay: calc(var(--i) * 80ms)를 적용하여 지연 시간을 설정하시기 바랍니다. 그리드 전체가 뷰포트에 진입할 때 부모 요소에 클래스를 부여하는 방식이므로 코드가 간결해지는 장점이 있습니다. 다만, 항목이 많을 경우 지연 누적으로 인해 마지막 카드의 노출이 지연될 수 있으므로, 전체 소요 시간이 1초 내외가 되도록 간격을 조정하거나 상한선을 설정하는 방안을 권장합니다.

    04 텍스트 리빌 · Text reveal (split text)

    제목을 글자 단위로 분할하여 하단에서 순차적으로 나타나도록 구현해 주시기 바랍니다.

    04 텍스트 리빌

    JavaScript를 활용하여 문자열의 각 글자를 span 태그로 래핑한 뒤, 순차적인 지연 시간과 함께 overflow: hidden이 설정된 컨테이너 내부에서 translateY(100%)에서 0으로 이동하는 애니메이션을 구현할 수 있습니다. 이는 히어로 섹션의 강조 문구에 적합한 기법입니다. 다만, 텍스트 분할 시 스크린 리더가 글자 단위로 읽는 현상이 발생하므로, 전체 문장은 aria-label로 설정하고 각 span에는 aria-hidden="true"를 적용하여 접근성을 확보해야 합니다.

    05 마스크 리빌 · Clip-path reveal

    그림이 커튼이 걷히듯 clip-path로 한쪽부터 드러납니다.

    05 마스크 리빌

    clip-path: inset(0 100% 0 0)을 적용하여 우측을 완전히 차단한 후, 화면 진입 시 inset(0 0 0 0)으로 전환하여 좌측부터 노출되도록 구현합니다. 이미지 자체의 변형이나 위치 이동이 발생하지 않아 레이아웃 안정성이 높으며, 포트폴리오 썸네일이나 기사 대표 이미지 적용에 적합합니다. 보간 효과를 부드럽게 유지하기 위해서는 시작값과 종료값의 함수 형태(inset 간, 혹은 polygon의 꼭짓점 개수 등)를 동일하게 설정해야 한다는 점을 유의하십시오.

    06 블러인 · Blur-in reveal

    흐릿하던 요소가 초점이 맞듯 선명해지며 나타납니다.

    06 블러인

    filter: blur(12px) 및 opacity 0에서 시작하여 화면 진입 시 blur(0)·opacity 1로 전환되는 효과입니다. 사진이나 대형 타이포그래피에 몽환적인 연출을 더할 수 있으며, 이미지 지연 로딩 시 플레이스홀더 전환에도 활용 가능합니다. 단, blur 효과는 픽셀 단위의 재렌더링이 필요하므로 대형 요소에 다수 적용할 경우 저사양 기기에서 성능 저하가 발생할 수 있습니다. 따라서 요소의 개수와 크기를 고려하여 신중하게 사용하시기 바랍니다.

    07 타이프라이터 · Typewriter effect

    글자가 커서와 함께 한 글자씩 타이핑되듯 찍힙니다.

    07 타이프라이터

    setTimeout을 활용하여 일정 간격으로 문자열을 한 글자씩 출력하고, 커서 깜빡임 효과는 CSS keyframes를 통해 별도로 구현하는 방식을 제안합니다. 이는 히어로 섹션이나 터미널 스타일의 문구 연출에 적합합니다. 한글은 Array.from으로 분리할 경우 완성형 단위로 처리되어 이모지 등 서로게이트 문자열의 깨짐 현상을 방지할 수 있으며, 재시작 시 이전 타이머를 반드시 정리하여 텍스트 중첩 문제를 예방해야 합니다.

    08 카운트업 · Count-up animation

    숫자가 화면에 들어오면 0부터 목표값까지 부드럽게 올라갑니다.

    08 카운트업

    requestAnimationFrame을 통해 프레임별 경과 시간 비율(0~1)을 산출하고, easeOutCubic 등 이징 함수를 적용하여 현재 값을 도출한 뒤 toLocaleString('ko-KR')을 사용해 천 단위 쉼표를 표기합니다. 시간 기반으로 연산하므로 모니터 주사율과 무관하게 일정한 속도로 동작하며, 숫자 너비 변화에 따른 레이아웃 흔들림을 방지하기 위해 font-variant-numeric: tabular-nums 속성 적용을 권장합니다.

    스크롤에 연동되는 효과 09–16

    스크롤 기반의 인터랙션 구현 방식입니다. 스크롤 위치를 0에서 1 사이의 진행률로 변환하여 크기, 위치, 색상을 산출하는 원리입니다. 최신 브라우저의 CSS Scroll-driven Animation(animation-timeline)을 활용하면 자바스크립트 없이도 구현이 가능합니다.

    09 스크롤 연동 · Scroll-linked animation

    읽은 만큼 맨 위 진행 막대가 차오릅니다.

    09 스크롤 연동

    스크롤 위치(0~1)를 애니메이션 진행도에 동기화하는 방안입니다. CSS의 경우 animation-timeline: scroll(root) 속성을 활용하여 키프레임을 스크롤에 연동하고, 미지원 브라우저는 scrollY / (scrollHeight - innerHeight) 연산을 통해 scaleX 값을 도출합니다. 이는 읽기 진행률이나 단계 표시 UI 구현에 적합합니다. 성능 최적화를 위해 width 속성 변경 시 발생하는 레이아웃 재계산을 방지하도록 transform 속성 사용을 권장합니다.

    10 패럴랙스 · Parallax scrolling

    멀리 있는 층은 느리게, 가까운 층은 빠르게 움직여 깊이감을 만듭니다.

    10 패럴랙스

    여러 레이어를 중첩한 뒤, 각 레이어별로 상이한 가중치를 스크롤 진행률에 곱하여 translateY로 이동시키는 방식입니다. 원거리 배경에는 낮은 계수를 적용해 속도를 늦추고, 근거리 전경에는 높은 계수를 적용하여 속도감을 부여합니다. 이는 히어로 섹션이나 스토리텔링형 페이지 구현에 적합합니다. 다만 과도한 움직임은 사용자에게 피로감을 줄 수 있으므로, prefers-reduced-motion 설정 시 기능을 비활성화할 것을 권장합니다.

    11 스크롤 줌 · Scale on scroll

    작은 카드 속 이미지가 스크롤에 따라 화면 가득 커집니다.

    11 스크롤 줌

    sticky로 고정한 무대 안에서 진행률에 따라 scale과 border-radius를 보간합니다. 크기 변화는 width/height 대신 transform: scale로 처리해야 레이아웃 재계산 없이 부드럽습니다. 제품 소개나 섹션 전환의 '몰입' 연출에 쓰입니다. 확대된 요소 안의 글자도 같이 커지므로 텍스트는 별도 레이어로 두는 편이 좋습니다.

    12 이미지 시퀀스 · Scroll-scrubbed image sequence

    미리 그려 둔 60장의 프레임을 스크롤 위치로 넘겨 일출 장면을 재생합니다.

    12 이미지 시퀀스

    프레임 이미지를 사전에 로드하여(캔버스 60장 직접 렌더링) '진행률 × (전체 프레임 수 - 1)' 연산으로 도출된 프레임을 캔버스에 drawImage 방식으로 구현합니다. 이는 영상의 currentTime을 제어하는 방식보다 즉각적인 반응을 보이며 역재생 또한 매끄러워 제품 회전 연출에 효과적입니다. 실무 적용 시 프레임 수 증가에 따른 이미지 용량 부담이 발생하므로, 사전 로딩 최적화 및 해상도 조절이 구현의 핵심입니다.

    13 SVG 라인 드로잉 · SVG line drawing

    스크롤할수록 SVG 선이 펜으로 그리듯 이어집니다.

    13 SVG 라인 드로잉

    path의 전체 길이를 getTotalLength()로 구해 stroke-dasharray에 넣고, stroke-dashoffset을 길이 × (1 - 진행률)로 줄이면 선이 그려지는 것처럼 보입니다. 경로, 서명, 다이어그램 연출에 좋습니다. SVG를 viewBox로 늘리면 non-scaling-stroke 같은 설정에 따라 길이 계산이 어긋날 수 있으니 그 경우 pathLength="1"을 쓰면 간단합니다.

    14 텍스트 필 · Text fill on scroll

    읽는 속도에 맞춰 문단의 단어가 하나씩 진하게 채워집니다.

    14 텍스트 필

    문장을 단어 단위 span으로 나누고, 진행률 × 단어 수만큼 앞쪽 단어에 활성 클래스를 붙여 색을 채웁니다. 핵심 메시지를 천천히 읽히게 하는 랜딩 페이지에 자주 쓰입니다. 단어를 span으로 쪼개면 스크린 리더가 끊어 읽을 수 있으니 원문을 aria-label로 함께 두세요.

    15 배경색 전환 · Background color transition

    구역을 지날 때마다 페이지 배경색이 다음 구역의 색으로 섞여 바뀝니다.

    15 배경색 전환

    각 구역에 data-bg 색을 두고, 화면 중앙이 어느 두 구역 사이에 있는지 계산해 두 색을 선형 보간한 값을 body 배경에 넣습니다. 구역 경계가 딱 끊기지 않아 브랜드 스토리나 포트폴리오에 잘 어울립니다. 배경이 어두워질 때 글자색도 함께 바꾸지 않으면 대비가 무너지니 전경색도 같이 보간하세요.

    16 마키 · Marquee, scroll velocity

    끝없이 흐르는 글자 띠가 스크롤 속도만큼 빨라지고 방향에 따라 거꾸로 흐릅니다.

    16 마키

    requestAnimationFrame 루프에서 기본 속도에 '스크롤 변화량'을 더해 띠를 이동시키고, 위치를 띠 절반 폭으로 나눈 나머지로 감싸 끝없이 이어지게 합니다. 스크롤 방향이 바뀌면 부호를 뒤집어 흐름도 반대로 갑니다. 속도 값을 매 프레임 조금씩 감쇠시키지 않으면 멈춘 뒤에도 계속 빠르게 돌아가니 주의하세요.

    고정·넘기기·내비게이션 17–24

    화면 일부를 고정하거나, 한 화면씩 넘기거나, 지금 읽는 위치를 알려 주는 기법입니다. position: sticky와 scroll-snap 같은 CSS만으로 되는 것이 많습니다.

    17 스티키 · position: sticky

    섹션 제목이 자기 섹션을 지나는 동안 화면 위에 붙어 있습니다.

    17 스티키

    position: sticky는 평소엔 일반 요소처럼 흐르다가 지정한 top 값에 닿으면 부모 블록 안에서만 고정됩니다. 부모가 끝나면 다음 제목이 밀어내듯 교체되므로 목록 머리글, 표 헤더에 잘 맞습니다. JS가 전혀 필요 없습니다. 조상 요소에 overflow: hidden/auto가 있으면 그 요소가 스크롤 기준이 되어 sticky가 동작하지 않는 것처럼 보이니 주의하세요.

    18 핀 + 스크럽 · Pin + scrub

    무대는 화면에 고정되고, 스크롤한 만큼 안의 애니메이션이 앞뒤로 재생됩니다.

    18 핀 + 스크럽

    긴 래퍼(예: 300vh) 내부에 position: sticky 요소를 배치하면 해당 영역을 지나는 동안 고정(pin) 효과가 적용됩니다. 래퍼의 getBoundingClientRect().top 값을 활용해 0~1 사이의 진행도를 산출한 뒤 이를 transform 등에 직접 대입하면 스크롤바를 재생 헤드(scrub)처럼 제어할 수 있습니다. 이는 GSAP ScrollTrigger의 pin/scrub 원리와 동일하며, 스크롤 이벤트 시 requestAnimationFrame을 활용해 레이아웃 읽기를 단일화하여 성능을 최적화하시기 바랍니다. 래퍼 높이가 짧을 경우 애니메이션이 빠르게 종료될 수 있으므로, 콘텐츠 단계에 적합한 높이를 설정해 주십시오.

    19 스크롤리텔링 · Scrollytelling

    왼쪽 글 단계가 화면 가운데에 오면 오른쪽 고정 그래픽이 그 단계에 맞게 바뀝니다.

    19 스크롤리텔링

    그래픽 영역은 position: sticky 속성을 사용하여 고정하고, 각 콘텐츠 단계마다 IntersectionObserver를 적용하십시오. rootMargin을 '-50% 0px -50% 0px'로 설정하면 화면 중앙을 지나는 단일 단계만 활성화되어 별도의 스크롤 연산 없이 상태 전환이 가능합니다. 이는 데이터 저널리즘이나 제품 소개와 같이 설명과 시각 자료를 결합하는 구성에 효과적입니다. 단, 단계 간 간격이 너무 좁을 경우 상태가 빈번하게 전환될 수 있으므로, 각 단계에 충분한 높이를 확보하시기 바랍니다.

    20 카드 스택 · Stacking cards

    카드가 위에 붙으며 차곡차곡 쌓이고, 아래로 깔린 카드는 살짝 작아집니다.

    20 카드 스택

    각 카드에 position: sticky와 조금씩 다른 top 값을 주면 다음 카드가 이전 카드 위로 올라와 쌓입니다. 깊이감은 JS로 더합니다: 다음 카드가 얼마나 다가왔는지 비율을 구해 아래 카드에 scale을 줄입니다. 카드들은 한 부모 안에 형제로 있어야 하며, 부모 높이가 끝나면 스택 전체가 같이 올라갑니다. 카드마다 별도 래퍼로 감싸면 sticky 범위가 래퍼 안으로 줄어 쌓이지 않으니 주의하세요.

    21 스크롤 스냅 · CSS scroll snap

    한 번 스크롤하면 패널이 한 화면씩 딱 맞게 멈춥니다.

    21 스크롤 스냅

    스크롤 컨테이너에 scroll-snap-type: y mandatory, 각 패널에 scroll-snap-align: start를 주면 브라우저가 스크롤이 끝날 때 가장 가까운 패널에 맞춰 멈춥니다. JS 없이 풀페이지 섹션, 이미지 캐러셀을 만들 수 있고 터치·키보드도 그대로 동작합니다. mandatory는 패널이 화면보다 길면 안쪽 내용을 건너뛰게 만들 수 있으니, 긴 패널에는 proximity를 고려하세요. 점 표시만 JS로 현재 패널을 읽어 갱신했습니다.

    22 가로 스크롤 · Horizontal scroll

    세로로 스크롤하면 고정된 무대 안의 트랙이 옆으로 이동합니다.

    22 가로 스크롤

    핀 + 스크럽과 같은 구조입니다. 긴 래퍼 안의 sticky 무대에 가로 트랙을 두고, 진행도 p에 (트랙 너비 − 화면 너비)를 곱해 translateX로 밉니다. 래퍼 높이를 '가로 이동 거리 + 화면 높이'로 맞추면 세로 스크롤 속도와 가로 이동 속도가 같아 자연스럽습니다. 트랙에 overflow: hidden 대신 무대에 overflow: clip이나 hidden을 쓰되 sticky 요소 자신의 조상에는 걸지 않도록 주의하세요.

    23 숨는 헤더 · Hide-on-scroll header

    아래로 내리면 헤더가 숨고, 조금이라도 위로 올리면 다시 나타납니다.

    23 숨는 헤더

    스크롤 이벤트에서 이전 scrollY와 현재 값을 비교해 방향을 구하고, 아래 방향이면 헤더에 translateY(-100%)를 주는 클래스를 붙입니다. transform만 바꾸므로 레이아웃이 다시 계산되지 않아 부드럽습니다. 화면이 좁은 모바일에서 읽기 공간을 넓힐 때 좋습니다. 작은 흔들림에도 깜빡이지 않게 몇 픽셀 임계값을 두고, 맨 위 근처에서는 항상 보이게 하세요.

    24 스크롤 스파이 · Scrollspy

    옆 목차가 지금 읽고 있는 섹션을 따라 강조됩니다.

    24 스크롤 스파이

    각 본문 섹션에 IntersectionObserver를 적용하여, 화면 상단 기준(rootMargin '0px 0px -70% 0px')에 진입하는 섹션의 ID와 일치하는 목차 링크에 활성 클래스를 부여합니다. 목차는 position: sticky 속성을 활용해 측면에 고정하며, 이는 문서 및 블로그의 우측 목차 구현에 통용되는 방식입니다. 섹션의 길이가 짧아 감지 영역을 건너뛸 경우를 대비해, 마지막으로 진입한 섹션을 참조함으로써 활성 상태가 해제되는 현상을 방지하시기 바랍니다.

    AI에게 만들어 달라고 할 때

    이름과 함께 구현 방안을 구체적으로 명시해 주시면, 보다 정확하고 완성도 높은 결과물을 도출할 수 있습니다.

    • CSS만으로: "스크롤 진행률 바를 CSS animation-timeline만으로 만들어 줘"
    • GSAP ScrollTrigger로: "섹션을 핀 고정하고 스크럽으로 단계별 애니메이션을 만들어 줘"
    • Framer Motion으로: "카드가 스태거로 페이드인 되게 useInView로 만들어 줘"

    끝으로, 모션은 절제할수록 더욱 세련된 인상을 줍니다. 페이지당 애니메이션 효과를 2~3가지로 최소화하고, prefers-reduced-motion 설정을 활성화한 사용자에게는 움직임 없이 최종 상태만 노출하십시오. 본문의 데모 또한 이러한 원칙을 준수하여 제작되었습니다.

    댓글 0

    1. 댓글을 불러오는 중이에요.