테마 전환

Astro View Transitions: 코드 2줄로 웹사이트에 앱처럼 부드러운 전환 효과 구현하기

Easton editorial illustration: build pipeline conveyor

Astro로 블로그를 공들여 만들고 디자인과 레이아웃에도 신경 썼는데, 링크를 클릭할 때마다 페이지 전체가 하얗게 번쩍인 뒤에야 새 화면이 나타난다고 해 보겠습니다. iPhone의 부드러운 애니메이션을 보다가 갑자기 Windows 98의 딱딱한 화면 전환으로 넘어간 듯한 느낌입니다.

작년에 친구의 웹사이트를 만들어 주던 중, 친구가 다른 사람의 포트폴리오를 보고 물었습니다. “저 사이트는 프로젝트를 클릭하면 이미지가 부드럽게 커지면서 넘어가는데, 우리 사이트는 왜 화면이 딱 끊기며 새로고침되는 거야?” 저도 조금 난감했습니다. React SPA로 다시 만들어야 하나 싶었고, 그러면 Astro의 정적 생성 장점을 포기해야 하는 것 아닌가 걱정됐습니다.

그러다 View Transitions API와 Astro의 조합을 발견했습니다. 처음 사용했을 때는 정말 놀랐습니다. Layout 컴포넌트의 <head>에 코드 2줄만 추가했는데 페이지 전환이 곧바로 부드러운 애니메이션으로 바뀌었습니다. React도 Vue도 필요 없고 JavaScript 라이브러리조차 설치할 필요가 없었습니다.

이 글에서는 다음 내용을 차근차근 설명합니다.

  • View Transitions API란 무엇이며 2025년에 갑자기 주목받은 이유(브라우저 지원율 85% 이상)
  • Astro에서 페이지 전환을 활성화하는 3가지 방법(가장 간단한 코드 2줄부터 고급 사용자 정의까지)
  • 페이드 인·아웃, 슬라이드, 요소 모핑 등 다양한 효과를 구현하는 방법
  • 글 목록에서 상세 페이지로 부드럽게 넘어가는 전체 실전 예제
  • 자주 만나는 문제와 해결 방법(저도 모두 겪어 봤습니다)

Astro 사이트를 앱처럼 부드럽게 바꿀 준비가 되셨나요? 시작해 보겠습니다.

View Transitions API란 무엇이며 왜 유용한가요?

라이브러리가 필요 없는 브라우저 네이티브 ‘마법’

View Transitions API는 브라우저가 제공하는 네이티브 기능입니다. 간단히 말하면 브라우저에 “콘텐츠를 바꾸겠다”고 알리면 이전 페이지와 새 페이지의 ‘사진’을 각각 한 장씩 자동으로 캡처한 뒤 두 화면 사이의 부드러운 애니메이션을 생성합니다.

조금 추상적으로 들리나요? 블로그 홈에 ‘Astro 튜토리얼’이라는 글이 있고 클릭하면 상세 페이지로 이동한다고 가정해 보겠습니다. 기존 방식은 홈 화면 사라짐 → 흰 화면 → 상세 페이지 표시 순서입니다. View Transitions를 사용하면 브라우저가 홈과 상세 페이지의 제목을 ‘같은 요소’로 인식하고, 제목을 목록 위치에서 상세 페이지 상단으로 부드럽게 이동시키는 동안 나머지 콘텐츠를 페이드 인·아웃합니다.

가장 큰 장점은 브라우저가 이 애니메이션을 자동으로 만들어 준다는 것입니다. 복잡한 CSS 애니메이션을 작성하거나 GSAP, Framer Motion 같은 라이브러리를 도입할 필요가 없습니다.

React나 Vue 없이도 SPA 같은 효과를 만들 수 있는 이유

페이지 전환 애니메이션이라고 하면 많은 사람이 먼저 “React Router가 필요하지 않을까?” 또는 “Vue Router와 transition 컴포넌트를 함께 써야 하지 않을까?”라고 생각합니다. 하지만 이런 방식에는 공통적인 단점이 있습니다. 바로 무겁다는 점입니다.

기존 SPA 프레임워크로 페이지 전환을 구현하려면 다음과 같은 부담이 있습니다.

  • 애플리케이션 전체를 단일 페이지로 만들고 모든 라우팅을 JavaScript가 제어해야 합니다.
  • 번들 크기가 커지고 첫 화면 로딩이 느려집니다.
  • SEO를 별도로 처리해야 합니다(지금은 많이 개선되었습니다).

반면 Astro와 View Transitions의 조합은 훨씬 깔끔합니다.

  • 다중 페이지 아키텍처(MPA) 유지: 각 페이지가 독립된 HTML이므로 기본적으로 SEO에 유리합니다.
  • 필요할 때만 로드: 현재 페이지에 필요한 JS와 CSS만 로드합니다.
  • 네이티브 API: 성능 부담이 매우 작고 번들 크기를 늘리지 않습니다.
  • 점진적 향상: 지원하지 않는 브라우저에서는 기능에 영향 없이 일반 페이지 이동으로 자동 폴백됩니다.

예전에 같은 블로그 사이트로 테스트했을 때 React SPA 버전은 빌드 후 300KB 이상이었지만 Astro 버전은 약 50KB에 불과했습니다. View Transitions를 추가한 뒤에도 크기는 거의 변하지 않았습니다.

85%+
브라우저 지원율
2025년 View Transitions API 지원율
50KB vs 300KB
번들 크기 비교
Astro 버전은 React SPA보다 6배 작음
2줄
설정 코드
Layout 컴포넌트의 head에 <ViewTransitions /> 추가

2025년 브라우저 지원 현황: 안심하고 사용할 수 있습니다

좋은 소식이 있습니다. 2025년 기준 View Transitions API의 브라우저 지원율은 이미 85%를 넘었습니다.

구체적으로는 다음과 같습니다.

  • Chrome 111+: 동일 문서 전환 지원(한 페이지 안에서 상태 전환)
  • Chrome 126+: 문서 간 전환 지원(서로 다른 페이지 사이의 이동) — Astro에서 사용하는 방식입니다.
  • Safari: 지원
  • Edge: Chromium 기반으로 완전 지원
  • Firefox 144+(2025년 10월 출시): View Transitions는 Interop 2025의 핵심 프로젝트이며 Firefox도 마침내 지원합니다.

흥미롭게도 React 팀도 2025년에 View Transitions를 핵심 라이브러리에 통합했습니다(react@canary에서 지원). 이 API가 이미 프론트엔드의 ‘표준 기능’으로 자리 잡았다는 뜻입니다.

물론 지원하지 않는 나머지 15%의 브라우저가 걱정될 수 있습니다. 하지만 Astro가 자동으로 폴백을 처리하므로, 이런 브라우저에서는 애니메이션만 빠진 일반 페이지 이동으로 동작하고 기능에는 전혀 영향이 없습니다. 이것이 점진적 향상의 장점입니다.

Astro에서 View Transitions를 활성화하는 3가지 방법

이제 이론은 마치고 직접 적용해 보겠습니다. 가장 간단한 방법부터 시작하므로 읽고 바로 사용할 수 있습니다.

방법 1: 전역 활성화(가장 추천, 코드 2줄)

사이트 전체에 페이지 전환 효과를 적용하고 싶다면 이 방법이 가장 간단합니다. Layout 컴포넌트(일반적으로 src/layouts/BaseLayout.astro 또는 src/layouts/Layout.astro)를 열고 <head> 태그에 다음 두 줄을 추가합니다.


---

import { ViewTransitions } from 'astro:transitions';

---

<html>
  <head>
    <title>My Astro Site</title>
    <ViewTransitions />
  </head>
  <body>
    <slot />
  </body>
</html>

이게 전부입니다. 이제 개발 서버(npm run dev)를 시작하고 아무 링크나 클릭해 보세요. 페이지 전환이 부드러운 페이드 인·아웃 애니메이션으로 바뀐 것을 확인할 수 있습니다.

처음 사용했을 때는 효과가 너무 쉽게 나타나서 브라우저 캐시 때문인가 의심할 정도였습니다. 여러 번 새로고침해 확인해 보니 정말 이것만으로 충분했습니다.

적합한 상황: 블로그, 문서 사이트, 포트폴리오처럼 사이트 전체에 전환 효과가 필요한 경우

방법 2: 필요한 페이지에서만 활성화

경우에 따라 특정 페이지에만 전환 효과를 적용하고 싶을 수 있습니다. 예를 들어 홈과 소개 페이지에는 멋진 애니메이션이 필요하지만 관리자 페이지에는 필요하지 않을 수 있습니다. 이때는 개별 페이지의 <head>에 다음 코드를 추가합니다.


---

import { ClientRouter } from 'astro:transitions';

---

<html>
  <head>
    <title>About Page</title>
    <ClientRouter />
  </head>
  <body>
    <!-- 页面内容 -->
  </body>
</html>

참고로 ClientRouter는 새로운 이름이며 이전에는 ViewTransitions라고 불렸습니다. Astro 팀은 이 기능을 더 정확히 설명하기 위해 이름을 바꿨습니다. 단순히 뷰 전환만 수행하는 것이 아니라 페이지 내비게이션을 가로채 MPA를 ‘유사 SPA’로 바꾸기 때문입니다. 다만 예전 이름도 여전히 사용할 수 있으며 오류가 발생하지 않습니다.

적합한 상황: 일부 페이지에 특별한 처리가 필요한 하이브리드 애플리케이션

방법 3: 코드를 수정하지 않고 빠르게 효과 확인하기

프로젝트 코드를 건드리지 않고 효과만 빠르게 체험하고 싶다면 Astro 공식 Demo 사이트를 사용할 수 있습니다.

👉 View Transitions Demo

이 Demo에서는 목록에서 상세 페이지로 이동하기, 이미지 갤러리, 음악 플레이어 등 다양한 전환 효과를 보여 줍니다. 먼저 직접 사용해 보고 마음에 드는 효과를 찾은 뒤 프로젝트에 구현해 보는 것을 추천합니다.

안내: View Transitions를 지원하는 브라우저(Chrome 126+, Safari 또는 최신 Firefox)로 열어야 합니다.

정상 작동을 확인하는 3가지 신호

코드를 추가한 뒤 View Transitions가 활성화되었는지는 다음 신호로 확인할 수 있습니다.

  1. 페이지 전환 시 흰 화면이 더 이상 깜박이지 않음: 링크를 클릭하면 ‘흰 화면 → 새 페이지’처럼 튀지 않고 콘텐츠가 부드럽게 전환됩니다.
  2. 내비게이션 바 같은 공통 요소가 다시 렌더링되지 않음: 내비게이션 바가 사라졌다 다시 나타나지 않고 제자리에 유지됩니다(뒤에서 transition:persist를 설명합니다).
  3. 브라우저 콘솔에 오류가 없음: 오류가 있다면 Astro 버전이 너무 오래되었거나 설정에 문제가 있을 수 있습니다.

내비게이션 바가 처음으로 깜박이지 않는 모습을 봤을 때는 눈의 착각인가 싶었습니다. View Transitions를 끈 버전과 비교하고 나서야 실제로 적용된 것이 맞다는 걸 확인했습니다.

전환 애니메이션 사용자 정의하기: 브랜드 분위기에 맞는 효과

기본 페이드 인·아웃 효과는 깔끔하지만 때로는 더 개성 있는 애니메이션이 필요합니다. 여기서는 입문부터 고급 단계까지 4가지 사용자 정의 기법을 소개합니다.

기법 1: transition:animate로 애니메이션 유형 변경하기

Astro에는 transition:animate 지시어로 사용할 수 있는 4가지 애니메이션 효과가 내장되어 있습니다. 예를 들어 글 콘텐츠가 오른쪽에서 미끄러져 들어오게 하려면 다음과 같이 작성합니다.

<article transition:animate="slide">
  <h1>文章标题</h1>
  <p>文章内容...</p>
</article>

4가지 내장 애니메이션은 다음과 같습니다.

  1. fade(기본값): 가장 범용적인 페이드 인·아웃
  2. slide: 콘텐츠가 오른쪽에서 들어오는 슬라이드 효과로 글 상세 페이지에 적합
  3. initial: 브라우저 기본 스타일을 사용하며 사실상 애니메이션이 없는 것과 비슷함
  4. none: 애니메이션을 완전히 비활성화하며 전환이 필요 없는 요소에 적합

제가 가장 자주 사용하는 조합은 본문 콘텐츠에는 slide, 사이드바에는 fade를 적용하는 것입니다. 화면에 더 뚜렷한 깊이감이 생깁니다.

애니메이션 지속 시간도 조절할 수 있습니다. Astro는 fade()slide() 함수를 제공합니다.


---

import { fade, slide } from 'astro:transitions';

---

<article transition:animate={slide({ duration: '0.5s' })}>
  <!-- 滑动持续 0.5 秒 -->
</article>

<aside transition:animate={fade({ duration: '0.2s' })}>
  <!-- 淡入淡出持续 0.2 秒 -->
</aside>

기법 2: transition:name으로 요소 ‘모핑’하기

가장 흥미로운 기능입니다. transition:name은 브라우저에 “두 페이지의 이 요소는 사실 같은 것이므로 모핑 애니메이션으로 연결해 줘”라고 알려 줍니다.

대표적인 예는 글 목록에서 상세 페이지로 이동할 때의 제목 전환입니다.

목록 페이지(index.astro):

<ul>
  <li>
    <a href="/posts/astro-guide">
      <h2 transition:name="post-title-astro-guide">Astro 完全指南</h2>
    </a>
  </li>
</ul>

상세 페이지(posts/astro-guide.astro):

<article>
  <h1 transition:name="post-title-astro-guide">Astro 完全指南</h1>
  <p>文章内容...</p>
</article>

두 페이지의 제목에 모두 transition:name="post-title-astro-guide"가 사용된 것이 보이시나요? 목록 항목을 클릭하면 브라우저가 제목을 목록 위치에서 상세 페이지 상단으로 부드럽게 이동시키면서 글자 크기와 색상도 조정합니다.

중요: transition:name 값은 페이지마다 고유해야 합니다. 글이 여러 개라면 동적 값을 사용할 수 있습니다.

{posts.map(post => (
  <h2 transition:name={`post-title-${post.slug}`}>{post.title}</h2>
))}

이 기능을 처음 사용했을 때 제목이 상세 페이지 상단으로 ‘날아가는’ 모습을 보고 정말 최첨단 기술처럼 느껴졌습니다.

기법 3: transition:persist로 요소 상태 유지하기

페이지 전환 중에도 그대로 유지하고 싶은 요소가 있을 수 있습니다.

  • 페이지를 바꿔도 재생이 끊기지 않아야 하는 음악 플레이어
  • 다시 렌더링되지 않아야 하는 내비게이션 바
  • 수량 표시를 유지해야 하는 장바구니 아이콘

이때 transition:persist를 사용합니다.

<MusicPlayer client:load transition:persist />

다른 페이지로 이동해도 MusicPlayer 컴포넌트는 제거된 뒤 다시 만들어지지 않고 새 페이지로 그대로 ‘옮겨집니다’. 재생 위치 같은 내부 상태도 완전히 유지됩니다.

고급 활용: transition:persist-props 함께 사용하기

기본적으로 transition:persist는 내비게이션할 때 새 props로 컴포넌트를 다시 렌더링합니다. props조차 업데이트하지 않으려면(예: 내비게이션 바 검색창에 사용자가 입력한 내용을 지우고 싶지 않은 경우) transition:persist-props를 추가합니다.

<SearchBar
  client:load
  transition:persist
  transition:persist-props
/>

문서 사이트를 만들 때 이 기능을 사용해 본 적이 있는데 효과가 좋았습니다. 사용자가 검색어를 절반쯤 입력한 뒤 링크를 클릭해도 검색창 내용이 그대로 남아 사용자 경험이 확실히 좋아졌습니다.

기법 4: 애니메이션을 전역에서 제어하기

페이지 전체의 기본 애니메이션을 지정하고 싶다면 <html> 요소에 다음과 같이 설정합니다.

<html transition:animate="slide">
  <head>
    <ViewTransitions />
  </head>
  <body>
    <!-- 所有内容默认使用 slide 动画 -->
  </body>
</html>

그런 다음 하위 요소에서 필요한 만큼 덮어쓸 수 있습니다.

<nav transition:animate="fade">
  <!-- 导航栏单独用 fade -->
</nav>

<article>
  <!-- 文章使用继承的 slide -->
</article>

이런 계층형 제어 방식은 매우 유연하며 대규모 프로젝트에 적합합니다.

실전: 완성도 높은 블로그 전환 경험 만들기

이론과 기법을 살펴봤으니 이제 전체 실전 프로젝트를 만들어 보겠습니다. 블로그 홈에서 글 상세 페이지로 넘어가는 전환 효과입니다.

상황 설정

블로그 구조가 다음과 같다고 가정합니다.

  • : 각 글의 제목, 요약, 커버 이미지를 포함한 글 목록 표시
  • 상세 페이지: 제목, 커버 이미지, 본문을 포함한 전체 글 표시

구현할 효과는 다음과 같습니다.

  1. 글 제목을 클릭하면 제목이 상세 페이지 상단으로 부드럽게 이동(모핑 애니메이션)
  2. 커버 이미지에도 모핑 애니메이션 적용
  3. 나머지 콘텐츠는 페이드 인·아웃
  4. 내비게이션 바는 다시 렌더링되지 않고 상태 유지

단계 1: Layout에서 View Transitions 활성화하기

먼저 src/layouts/BaseLayout.astro에 ViewTransitions를 추가합니다.


---

import { ViewTransitions } from 'astro:transitions';

interface Props {
  title: string;
}

const { title } = Astro.props;

---

<!DOCTYPE html>
<html lang="zh-CN">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width" />
    <title>{title}</title>
    <ViewTransitions />
  </head>
  <body>
    <nav transition:persist transition:name="main-nav">
      <a href="/">首页</a>
      <a href="/about">关于</a>
    </nav>
    <main>
      <slot />
    </main>
  </body>
</html>

내비게이션 바에 transition:persisttransition:name="main-nav"를 추가했습니다. 따라서 페이지를 전환할 때 내비게이션 바가 깜박이지 않습니다.

단계 2: 글 목록 페이지에서 제목과 커버에 transition:name 추가하기

src/pages/index.astro에 다음과 같이 작성합니다.


---

import BaseLayout from '../layouts/BaseLayout.astro';

const posts = await Astro.glob('./posts/*.md');

---

<BaseLayout title="我的博客">
  <h1>最新文章</h1>
  <div class="post-list">
    {posts.map(post => (
      <article class="post-card">
        <a href={post.url}>
          <img
            src={post.frontmatter.cover}
            alt={post.frontmatter.title}
            transition:name={`cover-${post.frontmatter.slug}`}
          />
          <h2 transition:name={`title-${post.frontmatter.slug}`}>
            {post.frontmatter.title}
          </h2>
          <p>{post.frontmatter.excerpt}</p>
        </a>
      </article>
    ))}
  </div>
</BaseLayout>

핵심은 다음과 같습니다.

  • 커버 이미지에 transition:name={'cover-${post.frontmatter.slug}'} 사용
  • 제목에 transition:name={'title-${post.frontmatter.slug}'} 사용
  • 각 글의 transition name이 고유하도록 slug 사용

단계 3: 글 상세 페이지에 같은 transition:name 사용하기

글의 Markdown 템플릿(일반적으로 src/layouts/PostLayout.astro)에 다음과 같이 작성합니다.


---

import BaseLayout from './BaseLayout.astro';

const { frontmatter } = Astro.props;

---

<BaseLayout title={frontmatter.title}>
  <article class="post-detail">
    <img
      src={frontmatter.cover}
      alt={frontmatter.title}
      transition:name={`cover-${frontmatter.slug}`}
      class="cover-image"
    />
    <h1 transition:name={`title-${frontmatter.slug}`}>
      {frontmatter.title}
    </h1>
    <div class="post-meta">
      <time>{frontmatter.date}</time>
      <span>{frontmatter.author}</span>
    </div>
    <div class="post-content" transition:animate="slide">
      <slot />
    </div>
  </article>
</BaseLayout>

다음 사항에 주의하세요.

  • 커버와 제목의 transition:name은 목록 페이지와 같아야 합니다.
  • 본문 콘텐츠에는 transition:animate="slide"를 사용해 슬라이드 효과를 추가했습니다.

단계 4: 효과를 더 부드럽게 만드는 CSS 추가하기

Layout 또는 전역 스타일에 다음 코드를 추가합니다.

/* 优化过渡性能 */
[transition:name] {
  will-change: transform;
}

/* 封面图在列表和详情页的样式 */
.post-card img {
  width: 100%;
  height: 200px;
  object-fit: cover;
  border-radius: 8px;
}

.post-detail .cover-image {
  width: 100%;
  max-height: 400px;
  object-fit: cover;
  border-radius: 12px;
}

/* 标题样式 */
.post-card h2 {
  font-size: 1.5rem;
  color: #333;
}

.post-detail h1 {
  font-size: 2.5rem;
  color: #111;
  margin-top: 1rem;
}

will-change: transform은 매우 중요합니다. 이 요소에 변환 애니메이션이 적용될 것임을 브라우저에 알려 미리 최적화하도록 합니다.

단계 5: 효과 테스트하기

개발 서버를 시작합니다.

npm run dev

홈을 열고 아무 글 제목이나 클릭해 보세요. 다음과 같은 효과를 확인할 수 있습니다.

  1. 제목이 목록 위치에서 상세 페이지 상단으로 부드럽게 이동하며 글자 크기도 함께 변합니다.
  2. 커버 이미지도 함께 이동하면서 확대됩니다.
  3. 내비게이션 바는 전혀 움직이지 않고 깜박이지 않습니다.
  4. 요약과 게시일 같은 나머지 콘텐츠가 부드럽게 페이드 인됩니다.

이 효과를 처음 봤을 때 “바로 이거야”라는 만족감이 들었습니다. 기존 페이지 이동과 비교하면 사용자 경험이 크게 좋아집니다.

선택 사항: 로딩 상태 추가하기

글 콘텐츠가 크면 로딩이 지연될 수 있습니다. Astro는 로딩 상태를 위한 훅을 제공합니다.

<script>
  document.addEventListener('astro:before-preparation', () => {
    // 显示加载动画
    document.body.classList.add('loading');
  });

  document.addEventListener('astro:page-load', () => {
    // 隐藏加载动画
    document.body.classList.remove('loading');
  });
</script>

<style>
  body.loading::after {
    content: '';
    position: fixed;
    top: 50%;
    left: 50%;
    width: 40px;
    height: 40px;
    border: 4px solid #f3f3f3;
    border-top: 4px solid #3498db;
    border-radius: 50%;
    animation: spin 1s linear infinite;
  }

  @keyframes spin {
    0% { transform: rotate(0deg); }
    100% { transform: rotate(360deg); }
  }
</style>

이제 콘텐츠를 불러오는 동안 회전하는 로딩 아이콘이 표시되어 경험이 더 완성도 높아집니다.

고급 기법과 자주 발생하는 문제

기초와 실전 내용을 모두 살펴봤으니 이제 몇 가지 고급 기법과 직접 겪었던 문제 및 해결 방법을 공유하겠습니다.

고급 기법 1: 사용자의 ‘동작 줄이기’ 설정 존중하기

일부 사용자는 전정기관 장애(멀미)가 있거나 단순히 애니메이션을 선호하지 않아 시스템 설정에서 ‘동작 줄이기’를 켭니다. 개발자는 이 설정을 존중해야 합니다.

Astro와 브라우저가 자동으로 처리하지만 CSS에서 직접 제어할 수도 있습니다.

@media (prefers-reduced-motion: reduce) {
  * {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}

또는 Astro 컴포넌트에서 특정 애니메이션을 비활성화할 수 있습니다.

<div transition:animate={
  typeof window !== 'undefined' &&
  window.matchMedia('(prefers-reduced-motion: reduce)').matches
    ? 'none'
    : 'slide'
}>
  内容
</div>

솔직히 놓치기 쉬운 세부 사항이지만 일부 사용자에게는 정말 중요합니다.

고급 기법 2: 스크립트 생명주기 처리하기

기존 MPA에서는 페이지를 이동할 때마다 스크립트가 다시 실행됩니다. 하지만 View Transitions를 사용하면 내비게이션이 ‘유사 SPA’ 방식으로 바뀌어 스크립트 동작도 조금 달라집니다.

Astro는 다음과 같은 생명주기 이벤트를 제공합니다.

// 页面加载完成(包括首次加载和导航后)
document.addEventListener('astro:page-load', () => {
  console.log('页面内容已更新');
  // 重新初始化 UI 组件、绑定事件等
});

// 导航即将开始
document.addEventListener('astro:before-preparation', () => {
  console.log('即将导航到新页面');
  // 清理定时器、取消网络请求等
});

// 导航被取消(比如用户点击了返回按钮)
document.addEventListener('astro:after-swap', () => {
  console.log('DOM 已更新但动画还未完成');
});

자주 발생하는 문제: 스크립트에서 이벤트 리스너를 등록했다면 astro:before-preparation에서 정리해야 합니다. 그렇지 않으면 메모리 누수가 발생할 수 있습니다.

예전에 한 프로젝트에서 스크롤 리스너를 정리하지 않아 몇 차례 페이지를 이동한 뒤 화면이 버벅이기 시작했습니다. 정리 로직을 추가한 뒤에야 해결됐습니다.

고급 기법 3: 성능 최적화하기

View Transitions의 성능 부담은 작지만 애니메이션 요소가 너무 많거나 복잡하면 여전히 끊길 수 있습니다. 다음 방법으로 최적화할 수 있습니다.

  1. 동시에 전환하는 요소 수 제한: 모든 요소에 transition:name을 추가하지 말고 핵심 요소에만 사용합니다.
  2. will-change: transform 사용: 브라우저가 미리 최적화하도록 알립니다.
  3. 애니메이션 중 reflow 방지: 애니메이션 도중 레이아웃 속성(width, height, padding 등)을 수정하지 않습니다.
  4. 실제 기기에서 테스트: 개발 기기의 성능이 좋다고 해서 사용자 기기에서도 부드러운 것은 아닙니다.
/* 好的做法 */
.animated-element {
  will-change: transform, opacity;
  transform: translateX(0);
}

/* 不好的做法 */
.animated-element {
  width: 100px; /* 修改 width 会触发 reflow,性能差 */
}

자주 발생하는 문제 1: 애니메이션이 작동하지 않음

증상: transition:name을 추가했지만 페이지가 여전히 딱 끊겨 이동하고 애니메이션이 없습니다.

가능한 원인과 해결 방법:

  1. transition:name이 고유하지 않음: 같은 페이지에 중복된 name이 있는지 확인합니다.
  2. 두 페이지의 name이 일치하지 않음: 목록과 상세 페이지에서 같은 name을 사용하는지 확인합니다.
  3. 브라우저가 지원하지 않음: DevTools Console을 열어 오류가 있는지 확인합니다.
  4. Astro 버전이 너무 오래됨: Astro 3.0+로 업그레이드합니다(View Transitions는 3.0에서 도입).
# 检查 Astro 版本
npx astro --version

# 升级 Astro
npm install astro@latest

자주 발생하는 문제 2: 요소가 깜박이거나 튐

증상: 전환 도중 요소가 잠깐 깜박이거나 위치가 튑니다.

가능한 원인과 해결 방법:

  1. CSS 스타일이 일치하지 않음: 두 페이지에서 요소의 기본 스타일(display, position 등)이 같은지 확인합니다.
  2. 이미지 로딩이 완료되지 않음: 이미지에 loading="eager"를 추가하거나 고정 높이를 지정합니다.
  3. transition:persist를 사용하지 않음: 내비게이션 바나 플레이어처럼 상태를 유지해야 하는 요소에 transition:persist를 추가합니다.
<!-- 解决图片闪烁 -->
<img
  src={cover}
  loading="eager"
  style="height: 200px"
  transition:name="cover"
/>

자주 발생하는 문제 3: 뒤로 버튼의 애니메이션 방향이 잘못됨

증상: 앞으로 이동할 때는 애니메이션 방향이 정상이지만 뒤로 버튼을 눌러도 계속 오른쪽에서 왼쪽으로 움직입니다.

해결 방법: Astro가 앞으로/뒤로 이동의 애니메이션 방향을 자동으로 처리하지만 사용자 정의 애니메이션을 사용했다면 직접 처리해야 할 수 있습니다.

document.addEventListener('astro:before-preparation', (event) => {
  const isBack = event.direction === 'back';
  if (isBack) {
    // 调整动画方向
    document.documentElement.classList.add('reverse-animation');
  }
});
.reverse-animation [transition:animate="slide"] {
  animation-direction: reverse;
}

자주 발생하는 문제 4: 서드파티 스크립트와 충돌함

증상: View Transitions를 추가한 뒤 Google Analytics나 광고 스크립트 같은 서드파티 도구가 작동하지 않습니다.

원인: 이런 스크립트는 일반적으로 페이지 로딩 시 한 번 실행됩니다. 하지만 View Transitions는 내비게이션을 ‘가로채므로’ 서드파티 스크립트가 페이지 변경을 알지 못합니다.

해결 방법: astro:page-load 이벤트에서 서드파티 스크립트를 다시 실행합니다.

document.addEventListener('astro:page-load', () => {
  // Google Analytics
  if (typeof gtag !== 'undefined') {
    gtag('config', 'GA_MEASUREMENT_ID', {
      page_path: window.location.pathname,
    });
  }

  // Facebook Pixel
  if (typeof fbq !== 'undefined') {
    fbq('track', 'PageView');
  }
});

이 문제도 직접 겪었습니다. View Transitions를 추가한 뒤 GA 통계가 정확하지 않다는 걸 발견하고서야 직접 다시 실행해야 한다는 사실을 알게 됐습니다.

호환성과 점진적 향상

마지막으로 한 가지를 기억하세요. View Transitions의 지원율은 이미 85% 이상이지만 여전히 지원하지 않는 브라우저가 있습니다. 다행히 Astro가 자동으로 폴백하므로 이런 브라우저에서는 애니메이션만 빠진 일반 페이지 이동으로 동작하고 기능은 정상적으로 유지됩니다.

브라우저 지원 여부를 직접 확인하려면 다음 코드를 사용할 수 있습니다.

if (document.startViewTransition) {
  console.log('浏览器支持 View Transitions');
} else {
  console.log('浏览器不支持,已自动降级');
}

이것이 점진적 향상의 장점입니다. 최신 브라우저는 부드러운 경험을 제공하고 오래된 브라우저에서도 기능은 망가지지 않습니다.

결론

지금까지의 내용을 정리해 보겠습니다.

View Transitions API + Astro는 가장 간단한 페이지 전환 솔루션입니다. React도 Vue도 서드파티 라이브러리도 필요하지 않습니다. Layout 컴포넌트의 <head>에 코드 2줄만 추가하면 Astro 사이트에 앱처럼 부드러운 경험을 제공할 수 있습니다.

기본 페이드 인·아웃부터 사용자 정의 슬라이드 효과, 요소 모핑 애니메이션, 상태 유지까지 차근차근 적용해 딱딱한 다중 페이지 사이트를 부드러운 현대적 웹 애플리케이션으로 바꿨습니다. 더 중요한 점은 모든 기능이 네이티브 API를 기반으로 하므로 성능 부담이 매우 작고 오래된 브라우저에서는 자동으로 폴백된다는 것입니다.

지금 바로 사용해 보고 싶다면 다음 순서를 추천합니다.

  1. 가장 간단한 방법부터 시작: Layout에 <ViewTransitions />를 추가하고 기본 효과를 확인합니다.
  2. 인상적인 지점 찾기: 내비게이션 바의 깜박임 제거일 수도 있고 제목 모핑일 수도 있습니다.
  3. 필요한 만큼 조정: 사이트 분위기에 맞게 transition:animatetransition:name으로 효과를 조정합니다.
  4. 실제 환경에서 테스트: 여러 브라우저와 기기에서 효과를 검증합니다.

솔직히 이제는 새 프로젝트를 시작할 때마다 View Transitions를 가장 먼저 추가합니다. 정말 간단한데 효과는 놀라울 정도로 좋기 때문입니다. 때로는 좋은 사용자 경험을 만드는 데 복잡한 코드가 필요한 것이 아니라 올바른 도구를 고르는 일이 더 중요합니다.

구현 중 문제가 생기면 다음 방법을 확인해 보세요.

마지막으로 View Transitions로 멋진 효과를 만들었다면 댓글에 사이트 링크를 공유해 주세요. 여러분이 어떤 아이디어를 구현했는지 정말 보고 싶습니다.

이제 Astro 프로젝트를 열고 사이트를 더 부드럽게 바꿔 보세요!

Astro View Transitions 전체 설정 과정

코드 2줄로 웹사이트에 앱처럼 부드러운 경험을 더하는 방법을 기초 설정부터 고급 사용자 정의까지 실전 예제와 함께 설명합니다.

⏱️ Estimated time: 15 min

  1. 1

    Step 1: View Transitions API와 브라우저 지원 현황 이해하기

    View Transitions API란 무엇인가요?
    • 브라우저가 제공하는 네이티브 기능입니다.
    • 간단히 말하면 브라우저에 ‘콘텐츠를 바꾸겠다’고 알리는 방식입니다.
    • 브라우저가 이전 페이지와 새 페이지의 ‘사진’을 각각 한 장씩 자동으로 캡처합니다.
    • 그런 다음 이전 화면에서 새 화면으로 이어지는 부드러운 애니메이션을 자동 생성합니다.
    • 가장 큰 장점은 이 애니메이션을 브라우저가 자동으로 만들어 준다는 점입니다.
    • 복잡한 CSS 애니메이션을 작성하거나 GSAP, Framer Motion 같은 라이브러리를 도입할 필요가 없습니다.

    2025년 브라우저 지원율은 85%를 넘습니다.
    • Chrome 111+: 동일 문서 전환 지원(한 페이지 안에서 상태 전환)
    • Chrome 126+: 문서 간 전환 지원(서로 다른 페이지 사이의 이동으로, Astro에서 사용하는 방식)
    • Safari: 지원
    • Edge: Chromium 기반으로 완전 지원
    • Firefox 144+: 지원(View Transitions는 Interop 2025의 핵심 프로젝트)

    흥미롭게도 React 팀도 2025년에 View Transitions를 핵심 라이브러리에 통합했습니다(react@canary에서 지원). 이 API가 이미 프론트엔드의 ‘표준 기능’으로 자리 잡았다는 뜻입니다.

    호환성 처리:
    • Astro가 자동으로 폴백을 처리합니다.
    • 지원하지 않는 브라우저에서는 일반 페이지 이동으로 동작합니다.
    • 애니메이션만 없을 뿐 기능에는 전혀 영향이 없습니다.
    • 이것이 점진적 향상의 장점입니다.
  2. 2

    Step 2: Astro와 View Transitions 조합의 장점

    React나 Vue 없이도 SPA 같은 효과를 만들 수 있는 이유는 무엇일까요?

    기존 SPA 프레임워크의 문제점:
    • 애플리케이션 전체를 단일 페이지로 만들어야 합니다.
    • 모든 라우팅을 JavaScript가 제어합니다.
    • 번들 크기가 커지고 첫 화면 로딩이 느려집니다.
    • SEO를 별도로 처리해야 합니다.

    Astro와 View Transitions 조합의 장점:
    • 다중 페이지 아키텍처(MPA)를 유지합니다. 각 페이지가 독립된 HTML이므로 기본적으로 SEO에 유리합니다.
    • 현재 페이지에 필요한 JS와 CSS만 필요할 때 로드합니다.
    • 네이티브 API라 성능 부담이 매우 작고 번들 크기를 늘리지 않습니다.
    • 점진적 향상을 지원해 미지원 브라우저에서는 기능에 영향 없이 일반 페이지 이동으로 자동 폴백됩니다.

    성능 비교:
    • 예전에 같은 블로그 사이트로 테스트해 본 적이 있습니다.
    • React SPA 버전은 빌드 후 300KB 이상이었습니다.
    • Astro 버전은 약 50KB에 불과했습니다.
    • View Transitions를 추가한 뒤에도 크기는 거의 변하지 않았습니다.
  3. 3

    Step 3: 활성화하는 3가지 방법: 가장 간단한 방법부터 고급 사용자 정의까지

    방법 1: 가장 간단한 방법
    • Layout 컴포넌트의 <head>에 <ViewTransitions />를 추가합니다.
    • 코드 2줄이면 충분합니다.
    • 페이지 전환이 즉시 부드러운 애니메이션으로 바뀝니다.
    • React도 Vue도 필요 없고 JavaScript 라이브러리조차 설치할 필요가 없습니다.

    방법 2: 전환 효과 사용자 정의
    • transition:animate 속성으로 애니메이션 유형을 제어합니다.
    - fade: 페이드 인·아웃
    - slide: 슬라이드
    - none: 애니메이션 없음
    • transition:name 속성으로 요소에 이름을 지정합니다.
    • 브라우저가 목록 페이지와 상세 페이지의 제목을 ‘같은 요소’로 인식하게 합니다.
    • 그러면 제목이 목록 위치에서 상세 페이지 상단으로 부드럽게 이동합니다.

    방법 3: 고급 활용
    • 요소 모핑 애니메이션: 목록의 썸네일을 상세 페이지의 큰 이미지로 부드럽게 확대합니다.
    • 상태 유지: 페이지 전환 중 스크롤 위치나 폼 입력 등의 상태를 유지합니다.
    • 애니메이션 지속 시간과 이징 함수를 사용자 정의합니다.
  4. 4

    Step 4: 실전 예제: 글 목록에서 상세 페이지로 부드럽게 전환하기

    전체 실전 예제:

    상황:
    • 블로그 홈에 ‘Astro 튜토리얼’이라는 글 제목이 있다고 가정합니다.
    • 클릭하면 글 상세 페이지로 이동합니다.

    기존 페이지 이동:
    • 홈 화면 사라짐 → 흰 화면 → 상세 페이지 표시

    View Transitions 적용 후:
    • 브라우저가 홈과 상세 페이지의 제목을 ‘같은 요소’로 인식합니다.
    • 제목을 목록 위치에서 상세 페이지 상단으로 부드럽게 이동시킵니다.
    • 동시에 나머지 콘텐츠는 페이드 인·아웃됩니다.

    설정 단계:
    1. Layout 컴포넌트의 head에 <ViewTransitions />를 추가합니다.
    2. 글 제목에 transition:name 속성을 추가합니다(예: transition:name="article-title").
    3. 선택 사항: transition:animate="slide"로 슬라이드 효과를 추가합니다.
    4. 여러 브라우저와 기기에서 효과를 테스트합니다.

    결과:
    • 내비게이션 바가 깜박이지 않습니다.
    • 제목에 모핑 애니메이션이 적용됩니다.
    • 이미지가 부드럽게 전환됩니다.
    • 딱딱한 페이지 이동이 앱처럼 부드러운 사용자 경험으로 바뀝니다.
  5. 5

    Step 5: 자주 발생하는 문제와 모범 사례

    자주 발생하는 문제: 1) 애니메이션이 작동하지 않음(브라우저 지원 여부와 콘솔 오류 확인), 2) 요소 모핑이 부자연스러움(transition:name 속성값이 같은지, 요소 구조가 비슷한지 확인), 3) 성능 문제(View Transitions는 네이티브 API라 성능 부담이 매우 작지만 페이지 요소가 너무 많으면 영향을 줄 수 있으므로 핵심 요소에만 적용 권장). 모범 사례: 먼저 가장 간단한 방법(Layout에 <ViewTransitions /> 추가)으로 기본 효과를 확인하고, 내비게이션 바의 깜박임 제거 또는 제목 모핑처럼 인상적인 지점을 찾은 뒤, 사이트 분위기에 맞게 transition:animate와 transition:name으로 필요한 만큼 조정하고 여러 브라우저와 기기의 실제 환경에서 검증합니다. 호환성 안내: View Transitions의 지원율은 이미 85% 이상이지만 여전히 지원하지 않는 브라우저가 있습니다. Astro는 이런 환경에서 일반 페이지 이동으로 자동 폴백하므로 기능은 정상적으로 작동합니다.

FAQ

View Transitions API란 무엇이며 왜 유용한가요?
View Transitions API는 브라우저가 제공하는 네이티브 기능입니다. 간단히 말하면 브라우저에 ‘콘텐츠를 바꾸겠다’고 알리면 이전 페이지와 새 페이지의 ‘사진’을 각각 한 장씩 자동으로 캡처한 뒤 두 화면 사이의 부드러운 애니메이션을 생성합니다.

가장 큰 장점은 브라우저가 애니메이션을 자동으로 만들어 준다는 점입니다. 복잡한 CSS 애니메이션을 작성하거나 GSAP, Framer Motion 같은 라이브러리를 도입할 필요가 없습니다.

예를 들어 블로그 홈에 ‘Astro 튜토리얼’이라는 글이 있고 클릭하면 상세 페이지로 이동한다고 가정해 보겠습니다.
• 기존 방식: 홈 화면 사라짐 → 흰 화면 → 상세 페이지 표시
• View Transitions 적용 후 브라우저는 홈과 상세 페이지의 제목을 ‘같은 요소’로 인식합니다.
• 제목은 목록 위치에서 상세 페이지 상단으로 부드럽게 이동하고 나머지 콘텐츠는 페이드 인·아웃됩니다.
2025년 브라우저 지원 현황은 어떤가요? 안심하고 사용해도 되나요?
2025년 브라우저 지원율은 85%를 넘습니다.
• Chrome 111+: 동일 문서 전환 지원(한 페이지 안에서 상태 전환)
• Chrome 126+: 문서 간 전환 지원(서로 다른 페이지 사이의 이동으로, Astro에서 사용하는 방식)
• Safari: 지원
• Edge: Chromium 기반으로 완전 지원
• Firefox 144+: 지원(View Transitions는 Interop 2025의 핵심 프로젝트이며 Firefox도 마침내 지원)

흥미롭게도 React 팀도 2025년에 View Transitions를 핵심 라이브러리에 통합했습니다(react@canary에서 지원). 이 API가 프론트엔드의 ‘표준 기능’이 되었다는 뜻입니다.

물론 지원하지 않는 나머지 15%의 브라우저가 걱정될 수 있습니다. Astro가 자동으로 폴백을 처리하므로 이런 브라우저에서는 애니메이션만 빠진 일반 페이지 이동으로 동작하고 기능에는 전혀 영향이 없습니다. 이것이 점진적 향상의 장점입니다.
React나 Vue 없이도 SPA 같은 효과를 만들 수 있는 이유는 무엇인가요?
기존 SPA 프레임워크로 페이지 전환을 구현하려면 다음과 같은 부담이 있습니다.
• 애플리케이션 전체를 단일 페이지로 만들고 모든 라우팅을 JavaScript가 제어해야 합니다.
• 번들 크기가 커지고 첫 화면 로딩이 느려집니다.
• SEO를 별도로 처리해야 합니다(지금은 많이 개선되었습니다).

반면 Astro와 View Transitions의 조합은 훨씬 깔끔합니다.
• 다중 페이지 아키텍처(MPA)를 유지합니다. 각 페이지가 독립된 HTML이므로 기본적으로 SEO에 유리합니다.
• 현재 페이지에 필요한 JS와 CSS만 필요할 때 로드합니다.
• 네이티브 API라 성능 부담이 매우 작고 번들 크기를 늘리지 않습니다.
• 점진적 향상을 지원해 미지원 브라우저에서는 기능에 영향 없이 일반 페이지 이동으로 자동 폴백됩니다.

예전에 같은 블로그 사이트로 테스트했을 때 React SPA 버전은 빌드 후 300KB 이상이었지만 Astro 버전은 약 50KB에 불과했고, View Transitions를 추가한 뒤에도 크기는 거의 변하지 않았습니다.
Astro에서 View Transitions를 활성화하는 방법은 몇 가지인가요?
방법 1은 가장 간단합니다.
• Layout 컴포넌트의 <head>에 <ViewTransitions />를 추가합니다.
• 코드 2줄이면 페이지 전환이 즉시 부드러운 애니메이션으로 바뀝니다.
• React도 Vue도 필요 없고 JavaScript 라이브러리조차 설치할 필요가 없습니다.

방법 2는 전환 효과를 사용자 정의합니다.
• transition:animate 속성으로 애니메이션 유형을 제어합니다(fade는 페이드 인·아웃, slide는 슬라이드, none은 애니메이션 없음).
• transition:name 속성으로 요소에 이름을 지정해 브라우저가 홈과 상세 페이지의 제목을 ‘같은 요소’로 인식하게 합니다.
• 그러면 제목이 목록 위치에서 상세 페이지 상단으로 부드럽게 이동합니다.

방법 3은 고급 활용입니다.
• 요소 모핑 애니메이션(목록의 썸네일을 상세 페이지의 큰 이미지로 부드럽게 확대)
• 상태 유지(페이지 전환 중 스크롤 위치나 폼 입력 등의 상태 유지)
• 애니메이션 지속 시간과 이징 함수 사용자 정의
글 목록에서 상세 페이지로 부드럽게 전환하려면 어떻게 해야 하나요?
블로그 홈에 ‘Astro 튜토리얼’이라는 글 제목이 있고 클릭하면 상세 페이지로 이동한다고 가정해 보겠습니다.
• 기존 방식: 홈 화면 사라짐 → 흰 화면 → 상세 페이지 표시
• View Transitions 적용 후 브라우저는 홈과 상세 페이지의 제목을 ‘같은 요소’로 인식합니다.
• 제목은 목록 위치에서 상세 페이지 상단으로 부드럽게 이동하고 나머지 콘텐츠는 페이드 인·아웃됩니다.

설정 단계:
1) Layout 컴포넌트의 head에 <ViewTransitions />를 추가합니다.
2) 글 제목에 transition:name 속성을 추가합니다(예: transition:name="article-title").
3) 선택 사항: transition:animate="slide"로 슬라이드 효과를 추가합니다.
4) 여러 브라우저와 기기에서 효과를 테스트합니다.

결과:
• 내비게이션 바가 깜박이지 않습니다.
• 제목에 모핑 애니메이션이 적용됩니다.
• 이미지가 부드럽게 전환됩니다.
• 딱딱한 페이지 이동이 앱처럼 부드러운 사용자 경험으로 바뀝니다.
View Transitions 사용 시 자주 발생하는 문제와 모범 사례는 무엇인가요?
자주 발생하는 문제:
1) 애니메이션이 작동하지 않음:
• 브라우저 지원 여부를 확인합니다.
• 콘솔에 오류가 있는지 확인합니다.

2) 요소 모핑이 부자연스러움:
• transition:name 속성값이 같은지 확인합니다.
• 요소 구조가 비슷한지 확인합니다.

3) 성능 문제:
• View Transitions는 네이티브 API라 성능 부담이 매우 작습니다.
• 다만 페이지 요소가 너무 많으면 성능에 영향을 줄 수 있으므로 핵심 요소에만 사용하는 것이 좋습니다.

모범 사례:
• 먼저 가장 간단한 방법(Layout에 <ViewTransitions /> 추가)으로 기본 효과를 확인합니다.
• 내비게이션 바의 깜박임 제거 또는 제목 모핑처럼 인상적인 지점을 찾습니다.
• 사이트 분위기에 맞게 transition:animate와 transition:name으로 필요한 만큼 조정합니다.
• 여러 브라우저와 기기의 실제 환경에서 검증합니다.

호환성 안내: View Transitions의 지원율은 이미 85% 이상이지만 여전히 지원하지 않는 브라우저가 있습니다. Astro는 이런 환경에서 일반 페이지 이동으로 자동 폴백하므로 기능은 정상적으로 작동합니다. 브라우저 지원 여부를 직접 확인하려면 if (document.startViewTransition)을 사용할 수 있습니다.

5분 읽기 · 게시일: 2025년 12월 2일 · 수정일: 2026년 9월 8일

댓글

GitHub로 로그인하여 댓글을 남기세요

Easton BlogEaston Blog