copyright © 2026 | creaml4tt3 personal website.

Home/Blogs/Next.js View Transitions ใช้ยังไง? พร้อมตัวอย่างจริง

Next.js View Transitions ใช้ยังไง? พร้อมตัวอย่างจริง

03 May 2026 15:3019 days ago
Next.js View Transitions ใช้ยังไง? พร้อมตัวอย่างจริง

🚀 ทำให้ Next.js ลื่นเหมือน Native App ด้วย View Transitions

หนึ่งใน pain หลักของเว็บยุคนี้คือ “การเปลี่ยนหน้าแล้วรู้สึกกระตุก” แม้จะใช้ SPA หรือ Next.js แล้ว UX ก็ยังไม่ smooth เท่ากับ native mobile app

ตอนนี้ Next.js + React มี feature ใหม่ที่ช่วยแก้ปัญหานี้ตรง ๆ คือ View Transitions API ✨

มันช่วยให้:

  • เปลี่ยนหน้าได้ลื่นขึ้น

  • ทำ shared element transition ได้ง่าย

  • ใช้แค่ CSS + React component

  • ไม่ต้องพึ่ง animation library หนัก ๆ


⚙️ เปิดใช้งาน View Transitions ใน Next.js

เริ่มจากเปิด experimental feature ใน

1
next.config.ts
1
import type { NextConfig } from 'next';
2
3
const nextConfig: NextConfig = {
4
experimental: {
5
viewTransition: true,
6
},
7
};
8
9
export default nextConfig;

⚠️ ตอนนี้ยังเป็น experimental แต่ใช้งานได้จริงแล้ว


🌍 ใช้งาน Route Transition แบบ Global

หลายคนเริ่มจากใส่ใน layout.tsx แต่จริง ๆ ถ้าต้องการให้ transition ทำงานถูกต้องกับ App Router ควรใช้ template.tsx

เพราะ:

  • layout.tsx จะ persist ระหว่าง route

  • template.tsx จะ remount ทุกครั้งที่เปลี่ยนหน้า

  • เหมาะกับ route transition มากกว่า

📌

1
template.tsx
1
import { ViewTransition } from 'react';
2
3
interface TemplateProps {
4
children: React.ReactNode;
5
}
6
7
const Template: React.FC<TemplateProps> = ({ children }) => {
8
return (
9
<ViewTransition default="page-transition">
10
{children}
11
</ViewTransition>
12
);
13
};
14
15
export default Template;

🎨 สร้าง Animation ด้วย CSS

ใน

1
globals.css
1
::view-transition-group(.page-transition) {
2
animation-duration: 500ms;
3
}
4
5
::view-transition-old(.page-transition) {
6
animation: page-out 500ms ease;
7
}
8
9
::view-transition-new(.page-transition) {
10
animation: page-in 500ms ease;
11
}
12
13
@keyframes page-out {
14
from {
15
opacity: 1;
16
transform: scale(1);
17
filter: blur(0);
18
}
19
20
to {
21
opacity: 0;
22
transform: scale(0.98);
23
filter: blur(8px);
24
}
25
}
26
27
@keyframes page-in {
28
from {
29
opacity: 0;
30
transform: scale(0.98);
31
filter: blur(8px);
32
}
33
34
to {
35
opacity: 1;
36
transform: scale(1);
37
filter: blur(0);
38
}
39
}

👉 ทุกครั้งที่เปลี่ยน route จะรู้สึกลื่นขึ้นทันที เหมือน native app มากกว่าเดิมเยอะ


🧠 Shared Element Transition คือของจริง

จุดที่ View Transitions powerful จริง ๆ ไม่ใช่แค่ page fade

แต่มันคือ: “element เดียวกัน animate ข้ามหน้า”

เช่น:

  • blog card → blog detail

  • image thumbnail → hero image

  • title → expanded title

สิ่งนี้ทำให้ UX ดู premium มาก


🖼️ ตัวอย่าง: Blog Card → Blog Detail

📌 ฝั่ง Blog Card

1
import { ViewTransition } from 'react';
1
<ViewTransition
2
name={`blog-image-${item.fields.slug}`}
3
share="blog-image"
4
default="none"
5
>
6
<div className="blog-image-container w-full overflow-hidden">
7
{thumbnail && (
8
<Image
9
key={thumbnail.url}
10
src={thumbnail.url}
11
alt={item.fields.title}
12
width={thumbnail.width}
13
height={thumbnail.height}
14
className="blog-image max-h-[30vmin] object-cover group-hover/blog:scale-110 transition-transform duration-500"
15
/>
16
)}
17
</div>
18
</ViewTransition>

📌 ฝั่ง Blog Detail Page

1
import { ViewTransition } from 'react';
1
<ViewTransition
2
name={`blog-image-${blog.fields.slug}`}
3
share="blog-image"
4
default="none"
5
>
6
<Image
7
src={thumbnail?.url}
8
alt={blog.fields.title}
9
width={thumbnail?.width}
10
height={thumbnail?.height}
11
preload
12
sizes="(max-width: 1024px) 100vw, 1024px"
13
fetchPriority="high"
14
loading="eager"
15
className="blog-thumbnail object-cover"
16
/>
17
</ViewTransition>

📝 Shared Title Transition

นอกจาก image ยัง animate title ได้ด้วย

1
import { ViewTransition } from 'react';
1
<ViewTransition
2
name={`blog-title-${blog.fields.slug}`}
3
share="blog-title"
4
default="none"
5
>
6
<h1
7
className="blog-title text-balance font-bold font-noto-sans-thai-looped text-3xl"
8
style={{
9
viewTransitionName: `blog-title-${blog.fields.slug}`,
10
viewTransitionClass: 'blog-title',
11
}}
12
>
13
{blog.fields.title}
14
</h1>
15
</ViewTransition>

👉 สิ่งสำคัญที่สุดคือ:

name

ต้องตรงกันระหว่างสองหน้า

เช่น:

1
name={`blog-image-${slug}`}

เพราะ browser จะใช้ชื่อนี้ในการจับคู่ element เดิมกับ element ใหม่


🎨 Animation สำหรับ Shared Element

1
::view-transition-group(.blog-image) {
2
animation-duration: 700ms;
3
}
4
5
::view-transition-image-pair(.blog-image) {
6
overflow: hidden;
7
border-radius: 24px;
8
}
9
10
::view-transition-new(.blog-image) {
11
animation: scale-in 700ms ease;
12
}
13
14
@keyframes scale-in {
15
from {
16
transform: scale(0.95);
17
opacity: 0;
18
}
19
20
to {
21
transform: scale(1);
22
opacity: 1;
23
}
24
}

📌 จุดที่หลายคนไม่รู้คือ:

1
::view-transition-image-pair()

ช่วยแก้ปัญหา image stretch และ clipping ระหว่าง morph animation ได้ดีมาก


⚡ Performance Tips (สำคัญมาก)

ถ้าอยากให้ smooth จริงแบบ production:

✅ ใช้

1
loading="eager"

กับ element สำคัญ ✅ ใส่

1
fetchPriority="high"

✅ preload image ✅ ลด layout shift ✅ ใช้ stable transition names ✅ อย่า animate element ใหญ่เกินจำเป็น

เพราะ View Transition ใช้ snapshot ของ DOM จริง ถ้า asset โหลดไม่ทันจะรู้สึกกระตุกทันที


🔥 Insight จากการใช้งานจริง

สิ่งที่หลายคนพลาด:

❌ ใช้แค่ page animation ❌ ไม่ทำ shared element transition ❌ transition name ไม่ unique ❌ image โหลดช้า ❌ ใส่ไว้ใน

1
layout.tsx

แล้ว transition แปลก ๆ

ถ้าทำถูก:

👉 UX จะรู้สึกเหมือน native app ทันที โดยแทบไม่ต้องใช้ animation library เพิ่มเลย


🧩 สรุป

View Transitions เป็นหนึ่งใน feature ที่ impact สูงมากแต่ effort ต่ำ

เหมาะกับเว็บที่:

  • มี navigation บ่อย

  • image-heavy UI

  • blog

  • ecommerce

  • portfolio

  • dashboard

และที่สำคัญ: ใช้แค่ React + CSS + config นิดเดียวก็ได้ UX ที่ต่างจากเดิมชัดมาก 🚀

Next.jsReactWeb AnimationFrontendPerformanceUXViewTransitionSEO
Teekayu Poongkawabutr (Pon)
Teekayu Poongkawabutr (Pon)(Creaml4tt3)

Developer ท่านหนึ่งที่ทำงานบ้าง ไม่ทำงานบ้าง ทำงานเป็น dev แต่จบ graphic ชีวิตสับสน website: creaml4tt3.me

Latest Blogs

View all
Husky + lint-staged: ทำให้ Git Commit สะอาดขึ้นแบบอัตโนมัติ

Husky + lint-staged: ทำให้ Git Commit สะอาดขึ้นแบบอัตโนมัติ

10 May 2026 15:3012 days ago

ตั้งค่า Git workflow ให้สะอาดและอัตโนมัติด้วย Husky + lint-staged พร้อมสอนติดตั้ง วิธีใช้งาน ข้อดีข้อเสีย และ optional setup สำหรับ formatter/linter อย่าง Prettier และ Biome

ลาออกครั้งแรกโดยไม่มีงานใหม่: ประสบการณ์จริงของ Junior Developer

ลาออกครั้งแรกโดยไม่มีงานใหม่: ประสบการณ์จริงของ Junior Developer

21 Apr 2026 17:00a month ago

ประสบการณ์จริงของการลาออกครั้งแรกโดยยังไม่มีงานใหม่รองรับ จากเด็กจบสาย Graphic ที่ผันตัวมาเป็น Junior Developer ต้องเผชิญความไม่มั่นใจ การหางานสุดกดดัน และบทเรียนชีวิตที่ไม่มีในห้องเรียน

ตั้งค่า Rclone ใช้งานร่วมกับ Cloudflare R2 อย่างง่ายในไม่กี่ขั้นตอน

ตั้งค่า Rclone ใช้งานร่วมกับ Cloudflare R2 อย่างง่ายในไม่กี่ขั้นตอน

02 Jun 2025 11:00a year ago

เรียนรู้วิธีเชื่อมต่อ Rclone กับ Cloudflare R2 (Object Storage แบบ S3-compatible) พร้อมตัวอย่างการตั้งค่า การสำรองข้อมูลอย่างง่ายในไม่กี่ขั้นตอน