- מעבר Cross-fade עובד בין עמודים — קוד HTML/CSS מלא של 2 עמודים עם
document.startViewTransition()או@view-transition { navigation: auto }, משודר live בדפדפן - Morph Transition על כרטיס מוצר — דמו של list view → detail view, שבו תמונת המוצר, הכותרת והמחיר "עפים" בחלקות ממקום למקום (בדיוק כמו ב-iOS App Store)
- Slide Transition בסגנון wizard — 3 עמודים שמחליקים אופקית, עם כיוון נכון ב-RTL (מימין לשמאל ב-Next, משמאל לימין ב-Back)
- רשימת Frameworks שתומכים ב-View Transitions — טבלת השוואה בין Astro, Next.js App Router, React Router v7, SvelteKit, ו-vanilla HTML/CSS — עם שורת ההפעלה המדויקת לכל אחד
- 3 AI Prompt Templates מוכנים — (א) "Cross-fade with reduced-motion fallback", (ב) "Morph between
.card-*and.detail-*with named view-transition-name", (ג) "Astro site-wide slide transition" - Fallback Checklist של 6 פריטים — וידוא שהאתר עובד 100% בדפדפנים ללא תמיכה (Firefox ישן, Safari 17, WebView old Android)
- מילון של 10 מונחים חדשים — View Transitions API, view-transition-name, morph, cross-fade, pseudo-elements, same-document, cross-document ועוד
- תוכלו להסביר מה View Transitions API עושה ואיך הוא שונה מאנימציות CSS רגילות —
@keyframesמניע אלמנט יחיד, View Transitions מניע מעבר בין שני מצבי DOM שונים, כולל בין עמודים נפרדים - תוכלו לבקש מ-AI מעבר cross-fade ב-3 שורות CSS —
@view-transition { navigation: auto }ל-MPA, אוdocument.startViewTransition(() => updateDOM())ל-SPA — בלי ספריות ובלי framework - תוכלו להנחות AI לבנות morph transition שבו אלמנט מ-list view "עף" חלק ל-detail view — עם שמות ייחודיים של
view-transition-nameעל התמונה, הכותרת והמחיר, והבנה למה שם חייב להיות ייחודי בכל רגע נתון - תוכלו לדעת איך View Transitions משתלב עם Astro, Next.js, React Router, ו-SvelteKit — מתי זה שורה אחת (
<ViewTransitions />ב-Astro) ומתי צריך עטיפה ידנית (startTransitionב-React), וגם מתי לא להשתמש (פופאפים קצרים, tooltip hovers)
- פרקים קודמים: פרק 6 (Modern CSS Superpowers) — חובה, כי דיברנו שם על progressive enhancement ועל Can I Use. מומלץ מאוד גם פרק 7 (Scroll-Driven Animations) — אתם כבר יודעים איך לחבר
@keyframesלטיימליין חיצוני, אותו רעיון חוזר פה - מושגים שיחזרו:
@keyframes(מפרק 7), progressive enhancement (פרק 6), browser support דרך Can I Use (פרק 6), ו-scroll-driven animations כהשראה לטיימליינים חדשים (פרק 7) - כלים: דפדפן Chrome 111+ או Edge 111+ (כל גרסה מ-2023 ואילך) — ל-cross-document צריך Chrome 126+. גם StackBlitz או CodePen יעשו את העבודה. אופציונלי: Astro 4+, Next.js 15+, או React Router v7 — אם רוצים לבדוק framework integration
- ידע: הבנה בסיסית מה זה SPA מול MPA (אם לא — נסביר ב-8.9), יכולת לפתוח DevTools ולראות את Animations panel
- זמן משוער: 100-130 דקות (כולל 4 התרגילים — חלקם דורשים StackBlitz פתוח במקביל)
בפרק 7 הוספתם לאתר שלכם Scroll-Driven Animations — reveal בגלילה, progress bar, ו-parallax ב-CSS טהור. האתר כבר "חי" כשגוללים. אבל יש עדיין רגע אחד שחושף אותו כ"אתר" ולא כ"אפליקציה" — הניווט בין עמודים. לוחצים על קישור, המסך נהיה לבן לרגע, ואז עמוד חדש "קופץ". זה ה-hard page refresh הקלאסי. בפרק הזה (8) תסגרו את הפער האחרון: תוסיפו View Transitions API שהופך כל מעבר לאנימציה חלקה — cross-fade ב-3 שורות CSS, או morph של כרטיס מוצר שעף לעמוד הפריט כמו ב-App Store. בפרק הבא (9) — Glassmorphism, Liquid Glass, Aurora UI ומגמות עיצוב מודרניות — נעבור ל-שכבת האפקטים: backdrop-filter: blur(), mesh gradients, ו-Aurora backgrounds אנימטיים. אחרי פרק 9 יהיו לכם את כל השכבות: layout (פרק 5), modern CSS (פרק 6), scroll animations (פרק 7), page transitions (פרק 8), ו-visual effects (פרק 9) — החמישייה שהופכת אתר מ"בסדר" ל"וואו". פרק 8 הוא דרישת-קדם ל-capstone בפרק 13, שם תבנו design brief שכולל View Transitions כחלק מה-spec.
| מונח (English) | תרגום | הגדרה בשורה אחת |
|---|---|---|
| View Transitions API | ממשק מעברי תצוגה | API מקורי בדפדפן שמאפשר אנימציה חלקה בין שני מצבי DOM שונים — בתוך עמוד אחד (SPA) או בין עמודים (MPA) |
| view-transition-name | שם מעבר תצוגה | CSS property שמסמן אלמנט כ"משתתף" במעבר; הערך חייב להיות ייחודי בכל רגע נתון |
| ::view-transition (pseudo-elements) | פסאודו-אלמנטים של המעבר | 7 שכבות וירטואליות שהדפדפן יוצר אוטומטית בזמן מעבר — אפשר לעצב אותן עם @keyframes |
| Cross-fade | מעבר הדרגתי | ברירת-המחדל: העמוד הישן נעלם ב-fade-out והחדש מופיע ב-fade-in, בדרך כלל ב-250ms |
| Morph Transition | מעבר מורפינג / Shared Element | אלמנט "עף" ממיקום אחד לאחר בין שני מצבים — כמו תמונת מוצר ש"גדלה" מ-thumbnail ל-full view |
| Slide Transition | מעבר החלקה | העמוד הישן מחליק החוצה לכיוון אחד, החדש נכנס מהצד הנגדי — סגנון wizard/onboarding |
| Same-document transitions | מעברים בתוך מסמך | מעברים בתוך SPA — הדף לא נטען מחדש, רק ה-DOM משתנה; מופעל עם document.startViewTransition() |
| Cross-document transitions | מעברים בין מסמכים | מעברים בין עמודים שונים (MPA) — כל לחיצה על קישור טוענת HTML חדש; מופעל עם @view-transition { navigation: auto } |
| Navigation API | ממשק ניווט | API חדש שמחליף חלק מ-history.pushState — משתלב בטבעיות עם View Transitions ב-SPAs |
| Page Transitions | מעברי עמודים | המונח-על לכל מעבר בין שני מצבי UI; View Transitions הוא ה-implementation הנייטיבי שלהם ב-2025-2026 |
8.1 למה אתר מרגיש כמו "אתר" ואפליקציה כמו "אפליקציה"
יש טסט פשוט. פתחו את Instagram באייפון. פתחו את אינסטגרם בדפדפן ב-desktop (instagram.com). תחליקו בין תמונות, תיכנסו לפרופיל, תחזרו. שימו לב מה בדיוק מרגיש שונה. הפידים זהים. הצבעים זהים. האייקונים זהים. אבל משהו — משהו עמוק — עושה את ההבדל בין "זו אפליקציה" ל"זה אתר".
ההבדל הזה הוא מעברים. באפליקציה, כשאתם לוחצים על תמונת פרופיל, היא "גדלה" עד שהיא ממלאת את המסך. באתר, כשאתם לוחצים על קישור — המסך נהיה לבן לשבריר שנייה, ואז עמוד חדש "קופץ" במקום. זה hard page refresh, וזה הטל המרכזי שחושף אתר כאתר.
המעברים האלה — shared element transitions בלשון Material Design, hero animations בלשון iOS — היו עד 2023 בלעדיים לאפליקציות native. ב-web היית חייב לכתוב 200 שורות של JavaScript עם getBoundingClientRect(), requestAnimationFrame, ו-FLIP technique (First-Last-Invert-Play). זה היה מסובך, שביר, ולא-responsive. 90% מהאתרים פשוט ויתרו.
מה השתנה ב-2023-2026
ב-מרץ 2023, Chrome 111 הכניסו את View Transitions API — ה-native פתרון של הפלטפורמה. ב-ספטמבר 2024 הגיעה התמיכה ב-cross-document transitions (מעברים בין עמודים נפרדים, לא רק בתוך SPA). ב-2025-2026, Firefox ו-Safari מצטרפים. התוצאה: כל אתר, ב-3 שורות CSS, יכול להרגיש כמו אפליקציה.
זה לא מוגזם להגיד שזה אחד השינויים הכי גדולים בחוויית ה-web מאז responsive design. וכן — AI עדיין לא משתמש בזה כברירת-מחדל. זו בדיוק ההזדמנות שלכם.
המרחק בין "אתר" ל"אפליקציה" הוא היום 3 שורות של CSS, לא 200 שורות של JavaScript. View Transitions API הוא הטכנולוגיה הכי underrated של 2025-2026 — רוב המפתחים עדיין חושבים שצריך Framer Motion או GSAP בשביל זה. הם טועים. הפלטפורמה כבר פתרה את זה, חינם, native, performant.
למה זה משנה עסקית
- תפיסת ערך — מוצר שמרגיש "אפליקציה" מתומחר ב-20-40% יותר ממוצר שמרגיש "אתר". גולש תופס SaaS עם מעברים חלקים כיותר מקצועי מאחד בלי, בלי יחס לפיצ'רים.
- Retention — מעבר חלק מקטין את ה-"perceived loading time" ב-30-50%. הגולש לא רואה מסך לבן, אז הוא לא חושב "זה איטי".
- Memorability — אפקט morph של תמונת מוצר שעפה לעמוד מלא זכור יותר משינוי עמוד רגיל. זה הופך פעולה שגרתית ל-moment.
- Competitive edge — נכון לאפריל 2026, פחות מ-5% מאתרי B2B ישראליים משתמשים ב-View Transitions. אם אתם בתוך ה-5%, אתם נראים לפחות שנה קדימה.
פתחו את live-transitions.pages.dev (או view-transitions.chrome.dev) בדפדפן Chrome. נווטו בין הדפים. שימו לב מה קורה למסך — הוא לא קופץ, הוא מתחלף בחלקות. עכשיו פתחו אותו ב-Firefox או Safari (אם אין לכם תמיכה, עדיין יעבוד — פשוט בלי האנימציה). ההבדל בין שתי החוויות הוא בדיוק מה שאתם תדעו לבנות בסוף הפרק הזה.
8.2 View Transitions API — מה זה, ואיך הוא שונה מ-@keyframes
הדרך הכי פשוטה להבין את View Transitions היא להשוות אותו ל-@keyframes הקלאסי שאתם כבר מכירים מפרק 7:
| @keyframes | View Transitions API |
|---|---|
| מניע אלמנט אחד ממצב A למצב B | מניע מעבר בין שני מצבי DOM שונים — יכול להיות בתוך עמוד או בין עמודים |
| האלמנט קיים בשני המצבים | האלמנט יכול להיעלם (DOM ישן) ולהופיע (DOM חדש) — הדפדפן מגשר |
| מופעל עם trigger (hover, click, class) | מופעל עם document.startViewTransition() או ניווט רגיל |
| מתאים לאלמנטים יחידים: כפתור, כרטיס, נצר | מתאים למעברים מבניים: ניווט, מיון, פילטרים, modals |
| לא יכול לעבור בין עמודים | עובד בין עמודים שונים (cross-document) ב-Chrome 126+ |
הקסם מאחורי הקלעים
כשאתם מפעילים View Transition, הדפדפן עושה משהו מורכב מאחורי הקלעים:
- צילום של ה-DOM הנוכחי (העמוד הישן) — מעין screenshot וירטואלי בזיכרון.
- ביצוע השינוי — החלפת HTML, ניווט לעמוד חדש, או עדכון DOM.
- צילום של ה-DOM החדש.
- יצירת 7 pseudo-elements שמכילים את שני הצילומים (ישן + חדש).
- הפעלת fade-out על הישן ו-fade-in על החדש, בברירת-מחדל — אפשר להחליף את זה ב-
@keyframesמשלכם. - הסרת ה-pseudo-elements כשהמעבר מסתיים.
זה הסיבה שמרגישים כמו אפליקציה — הדפדפן מטפל באנימציה ב-compositor thread, ב-60fps, גם אם ה-DOM השתנה לחלוטין בין שני המצבים.
שלושה סוגי מעברים — בראייה גבוהה
- Cross-fade (ברירת-מחדל) — העמוד הישן דוהה לשקיפות, החדש מופיע. 3 שורות CSS, אפקט מיידי.
- Morph / Shared Element — אלמנט ספציפי (תמונה, כותרת) "עף" ממיקום ישן למיקום חדש. דורש
view-transition-nameייחודי על האלמנט בשני המצבים. - Slide — העמוד הישן מחליק החוצה, החדש נכנס מהצד. דורש
@keyframesמשלכם על ה-pseudo-elements.
נעבור על שלושתם במתכונים מלאים בסעיפים 8.6, 8.7, ו-8.8. אבל קודם — נבין את ה-building blocks.
פתחו את DevTools ב-Chrome (F12). לכו ל-Animations panel (אם לא רואים — לחצו על 3 הנקודות → More tools → Animations). עכשיו חזרו לאתר מה-Do Now הקודם ונווטו בין העמודים. תראו בפאנל את ה-view transition animations נרשמות בזמן אמת. לחצו עליהן — אתם תראו את 7 ה-pseudo-elements שהדפדפן יצר. זה ה-proof שזה לא קסם — זו CSS רגיל מתחת.
8.3 document.startViewTransition() — נקודת הכניסה ב-JavaScript
ל-same-document transitions (SPA, React, Vue, Svelte) — זו השורה שמפעילה הכל:
document.startViewTransition(() => {
// כאן אתם מעדכנים את ה-DOM.
// הדפדפן יצלם "לפני", יריץ את הפונקציה, יצלם "אחרי", ויעביר ביניהם.
updateTheDOM();
});
זהו. תנאי יחיד: הפונקציה שמועברת חייבת לעדכן את ה-DOM בצורה סינכרונית, או להחזיר Promise ש-resolve אחרי העדכון.
דוגמה מלאה — מיון רשימה עם fade
const sortBtn = document.querySelector('#sort-btn');
const list = document.querySelector('#product-list');
sortBtn.addEventListener('click', () => {
// בדיקת תמיכה — חיוני!
if (!document.startViewTransition) {
sortList(); // fallback: מיון רגיל, בלי אנימציה
return;
}
// הפעלת המעבר
document.startViewTransition(() => sortList());
});
function sortList() {
const items = [...list.children];
items.sort((a, b) => +a.dataset.price - +b.dataset.price);
items.forEach(item => list.appendChild(item));
}
התוצאה: כשלוחצים על "מיון לפי מחיר", הפריטים לא קופצים למיקומים החדשים — הם זוחלים בחלקות. 4 שורות של boilerplate (startViewTransition + בדיקת תמיכה) הוסיפו חוויית app.
תחזיר Promise אם העדכון async
document.startViewTransition(async () => {
const newData = await fetch('/api/products').then(r => r.json());
renderProducts(newData);
});
שימו לב: הדפדפן "יקפיא" את המצב הישן על המסך עד שה-Promise מסתיים. אם ה-fetch לוקח 3 שניות — הגולש רואה מסך קפוא 3 שניות. תמיד עטפו fetch-ים איטיים ב-Promise.race עם timeout של 200-300ms לכל היותר, או תשתמשו ב-skeleton screen מחוץ למעבר.
מה מחזיר הפונקציה
startViewTransition מחזיר אובייקט עם 3 Promises שימושיים:
const transition = document.startViewTransition(() => updateDOM());
transition.ready.then(() => {
// ה-pseudo-elements נוצרו; אפשר להוסיף animations דינמית
});
transition.finished.then(() => {
// המעבר הסתיים; זמן טוב לניקוי
});
transition.updateCallbackDone.then(() => {
// ה-DOM update הסתיים (הפונקציה רצה), אבל האנימציה עדיין בתהליך
});
ב-95% מהמקרים לא תצטרכו את זה. אבל כשתרצו לסנכרן דברים (למשל להפעיל sound effect בדיוק בסוף המעבר) — transition.finished הוא החבר שלכם.
פתחו StackBlitz (או CodePen). צרו HTML עם 5 div-ים ברשימה, וכפתור "shuffle". כתבו JS שעושה items.sort(() => Math.random() - 0.5) ומסדר מחדש את ה-DOM. ריצו — הפריטים יקפצו. עכשיו עטפו את הסידור ב-document.startViewTransition(() => ...). ריצו שוב — הם יזחלו בחלקות. זו הדרך הכי מהירה להרגיש את הקסם.
8.4 view-transition-name — איך "לסמן" אלמנט שמשתתף במעבר
ברירת-המחדל של View Transitions היא cross-fade גלובלי — כל העמוד דוהה, כל העמוד מופיע. זה נחמד, אבל לא מרשים. הקסם האמיתי מתחיל כשאלמנט ספציפי עובר בצורה שונה מהשאר — למשל תמונת מוצר שגדלה מ-thumbnail ל-full view, בזמן שכל השאר עושה cross-fade רגיל.
לשם כך צריך view-transition-name. זה CSS property שאומר לדפדפן "האלמנט הזה מקבל טיפול מיוחד — עקוב אחריו בנפרד".
ה-syntax הבסיסי
.product-card__image {
view-transition-name: product-hero-image;
}
עכשיו, בכל מעבר, אם קיים אלמנט עם view-transition-name: product-hero-image ב-לפני וגם ב-אחרי — הדפדפן יתאים ביניהם וייצר morph animation.
הכלל הקריטי: ייחודיות
בכל רגע נתון, לכל view-transition-name חייב להיות בדיוק אלמנט אחד על העמוד. אם יש שניים — המעבר ייכשל בשקט, והאלמנטים יקפצו כמו בלי View Transitions. זה הטעות המס' 1 של מתחילים.
מה קורה: מגדירים .card { view-transition-name: card } על class משותף. כל 12 הכרטיסים ברשימה מקבלים את אותו שם. המעבר נשבר — כל הכרטיסים "קופצים" במקום לזרום.
למה זה מפתה: נראה הגיוני — כולם כרטיסים, כולם מקבלים אותו style. ככה CSS עובד בכל מקום אחר.
מה לעשות במקום: או לתת שם ייחודי לכל כרטיס עם אינדקס: style="view-transition-name: card-{index}" (ב-React/Vue בקלות), או להשתמש ב-CSS fallback: .card:nth-child(1) { view-transition-name: card-1; } וכו'. החל מ-Chrome 125 יש גם view-transition-class שמאפשר לעצב קבוצות בלי להפר ייחודיות — אבל זה עדיין בזהירות.
מתכון: תיוג כרטיס מוצר שלם כ-"morph group"
אתם רוצים שכשהגולש ילחץ על כרטיס מוצר ברשימה, התמונה, הכותרת, והמחיר יעופו בחלקות למיקומים החדשים בעמוד הפריט. הנה ה-CSS:
/* בעמוד הרשימה */
.product-card[data-id="42"] .product-image {
view-transition-name: product-42-image;
}
.product-card[data-id="42"] .product-title {
view-transition-name: product-42-title;
}
.product-card[data-id="42"] .product-price {
view-transition-name: product-42-price;
}
/* בעמוד הפריט */
.product-detail__hero-image {
view-transition-name: product-42-image;
}
.product-detail__title {
view-transition-name: product-42-title;
}
.product-detail__price {
view-transition-name: product-42-price;
}
שימו לב: אותם 3 שמות בשני העמודים, אבל על סלקטורים שונים. הדפדפן מתאים ביניהם ובונה אנימציה של morph עבור כל אחד. התוצאה: חוויה זהה ל-iOS App Store.
יצירת שם דינמית ב-React/Vue
בפועל, אתם לא תכתבו CSS ידני לכל מוצר. תעבירו את השם כ-inline style:
// React
<img
src={product.image}
style={{ viewTransitionName: `product-${product.id}-image` }}
/>
// Vue
<img
:src="product.image"
:style="{ viewTransitionName: `product-${product.id}-image` }"
/>
זה הדפוס הסטנדרטי: שם מבוסס ID. אם יש לכם 100 מוצרים בעמוד, יהיו 100 view-transition-name שונים — וזה בסדר גמור, כי רק אלה שמופיעים בשני העמודים יעברו morph.
פתחו אתר e-commerce שאתם אוהבים (Zalando, ASOS, KSP, או כל אחד). לחצו על כרטיס מוצר והסתכלו איך העמוד עובר. האם התמונה "עפה" או "קופצת"? האם הכותרת נשארת במקום או מתחלפת? אם אתם רואים morph — אתם יודעים שהאתר מיישם View Transitions (או FLIP ידני). אם הכל קופץ — האתר עדיין לא עושה את זה, וזה מה שאתם תבנו בעצמכם בסוף הפרק.
8.5 ::view-transition pseudo-elements — 7 השכבות של המעבר
כש-View Transition מתחיל, הדפדפן בונה עץ של 7 pseudo-elements וירטואליים. הם לא נראים ב-DOM הרגיל, אבל אפשר לעצב אותם עם CSS. הכרה שלהם = שליטה מלאה במעבר.
| Pseudo-element | מה זה | מתי לעצב |
|---|---|---|
::view-transition | ה-root — השכבה שמכילה את הכל | לעיתים נדירות — רק לקביעת pointer-events או z-index גלובלי |
::view-transition-group(root) | קבוצת ברירת-המחדל — כל מה שאין לו שם ייחודי | כשרוצים לשלוט ב-duration/easing של ה-cross-fade הכללי |
::view-transition-group(name) | הקבוצה של אלמנט מסומן עם view-transition-name: name | כשרוצים animation מותאם לאלמנט — לדוגמה תמונת hero |
::view-transition-image-pair(name) | המיכל שמכיל את שתי הגרסאות (old + new) | ל-mix-blend-mode או positioning מיוחד |
::view-transition-old(name) | ה-snapshot של ה-DOM הישן | לשנות את ה-fade-out: duration, easing, transform |
::view-transition-new(name) | ה-snapshot של ה-DOM החדש | לשנות את ה-fade-in: duration, easing, transform |
::view-transition-root | alias ל-::view-transition בחלק מהמפרטים | בד"כ לא — השתמשו ב-::view-transition |
דוגמה: שליטה ב-duration של ה-cross-fade הכללי
::view-transition-old(root),
::view-transition-new(root) {
animation-duration: 0.4s;
animation-timing-function: cubic-bezier(0.16, 1, 0.3, 1);
}
שורה אחת — ה-fade-out וה-fade-in עכשיו לוקחים 400ms (במקום 250ms ברירת-המחדל) עם easing של "ease-out expo" (קלאסי של Linear, Vercel, Framer).
דוגמה: מעבר custom על כרטיס hero
/* החלף את ה-fade הסטנדרטי ב-scale-fade לתמונת ה-hero */
::view-transition-old(hero-image) {
animation: scale-out 0.3s ease-in forwards;
}
::view-transition-new(hero-image) {
animation: scale-in 0.3s ease-out backwards;
}
@keyframes scale-out {
to { opacity: 0; transform: scale(1.2); }
}
@keyframes scale-in {
from { opacity: 0; transform: scale(0.8); }
}
עכשיו תמונת ה-hero לא סתם דוהה — היא "מתקרבת ומתרחקת" תוך כדי fade. זה הדפוס של Apple.com וגם של Dribbble.
פתחו את אתר הדמו מה-Do Now הראשון. ב-DevTools, לכו ל-Elements ופתחו את ה-root (html). בזמן שאתם לוחצים על קישור, תסתכלו מהר על ה-DOM — תראו לרגע עץ של ::view-transition עם ילדים (::view-transition-group, ::view-transition-image-pair...). זה ה-"מאחורי הקלעים". אחרי כמה מאות מילישניות הוא נעלם.
8.6 מתכון #1: Cross-fade — ברירת-מחדל ב-3 שורות
Cross-fade הוא המתכון הכי פשוט, והכי מומלץ כ-baseline. כמעט כל אתר יכול לקבל אותו בחינם — והוא כבר משנה 60% מהתחושה.
ל-MPA / Astro / static sites — שורה אחת
@view-transition {
navigation: auto;
}
זהו. שימו את השורה הזו ב-CSS הגלובלי של האתר. כל ניווט בין עמודים יהיה cross-fade. עובד ב-Chrome 126+ ו-Edge 126+.
ל-SPA / React / Vue — wrapping של ניווט
// ב-App.jsx או ב-router wrapper
function navigate(url) {
if (!document.startViewTransition) {
window.location.href = url; // fallback
return;
}
document.startViewTransition(() => {
// ה-router שלכם מעדכן את ה-DOM
router.push(url);
});
}
התאמה עדינה של ה-cross-fade
/* השתמשו בעיטור שקוף + duration נוח */
::view-transition-old(root),
::view-transition-new(root) {
animation-duration: 0.25s;
animation-timing-function: ease-out;
}
/* אל תרצו overlap? הריצו ברצף במקום במקביל */
::view-transition-image-pair(root) {
isolation: auto; /* כברירת-מחדל יש blend; isolation: auto מחזיר לרגיל */
}
הוספת slide דק ב-RTL (מאוד ישראלי)
::view-transition-old(root) {
animation: slide-out-rtl 0.3s ease-in forwards;
}
::view-transition-new(root) {
animation: slide-in-rtl 0.3s ease-out backwards;
}
@keyframes slide-out-rtl {
to { opacity: 0; transform: translateX(20px); }
}
@keyframes slide-in-rtl {
from { opacity: 0; transform: translateX(-20px); }
}
שימו לב ל-translateX חיובי (20px ימינה) לעמוד הישן ו-שלילי (-20px משמאל) לעמוד החדש — בעברית RTL זו ההתקדמות הטבעית. אם אתם עובדים ב-LTR — החליפו את הסימנים.
מה קורה: מפתחים מנסים "לעזור" עם html { transition: opacity 0.3s }. התוצאה: ה-transition הרגיל מתנגש עם View Transitions, והמעבר נשבר.
למה זה מפתה: כי transition מוכר, ו-View Transitions חדש ומפחיד.
מה לעשות במקום: לסמוך על View Transitions. אל תוסיפו CSS transitions על html/body. כל ה-animation נעשית ב-pseudo-elements. אם רוצים שליטה — השתמשו ב-::view-transition-old/new, לא ב-transition רגיל.
פתחו את האתר האישי שלכם (הגנרי, מפרק 1), או כל אתר ב-StackBlitz. הוסיפו ל-CSS הגלובלי: @view-transition { navigation: auto; }. רעננו ב-Chrome. נווטו בין עמודים (אם זה static) או השתמשו ב-HTML hyperlinks רגילים. שימו לב לחוויה — מסך לבן נעלם, הכל הופך חלק. 3 שורות, חוויה של אפליקציה.
8.7 מתכון #2: Morph / Shared Element — כרטיס שעובר לעמוד מלא
זה המתכון שבאמת עושה "וואו". הגולש לוחץ על כרטיס מוצר ברשימה — התמונה "גדלה" וזזה למיקום החדש בעמוד הפריט, הכותרת "זוחלת" למקום, המחיר "מתנגן" לגודל חדש. זו אפליקציה — לא אתר.
זה בדיוק הדפוס שהופך את iOS App Store ל-iOS App Store. ועכשיו הוא שורה של CSS.
המתכון המלא — כרטיס list → detail view
נניח שיש לכם רשימת מוצרים ב-/products ועמוד פרטי מוצר ב-/products/42. צעד 1 — תיוג הכרטיס:
<!-- /products -->
<a href="/products/42" class="product-card">
<img
src="/images/42.jpg"
class="product-card__image"
style="view-transition-name: product-42-image;"
/>
<h3
class="product-card__title"
style="view-transition-name: product-42-title;"
>
אוזניות Sony WH-1000XM5
</h3>
<span
class="product-card__price"
style="view-transition-name: product-42-price;"
>
₪1,499
</span>
</a>
צעד 2 — תיוג אותם שמות בעמוד הפרטים:
<!-- /products/42 -->
<main class="product-detail">
<img
src="/images/42-large.jpg"
class="product-detail__hero"
style="view-transition-name: product-42-image;"
/>
<h1
class="product-detail__title"
style="view-transition-name: product-42-title;"
>
אוזניות Sony WH-1000XM5 Noise Cancelling
</h1>
<div
class="product-detail__price"
style="view-transition-name: product-42-price;"
>
₪1,499
</div>
</main>
צעד 3 — הפעלת cross-document transitions (אם זה MPA):
@view-transition {
navigation: auto;
}
/* Duration קצת יותר ארוך ל-morph, כדי שיראו את התנועה */
::view-transition-group(product-42-image),
::view-transition-group(product-42-title),
::view-transition-group(product-42-price) {
animation-duration: 0.4s;
animation-timing-function: cubic-bezier(0.16, 1, 0.3, 1);
}
זהו. 3 תגים, 3 שמות, 6 שורות CSS. התוצאה: תמונת המוצר "עפה" ממיקום הכרטיס למיקום ה-hero, הכותרת "זוחלת" לגודל החדש, המחיר "מתנגן". חוויית App Store, ב-CSS בלבד.
הפקת שמות דינמית — ב-React
ברור שלא תכתבו ידנית view-transition-name: product-42-image. בפועל תגנרו את זה:
// ProductCard.jsx
export function ProductCard({ product }) {
const nameBase = `product-${product.id}`;
return (
<Link href={`/products/${product.id}`}>
<img
src={product.image}
style={{ viewTransitionName: `${nameBase}-image` }}
/>
<h3 style={{ viewTransitionName: `${nameBase}-title` }}>
{product.title}
</h3>
<span style={{ viewTransitionName: `${nameBase}-price` }}>
₪{product.price}
</span>
</Link>
);
}
טיפ: morph גם על ניווט מערבי (back button)
כשהגולש לוחץ Back, הדפדפן גם מפעיל View Transition — אבל הפוך (מעמוד הפרטים חזרה לרשימה). אם השמות זהים בשני העמודים — ה-morph עובד בשני הכיוונים אוטומטית. זו המתנה הכי גדולה של ה-API.
מה קורה: מגדירים view-transition-name על כל 20 הכרטיסים ברשימה. כשהגולש לוחץ על כרטיס מס' 7, כל ה-20 מקבלים morph — המסך הופך לכאוס של תמונות שזזות.
למה זה מפתה: נראה עקבי — כולם כרטיסים, כולם אותו דין.
מה לעשות במקום: להגדיר view-transition-name רק על הכרטיס ה-נלחץ, דינמית. ב-React אפשר להעביר state שמזהה את ה-id הנלחץ, ולהחיל את השם רק עליו לפני ה-navigation. או להשתמש ב-:has(): .card:has(a:active) { view-transition-name: active-card; } (סוגי browser support בהתאם).
פתחו את chrome developer docs ל-View Transitions ולחצו על הלינק לדמו של "Shared Axis Transitions". שימו לב מה קורה בין העמודים — תמונת ה-hero של כל פוסט עפה חלק למקומה החדש. זה בדיוק מה שתבנו בתרגיל 2. שמרו את ה-URL.
8.8 מתכון #3: Slide — מעבר אופקי כמו wizard
Slide transition מתאים ל-wizard flows (רישום ב-3 שלבים), ל-carousel-like navigation, ול-onboarding screens. הוא משדר "רצף לינארי" — "עברנו לעמוד הבא בתהליך".
המתכון — ב-RTL (עברית)
/* כללי: Slide בכיוון "קדימה" — עמוד ישן יוצא משמאל, חדש נכנס מימין */
::view-transition-old(root) {
animation: slide-out-ltr 0.35s cubic-bezier(0.4, 0, 0.2, 1) forwards;
}
::view-transition-new(root) {
animation: slide-in-rtl 0.35s cubic-bezier(0.4, 0, 0.2, 1) backwards;
}
@keyframes slide-out-ltr {
to { transform: translateX(-100%); opacity: 0.5; }
}
@keyframes slide-in-rtl {
from { transform: translateX(100%); opacity: 0.5; }
}
Slide דו-כיווני — back button בכיוון הפוך
הבעיה: כשלוחצים Next, רוצים slide ימינה. כשלוחצים Back, רוצים slide שמאלה. אבל הדפדפן לא יודע את כיוון הניווט — הוא רק יודע "המעבר החל".
הפתרון: שימו טיימסטמפ או step number ב-URL או ב-sessionStorage. לפני ה-navigation, הוסיפו class ל-<html>:
// לפני ה-navigation
const direction = newStep > currentStep ? 'forward' : 'backward';
document.documentElement.dataset.navDirection = direction;
document.startViewTransition(() => {
router.push(newUrl);
});
/* CSS: שני מצבים */
html[data-nav-direction="forward"] ::view-transition-old(root) {
animation: slide-out-ltr 0.35s forwards;
}
html[data-nav-direction="forward"] ::view-transition-new(root) {
animation: slide-in-rtl 0.35s backwards;
}
html[data-nav-direction="backward"] ::view-transition-old(root) {
animation: slide-out-rtl 0.35s forwards;
}
html[data-nav-direction="backward"] ::view-transition-new(root) {
animation: slide-in-ltr 0.35s backwards;
}
עכשיו ה-wizard שלכם מרגיש כמו app. Next מחליק קדימה, Back מחליק אחורה, והגולש יודע בדיוק "איפה הוא" בתהליך.
פתחו אפליקציית onboarding באייפון (כל app חדש שהתקנתם). שימו לב לכיוון ה-slides: לאן זזים, כמה זמן, איזה easing (האם מרגיש "ספרינג" או "קבוע"?). זה בדיוק ה-reference שאתם תנסו לשחזר ב-web עם המתכון למעלה.
8.9 Same-document מול Cross-document — ההבדל הקריטי
זה ההבדל המושגי החשוב ביותר בפרק, ולצערנו גם זה שמבלבל הכי הרבה אנשים. בואו נעשה סדר.
| Same-document (SPA) | Cross-document (MPA) | |
|---|---|---|
| מה זה | ניווט בתוך אותו עמוד — ה-URL משתנה אבל הדף לא נטען מחדש | ניווט בין עמודים שונים — דף HTML חדש נטען מהשרת |
| דוגמאות | React app, Vue app, Svelte app, Angular app, Next.js עם client routing, Gmail, Twitter | Astro (ברירת-מחדל), WordPress, static HTML sites, Next.js App Router עם server-side navigation |
| איך מפעילים | document.startViewTransition(() => updateDOM()) | @view-transition { navigation: auto } ב-CSS |
| תמיכה בדפדפנים (2026-04) | Chrome/Edge 111+, Safari 18, Firefox מגיע | Chrome/Edge 126+, Safari 18.2, Firefox בתכנון |
| Fallback אוטומטי | אם אין תמיכה — הפונקציה פשוט רצה בלי אנימציה | אם אין תמיכה — ניווט רגיל עם page flash |
איך יודעים באיזה אני?
שאלו את עצמכם: כשאני לוחץ קישור באתר שלי, האם הכתובת בכתובית משתנה אחרי שהרשת טוענת דבר חדש (MPA), או לפני, ואז JavaScript מעדכן את התוכן (SPA)?
- אם יש lightning bolt / loading spinner של הדפדפן בכרטיסייה בזמן ניווט — MPA (cross-document).
- אם הניווט מרגיש מיידי, בלי spinner של הדפדפן — SPA (same-document).
יתרונות וחסרונות של כל גישה
SPA (same-document):
- + שליטה מלאה — אתם קובעים מתי בדיוק ה-DOM משתנה
- + אפשר לבצע pre-load, prefetch, skeleton לפני ה-transition
- − דורש JavaScript — אם ה-JS נכשל, אין ניווט בכלל
- − דורש framework או router ידני
MPA (cross-document):
- + שורה אחת של CSS, בלי JavaScript בכלל
- + עובד עם HTML סטטי — Astro, 11ty, WordPress, hand-coded HTML
- + SEO-friendly כברירת-מחדל
- − אין שליטה על מה שקורה בזמן ה-fetch — הדפדפן מחליט
- − אם הדף הבא איטי (יותר מ-500ms) — הגולש רואה freeze
| מצב | תוצאה |
|---|---|
| יש לכם Next.js App Router, Remix, Astro, או WordPress | ← Cross-document. השתמשו ב-@view-transition { navigation: auto }. שורה אחת, סוף הדרך. |
יש לכם React SPA, Vue SPA, Svelte (לא SvelteKit), או vanilla JS עם history.pushState | ← Same-document. עטפו את ה-navigation ב-document.startViewTransition(). |
| יש לכם Next.js Pages Router או Gatsby (hybrid) | ← Same-document לרוב. Next.js 14+ מציע unstable_ViewTransition component שעוטף את זה אוטומטית. |
| בוני אתר סטטי עם HTML+CSS בלבד (בלי framework) | ← Cross-document. שורה אחת ב-CSS ויש לכם מעבר. |
| לא בטוחים? | ← פתחו DevTools → Network. לחצו על קישור פנימי. אם יש request חדש של HTML document — MPA. אם לא — SPA. |
8.10 Cross-document ל-MPA — Astro, static sites, ו-@view-transition
Cross-document transitions הן ההפצצה של 2024-2026. אתר HTML סטטי של שנת 1999 יכול לקבל "תחושת אפליקציה" עם שורה אחת של CSS. אין צורך ב-framework, אין צורך ב-JavaScript, אין צורך ב-build step.
The simplest possible setup
יצרו שני קבצים:
<!-- /index.html -->
<!DOCTYPE html>
<html lang="he" dir="rtl">
<head>
<link rel="stylesheet" href="/styles.css">
</head>
<body>
<h1>עמוד ראשי</h1>
<a href="/about.html">לאודות →</a>
</body>
</html>
<!-- /about.html -->
<!DOCTYPE html>
<html lang="he" dir="rtl">
<head>
<link rel="stylesheet" href="/styles.css">
</head>
<body>
<h1>אודות</h1>
<a href="/index.html">← חזרה</a>
</body>
</html>
/* /styles.css */
@view-transition {
navigation: auto;
}
פתחו את index.html ב-Chrome. לחצו "לאודות". המסך לא קפץ — הוא התחלף בחלקות. 3 קבצים, 0 JavaScript, חווית app.
דרישות הבסיס — מה חייב להיות
- קובץ CSS גלובלי עם
@view-transition { navigation: auto }. חייב להיות טעון בשני העמודים. - ניווט ב-
<a>tag רגיל — לא ב-window.location, לא ב-form.submit(), לא ב-fetch. הדפדפן מפעיל את המעבר רק על ניווט סמנטי. - same-origin navigation — מעבר לדומיין אחר לא יפעיל View Transition (זה מגבלת אבטחה).
- HTML דומה מספיק — אם מבנה ה-DOM שונה דרמטית, ה-cross-fade עדיין יעבוד, אבל morph לא.
Opt-out של מעברים ספציפיים
@view-transition {
navigation: auto;
}
/* אל תפעיל מעברים אם ה-URL מכיל '/admin/' */
@media (prefers-reduced-motion: no-preference) {
/* ברוב המקרים לא צריך - אבל אפשר לבטל דרך JS: */
}
לבטל מעבר ספציפי דרך JS:
document.addEventListener('pageswap', (event) => {
if (event.viewTransition && shouldSkip(event.activation.to.url)) {
event.viewTransition.skipTransition();
}
});
Astro — מובנה לחלוטין
Astro 4+ מספק View Transitions integration מובנה:
---
// src/layouts/Layout.astro
import { ViewTransitions } from 'astro:transitions';
---
<html lang="he" dir="rtl">
<head>
<ViewTransitions />
</head>
<body>
<slot />
</body>
</html>
שורה אחת ב-<head>, ו-Astro דואג לכל השאר: cross-document transitions, named transitions, polyfill לדפדפנים ישנים, ו-persistent state בין עמודים. זה אחד הפיצ'רים שעושים Astro אטרקטיבי ב-2026.
8.11 Frameworks — Astro, Next.js App Router, React Router v7
האמת: רוב האתרים המקצועיים לא נכתבים ב-vanilla HTML. בואו נראה איך View Transitions משתלב בכל framework מרכזי באפריל 2026.
Astro 4.5+
הכי פשוט. מובנה, ללא setup נוסף:
---
import { ViewTransitions } from 'astro:transitions';
---
<html><head><ViewTransitions /></head>...</html>
אפשר גם להוסיף transition:name="unique-name" directive על כל אלמנט, ו-Astro ממיר אוטומטית ל-view-transition-name עם polyfill לדפדפנים שעוד אין להם תמיכה native.
Next.js App Router (15+)
Next.js 15 הכניסו unstable_ViewTransition component (צפוי להיות stable ב-Next 16):
// app/layout.tsx
import { unstable_ViewTransition as ViewTransition } from 'react';
export default function Layout({ children }) {
return (
<html lang="he" dir="rtl">
<body>
<ViewTransition>
{children}
</ViewTransition>
</body>
</html>
);
}
לתיוג אלמנטים ספציפיים:
<ViewTransition name={`product-${product.id}-image`}>
<img src={product.image} />
</ViewTransition>
שימו לב ש-Next.js מפעיל את זה על route transitions אוטומטית — אין צורך לעטוף router.push ידנית.
React Router v7
React Router v7 (יצא 2024) כולל ViewTransition component מובנה:
import { Link } from 'react-router';
<Link to="/products/42" viewTransition>
מוצר 42
</Link>
ה-viewTransition prop על Link עוטף אוטומטית את ה-navigation ב-document.startViewTransition. אין צורך ביותר.
SvelteKit
SvelteKit עדיין לא מציע API ייעודי (נכון לאפריל 2026), אבל שילוב ידני פשוט בקובץ +layout.svelte:
<script>
import { onNavigate } from '$app/navigation';
onNavigate((navigation) => {
if (!document.startViewTransition) return;
return new Promise((resolve) => {
document.startViewTransition(async () => {
resolve();
await navigation.complete;
});
});
});
</script>
טבלת השוואה
| Framework | Setup | Named transitions | Polyfill | Production-ready |
|---|---|---|---|---|
| Astro 4.5+ | 1 שורה: <ViewTransitions /> | transition:name | מובנה | כן, מ-2024 |
| Next.js 15 App Router | 1 component: <unstable_ViewTransition> | name prop | אין (stable browser only) | Experimental; צפוי stable ב-Next 16 |
| React Router v7 | prop: <Link viewTransition> | ידני עם style | אין | כן, מ-2024 |
| SvelteKit | wrapper ידני ב-onNavigate | ידני | אין | עובד, דורש boilerplate |
| Vue Router 4+ | wrapper ב-beforeEach | ידני | אין | עובד, דורש boilerplate |
| vanilla HTML | 1 שורה CSS: @view-transition | ידני | אין | כן, 2024+ Chrome |
חשבו על הפרויקט הנוכחי שלכם. באיזה framework הוא? רשמו בפינת המסך: (א) Framework = ____, (ב) Setup line = ____. אם אתם לא בטוחים — חפשו ב-package.json (ניתן לפתוח ישירות ב-IDE) והשוו לטבלה. בתרגיל 3 תפעילו View Transitions דווקא בפרויקט הזה.
8.12 Browser support — אפריל 2026, ו-fallback אלגנטי
מצב התמיכה עבר שינויים דרמטיים בין 2023 ל-2026. הנה ה-snapshot נכון לאפריל 2026 (freshness-sensitive — בדקו את caniuse.com לפני deployment):
| דפדפן | Same-document | Cross-document | הערות |
|---|---|---|---|
| Chrome / Chromium | 111+ (מרץ 2023) | 126+ (יוני 2024) | תמיכה מלאה, יציבה |
| Edge | 111+ | 126+ | זהה ל-Chrome |
| Safari | 18+ (ספטמבר 2024) | 18.2+ (דצמבר 2024) | תמיכה מלאה ב-iOS 18 ו-macOS Sonoma |
| Firefox | בתכנון (Nightly 2026) | בתכנון | נמצא ב-"in development"; צפוי ב-2026-2027 |
| Samsung Internet | 25+ (יוני 2024) | טרם | עוקב אחרי Chromium |
שימו לב: נתוני התמיכה משתנים במהירות. תמיד בדקו ב-caniuse.com/view-transitions לפני שאתם שולחים לפרודקשן.
Progressive enhancement — הפילוסופיה
View Transitions תוכנן מראש כ-progressive enhancement. זה אומר: הוא לא שובר שום דבר. אם הדפדפן לא תומך — הניווט פשוט קורה בלי אנימציה. אין לכם מה לדאוג ל-Firefox משנת 2020 שנכנס לאתר שלכם — הוא יראה את האתר כרגיל, בלי הבונוס.
Feature detection
ל-same-document:
if (document.startViewTransition) {
// יש תמיכה
document.startViewTransition(() => updateDOM());
} else {
// fallback
updateDOM();
}
ל-cross-document אין feature detection דרך JS — אבל CSS יודע להתעלם ממה שהוא לא מכיר:
/* Firefox ישן פשוט יתעלם. אין שבירה. */
@view-transition {
navigation: auto;
}
Fallback Checklist
- האתר שלכם חייב לעבוד 100% בלי View Transitions. בדקו ב-Firefox או ב-Chrome incognito עם disable JavaScript.
- הוסיפו
@supportsאם אתם מחילים רק styles מיוחדים:@supports (view-transition-name: a) { ... }. - אל תשלבו state קריטי ב-
startViewTransition. העדכון ל-DOM חייב לעבוד גם בלי ה-wrapping. - בדקו על מכשיר אמיתי (לא רק DevTools emulation) — iOS Safari 17 ו-Firefox Android עלולים להתנהג אחרת.
- הריצו Lighthouse — ה-accessibility ו-performance score לא אמורים לרדת.
- Core Web Vitals: ודאו ש-LCP לא נפגע. מעברים כבדים (morph של תמונות 5MB) יכולים לדחוף LCP מעל 2.5 שניות.
פתחו את caniuse.com/view-transitions. רשמו את ה-"Global" percentage (כמה אחוז מהמשתמשים בעולם יש להם תמיכה). עכשיו שימו לב לפלח של Firefox ו-Safari ישן. עבור אתר ישראלי, 95%+ מהגולשים כבר משתמשים ב-Chrome / Safari מודרני / Edge. זה אומר שהפיצ'ר הזה כבר production-ready לרוב הפרויקטים שלכם — עם fallback נקי ל-5% הנותרים.
8.13 Performance & UX rules — 1-3 אלמנטים, 300ms, reduced-motion
View Transitions הוא עוצמתי, ולכן קל לנצל אותו לרעה. הכלל הזהב: מעבר חלק מרגיש טבעי; מעבר מתוחכם מרגיש מוגזם. הנה 5 כללים ש-99% מהמפתחים מפרים — ואתם לא תפרו.
כלל 1: 1-3 אלמנטים מסומנים, לא יותר
אם אתם מתייגים 20 אלמנטים עם view-transition-name, המעבר יהפוך לכאוס של תנועה. העין של הגולש לא יכולה לעקוב אחרי 20 דברים שזזים במקביל. המלצה: 1 אלמנט ראשי (תמונת hero), 1-2 משניים (כותרת, מחיר) — וזהו. כל השאר — cross-fade כברירת-מחדל.
כלל 2: duration 200-400ms, לא יותר
מעבר של 500ms+ מרגיש "איטי" לגולש. מעבר של פחות מ-150ms מרגיש "מהיר מדי" — הגולש לא מרגיש את האנימציה. ה-sweet spot: 250ms ל-cross-fade, 300-400ms ל-morph.
כלל 3: prefers-reduced-motion — חובה, לא אופציונלי
יש משתמשים שהתנועה גורמת להם ל-motion sickness. יש משתמשים שיצרו setting "reduced motion" ב-OS. לכבד אותם זה לא bonus — זו דרישת נגישות:
@media (prefers-reduced-motion: reduce) {
::view-transition-group(*),
::view-transition-old(*),
::view-transition-new(*) {
animation: none !important;
}
}
זהו. 6 שורות CSS. משתמשים עם reduced-motion יקבלו ניווט מיידי בלי אנימציה — בדיוק כמו שהם רוצים.
כלל 4: אל תחסמו את ה-UI
אם המעבר לוקח 400ms, הגולש לא יכול לבטל את הניווט או ללחוץ Back במהלכו. זה OK ל-300ms, מתחיל להיות בעייתי ב-500ms+. אל תעשו מעברים ארוכים על interactions שהגולש עושה הרבה (חיפוש, פילטר, מיון).
כלל 5: test על mobile אמיתי
Safari iOS ו-Chrome Android יכולים להתנהג שונה מ-desktop. morph של תמונה גדולה על iPhone 12 עלול לקפוץ. בדקו תמיד על 2-3 מכשירים פיזיים לפני שליחה ל-production.
| סוג המעבר | מספר אלמנטים מתויגים | דוגמה |
|---|---|---|
| Cross-fade בלבד | 0 | מעבר בין עמודי About → Services |
| Hero spotlight | 1 | רק תמונת hero של בלוג מעברה לעמוד הכתבה |
| Product morph | 2-3 | תמונה + כותרת + מחיר של מוצר (e-commerce classic) |
| Dashboard transition | 3-5 | sidebar active link + header + main content area |
| Gallery spotlight | 1 | תמונת גלריה → lightbox. לעולם לא 2+. |
| >5 אלמנטים | ← STOP | אם אתם חושבים "גם וגם וגם", אתם טועים. קצצו. |
פתחו את Settings במחשב שלכם. ב-macOS: System Preferences → Accessibility → Display → "Reduce motion". ב-Windows: Settings → Accessibility → Visual effects → Animation effects = Off. עכשיו חזרו לאתר הדמו (מה-Do Now הראשון). האם האנימציות עדיין קורות? אם כן — האתר לא מכבד את ההעדפה, וזה bug. אם הן נעלמו — האתר בנוי נכון.
8.14 איך לבקש מ-AI View Transitions — 3 פרומפטים מדויקים
אם תבקשו מ-AI "add smooth page transitions", תקבלו cross-fade גנרי — או גרוע מזה, פתרון של 200 שורות JavaScript עם Framer Motion. הסוד הוא להיות ספציפיים. הנה 3 templates שעובדים:
Prompt #1 — Cross-fade עם fallback
Add a cross-fade View Transitions API to this site.
Requirements:
- Use @view-transition { navigation: auto } for cross-document support (MPA/Astro)
- Set transition duration to 250ms with ease-out timing
- Include a @media (prefers-reduced-motion: reduce) fallback that disables
all view-transition animations
- Do NOT add any CSS transitions on html or body elements
- Do NOT add JavaScript — CSS-only solution
- Ensure the site still works perfectly in browsers without support (Firefox, Safari 17)
Show me only the CSS I need to add, and the file where to put it.
Prompt #2 — Morph transition בין כרטיס לעמוד פרטי
Add a morph View Transition between the product list page and the product
detail page for product id={productId}.
Elements to morph (use unique view-transition-name for each):
- Product image: view-transition-name: product-{id}-image
- Product title: view-transition-name: product-{id}-title
- Product price: view-transition-name: product-{id}-price
Requirements:
- Add the view-transition-name via inline style (for React/Vue), so it can be
generated from the product id dynamically
- Match element names in BOTH the list card AND the detail page
- Use cubic-bezier(0.16, 1, 0.3, 1) for the group animation (ease-out expo)
- Set animation-duration to 400ms for morph elements, 250ms for everything else
- Include prefers-reduced-motion fallback that disables morph but keeps the navigation working
- Do NOT add view-transition-name on a shared class (.card) — it must be per-item
Frameworks: I'm using {React|Vue|Astro|vanilla}. Use appropriate syntax.
Prompt #3 — Slide transition בסגנון wizard (RTL)
Add a slide View Transition for a 3-step wizard in Hebrew (RTL direction).
Behavior:
- Next button: old page slides OUT to the left, new page slides IN from the right
- Back button: old page slides OUT to the right, new page slides IN from the left
- Track navigation direction in a data-nav-direction attribute on <html> element
- Duration: 350ms with cubic-bezier(0.4, 0, 0.2, 1)
- Include prefers-reduced-motion fallback
- Use translateX and opacity 0.5 at the midpoint for a polished effect
Framework: {Next.js App Router | Astro | vanilla JS}
Return: (1) the CSS for both directions, (2) the JS that sets the
data-nav-direction before calling startViewTransition.
מה הופך את הפרומפטים האלה לעובדים
- מילים טכניות מדויקות — "view-transition-name", "cubic-bezier", "prefers-reduced-motion". AI מזהה את המונחים ומייצר קוד מדויק.
- אילוצים שליליים — "Do NOT add any JavaScript", "Do NOT add view-transition-name on a shared class". בלי זה, ה-AI ימציא פתרונות מוגזמים.
- duration מדויק — לא "smooth" אלא "250ms with ease-out". AI לא מנחש.
- Framework מצוין — AI יודע ש-Astro זה לא Next.js זה לא React SPA. זה משנה את ה-output.
- Fallback explicit — כולל prefers-reduced-motion ו-browser support. AI לא יזכור בעצמו.
העתיקו את Prompt #1 לכלי AI שאתם משתמשים בו (Claude, ChatGPT, Cursor, v0). הריצו. קבלו את ה-CSS. הוסיפו אותו לאתר שלכם בקובץ CSS גלובלי. רעננו את הדפדפן ב-Chrome. נווטו בין שני עמודים באתר. האם יש cross-fade? אם כן — הצלחתם. אם לא — בדקו שיש לכם 2 עמודים שונים (.html נפרדים), והקובץ CSS טעון בשניהם.
8.15 Gotchas — 5 בעיות שכולם נתקלים בהן
Gotcha 1: display: none שובר morph
אלמנט עם display: none לא מצולם בזמן View Transition. אם התמונה שלכם מוסתרת ב-display: none בעמוד אחד ו-display: block בשני, ה-morph ייכשל.
הפתרון: השתמשו ב-visibility: hidden + opacity: 0, או ב-conditional rendering ב-React/Vue שמסיר את האלמנט לגמרי (לא רק מסתיר).
Gotcha 2: שם view-transition-name זהה בשני אלמנטים בו-זמנית
כבר דיברנו על זה — הנה עוד scenario. יש לכם sticky header עם לוגו שמקבל view-transition-name: logo. הלוגו מופיע גם ב-footer. בזמן מעבר — שני אלמנטים עם אותו שם. View Transition נשבר.
הפתרון: שמות ייחודיים — logo-header, logo-footer. לעולם לא לחזור על שם.
Gotcha 3: Mobile Safari מגמגם על morph של תמונות גדולות
iPhone 12 / 13 עם תמונה של 4MB תגרום ל-View Transition לגמגם ב-5-10 frames. הסיבה: הצילום עצמו לוקח זמן על mobile.
הפתרון: (א) תמונות מאופטמות — WebP/AVIF תחת 200KB. (ב) image-rendering: optimizeSpeed על תמונות במעבר. (ג) test על מכשיר אמיתי, לא רק DevTools.
Gotcha 4: מעברים לא עובדים עם window.location.href
אם ב-JS שלכם אתם משתמשים ב-window.location.href = '/page2' לניווט, Cross-document View Transitions לא יפעלו. הדפדפן מפעיל אותם רק על ניווט סמנטי (<a> tag click, form submit, history.back).
הפתרון: השתמשו ב-<a href="..."> במקום window.location.href. אם חייבים JS, עטפו ב-document.startViewTransition ידנית.
Gotcha 5: iframe-ים לא תומכים
אם ה-site שלכם משובץ ב-iframe (widget, chatbot), View Transitions בתוך ה-iframe עלולים לא לעבוד עקב הגבלות cross-origin.
הפתרון: חיו עם זה. iframe הוא sandbox, ומעברים בתוכו הם edge-case. אם חיוני — scroll ב-host document במקום ניווט ב-iframe.
מה קורה: המפתח אומר "95% ב-Chrome, לא כדאי להוסיף fallback". שולח לפרוד. יום אחד, בנאדם עם Firefox נכנס. החוויה שבורה — לחיצה על קישור לא מראה כלום למשך 300ms, ואז עמוד קופץ. הוא חושב "האתר הזה דפוק" ועוזב.
למה זה מפתה: האחוזים באמת קטנים, וה-fallback דורש 6 שורות של CSS.
מה לעשות במקום: fallback אלגנטי הוא תמיד חובה. זה לא 5% מהגולשים — זה 5% מהרושם הראשון. הוסיפו @media (prefers-reduced-motion: reduce) + בדיקת תמיכה ב-JS. Firefox Desktop 5%. Safari 17 (עדיין בשימוש) 3%. WebView on old Android 4%. זה 12% שעלול להתרשם רע. 6 שורות CSS זה מחיר זול להימנע מזה.
פתחו את האתר האישי שלכם ב-Firefox (אם אין לכם — התקינו עכשיו, לוקח דקה). לחצו בין דפים. רשמו מה אתם רואים — האם הניווט עובד חלק, או שיש page flash? האם יש שגיאות ב-console? אם הכל עובד (רק בלי האנימציה של Chrome) — ה-progressive enhancement שלכם עובד. אם יש שבירה — זה ה-bug מס' 1 שצריך לתקן לפני שמיישמים View Transitions.
- פתחו StackBlitz חדש — template "Static" (או vanilla HTML/CSS).
- צרו 3 קבצי HTML:
index.html,about.html,contact.html. בכל אחד שימו כותרת, פסקה, ו-3 קישורים לשני העמודים האחרים. - צרו קובץ
styles.cssגלובלי. טענו אותו בכל 3 העמודים. - הוסיפו ל-
styles.css:@view-transition { navigation: auto; }. - הוסיפו:
::view-transition-old(root), ::view-transition-new(root) { animation-duration: 0.25s; animation-timing-function: ease-out; }. - הוסיפו
@media (prefers-reduced-motion: reduce)שמבטל את האנימציות. - בדקו ב-Chrome — נווטו בין 3 העמודים. תראו cross-fade.
- פתחו DevTools → Animations panel. הפעילו מעבר. צלמו screenshot של ה-view-transition animations ברשימה.
- הפעילו "Reduce motion" במערכת. נווטו שוב — האנימציות צריכות להיעלם.
- פתחו את אותו האתר ב-Firefox — ודאו שהניווט עובד חלק, בלי שבירה.
מה צריך להיות בסוף: פרויקט StackBlitz עם 3 עמודים + cross-fade transitions + reduced-motion fallback + 3 screenshots (Chrome עם animations, Chrome עם reduced-motion, Firefox ללא animations אבל עם ניווט תקין).
- בפרויקט StackBlitz חדש, צרו HTML list עם 4 כרטיסי מוצר ב-
/products.html. כל כרטיס: תמונה (unsplash.com), כותרת, מחיר, קישור ל-/product-{id}.html. - צרו 4 עמודי פרטים:
product-1.htmlעדproduct-4.html. בכל אחד: אותה תמונה בגודל גדול (hero), אותה כותרת, אותו מחיר, ו"חזרה לרשימה". - הוסיפו
@view-transition { navigation: auto }ל-CSS הגלובלי. - ב-
products.html, לכל כרטיס הוסיפו inline styles:style="view-transition-name: product-{id}-image"על התמונה,product-{id}-titleעל הכותרת,product-{id}-priceעל המחיר. - ב-
product-{id}.html, הוסיפו את אותם שמות על ה-hero image, כותרת, ומחיר בעמוד הפרטים. - הוסיפו CSS ל-group animation:
::view-transition-group(product-1-image) { animation-duration: 0.4s; animation-timing-function: cubic-bezier(0.16, 1, 0.3, 1); }— חזרו על זה ל-4 המוצרים (או השתמשו ב-view-transition-classאם Chrome 125+). - בדקו ב-Chrome: לחצו על כרטיס. התמונה, הכותרת והמחיר צריכים "לעוף" למיקומיהם בעמוד הפרטים.
- לחצו Back. ה-morph צריך לעבוד בכיוון ההפוך אוטומטית.
- הוסיפו reduced-motion fallback.
- בדקו ב-Safari 18 ו-Firefox — ודאו שהכל עובד (ב-Firefox בלי morph, אבל בלי שבירה).
מה צריך להיות בסוף: 5 עמודים (1 list + 4 details) עם morph transitions שעובדים בשני הכיוונים, 3 screenshots (תחילה מעבר, אמצע מעבר, סוף מעבר), ו-reduced-motion fallback תקין.
- צרו פרויקט Astro חדש:
npm create astro@latest. בחרו ב-template "Minimal". - צרו 3 pages ב-
src/pages/:index.astro,blog.astro,about.astro. - צרו
src/layouts/Layout.astroעם ה-HTML boilerplate. - בתוך
<head>של ה-Layout, הוסיפו:import { ViewTransitions } from 'astro:transitions';ו-<ViewTransitions />. - הוסיפו ב-CSS גלובלי את ה-reduced-motion fallback.
- ריצו
npm run devופתחו ב-Chrome. נווטו בין העמודים — יהיה cross-fade אוטומטי. - בחרו אלמנט בכל עמוד (למשל ה-
h1). הוסיפוtransition:name="page-title"בכל עמוד. עכשיו לוגו הכותרת "יזוז" בחלקות במעבר. - הוסיפו פיצ'ר מתקדם:
transition:persistעל video או audio player — הוא ימשיך לנגן בזמן המעבר. - בנו production build:
npm run build. בדקו את ה-output של HTML — שימו לב ש-Astro מוסיף polyfill קטן שעובד גם ב-Safari 17. - Deploy ל-Netlify/Vercel/Cloudflare Pages. בדקו על URL אמיתי ב-3 דפדפנים.
מה צריך להיות בסוף: אתר Astro עם View Transitions מובנים, URL חי להצגה, 3 screenshots מ-3 דפדפנים (Chrome, Safari, Firefox), ומסמך קצר שמתאר אילו פיצ'רים השתמשתם בהם (transition:name, transition:persist, ברירת-המחדל).
- קחו את כל הפרויקטים שיצרתם בתרגילים 1-3.
- הפעילו "Reduce motion" במערכת שלכם (macOS / Windows / iOS / Android — כל מה שיש לכם בהישג יד).
- עברו על כל פרויקט ובדקו: האם המעברים נעלמים? האם הניווט עדיין עובד? האם אין freeze או שגיאות?
- רשמו בטבלה: פרויקט | מעברים כבויים? | ניווט עובד? | שגיאות? | Status (PASS/FAIL).
- לכל FAIL — תקנו את ה-CSS. ודאו שכל
::view-transition-*מוגדר לבטל animation. - בדקו גם עם
prefers-reduced-motion: no-preference(ברירת-מחדל) שהאנימציות חוזרות. - הריצו Lighthouse Accessibility score — ודאו שה-score הוא 100/100 (reduced-motion הוא חלק מ-accessibility).
- צלמו 2 video clips קצרים (10 שניות כל אחד): (א) עם reduced-motion off, (ב) עם reduced-motion on.
- העלו את ה-clips ל-Loom או YouTube unlisted, ושמרו את הקישורים.
מה צריך להיות בסוף: טבלת audit של 3 פרויקטים × 5 עמודות, 2 video clips משווים (motion on/off), ו-Lighthouse Accessibility score של 100 בכל פרויקט.
| Context | Transition | Why |
|---|---|---|
| Site-wide navigation (home, about, services) | Cross-fade | ברירת-מחדל מתאימה. לא מסיח את הדעת. מתאים לכל עמוד. |
| E-commerce: list → product detail | Morph על תמונה + כותרת + מחיר | יוצר תחושת continuity. הגולש "עוקב" אחרי המוצר. |
| Blog: list → article | Morph על cover image בלבד | קונטקסט שהכתבה היא הרחבה של ה-thumbnail. |
| Wizard / Onboarding / Checkout steps | Slide (horizontal) | משדר "תהליך לינארי". הגולש יודע שמתקדם. |
| Dashboard: switching between sections | Cross-fade + persistent sidebar | Sidebar לא זז (view-transition-name: sidebar); main content מחליף. |
| Gallery: thumbnail → lightbox | Morph על התמונה יחידה | ה-"hero moment" הקלאסי. תמונה גדלה למסך מלא. |
| Modal open/close | Scale + fade (custom @keyframes) | Modal הוא לא "עמוד", אז cross-fade חלש מדי. Scale נותן תחושת "מגיע ממקום מסוים". |
| Form submission → success page | Cross-fade עם delay קצר | מעבר חלק, אבל לא דרמטי. המטרה: confirmation, לא וואו. |
| תדירות | מה לעשות | כמה זמן |
|---|---|---|
| יומי | גלשו ל-2 אתרים חדשים (מ-Awwwards, Muzli, או רשימה של daily inspiration). בדקו: האם יש להם View Transitions? אם כן — איזה סוג (cross-fade, morph, slide)? פתחו DevTools → Animations וצפו במעבר. אם לא — שאלו "איך הייתי מיישם morph פה?". | 5 דקות |
| שבועי | בנוסף לשגרה של פרקים 5-7 (Layout audit, Modern CSS check, Scroll animations): הוסיפו View Transition אחד לפרויקט אחד חי. או Cross-fade (5 דקות), או Morph על אלמנט אחד (20 דקות). בדקו ב-3 דפדפנים + reduced-motion. | 30 דקות |
| חודשי | עדכנו את ה-prompt templates האישיים שלכם ל-View Transitions. הוסיפו variations: wizard RTL, persistent sidebar, modal scale-fade. בדקו שה-Fallback Checklist עובד ב-100% בכל האתרים שלכם (Lighthouse + real devices). | 45 דקות |
הוסיפו את 3 השורות האלה לקובץ ה-CSS הגלובלי של הפרויקט הכי חשוב שלכם ברגע זה:
@view-transition { navigation: auto; } ::view-transition-old(root), ::view-transition-new(root) { animation-duration: 0.25s; } @media (prefers-reduced-motion: reduce) { ::view-transition-old(*), ::view-transition-new(*) { animation: none !important; } }.
זה הכל. 3 שורות, 2 דקות. האתר שלכם ירגיש מייד 40% יותר "אפליקציה" — בלי לגעת בשום דבר אחר. ה-morph transitions ו-slide transitions הם בונוסים שאפשר להוסיף בהמשך, אבל ה-cross-fade הבסיסי הוא ה-80/20. אם תעשו רק את זה — כבר קיפצתם קפיצה שנראית יחסית לאיפה שהיו 99% מאתרי AI באפריל 2026.
- מה ההבדל היסודי בין
@keyframesל-View Transitions API? תסבירו במשפט אחד. (רמז:@keyframesמניע אלמנט יחיד ממצב A ל-B; View Transitions מניע מעבר בין שני מצבי DOM שונים, כולל בין עמודים) - למה
view-transition-nameחייב להיות ייחודי בכל רגע נתון? (רמז: הדפדפן צריך להתאים אלמנט "לפני" ל-"אחרי"; אם יש שניים עם אותו שם, ההתאמה נכשלת בשקט והמעבר נשבר) - איך יודעים אם האתר שלכם הוא SPA או MPA, ולמה זה משנה ל-View Transitions? (רמז: SPA = ניווט בלי page reload, MPA = HTML חדש מהשרת; ל-SPA:
document.startViewTransition(); ל-MPA:@view-transition { navigation: auto }) - למה מומלץ לתייג רק 1-3 אלמנטים עם
view-transition-name? מה קורה עם 20? (רמז: קוגניטיבית העין לא יכולה לעקוב; 20 אלמנטים שזזים = כאוס ויזואלי; 2-3 = focal points ברורים) - מה עושה
prefers-reduced-motion: reduce, ולמה זה חובה ולא אופציונלי? (רמז: משתמשים עם motion sickness / accessibility needs; זו דרישת נגישות WCAG; 6 שורות CSS מספיקות לכיבוי כל ה-view transitions)
בפרק הזה סגרתם את הפער האחרון שהופך אתר ל"אתר" במקום ל"אפליקציה": מעברי עמודים חלקים. ראיתם שהמרחק בין השניים, שעד 2023 היה 200 שורות JavaScript וספריות חיצוניות, הוא היום 3 שורות CSS. למדתם שלושה סוגי מעברים בסיסיים — Cross-fade (ברירת-מחדל, 3 שורות), Morph (shared element transition כמו App Store), ו-Slide (wizard-style, עם התאמה ל-RTL).
הבנתם את ה-building blocks של ה-API: document.startViewTransition() כנקודת הכניסה ב-JavaScript ל-SPAs; view-transition-name כ-CSS property שמסמן אלמנט כמשתתף במעבר, עם הכלל הקריטי של ייחודיות; 7 ה-::view-transition-* pseudo-elements שמאפשרים לעצב כל שכבה של המעבר ב-CSS; ו-@view-transition { navigation: auto } השורה המופלאה שמפעילה מעברים בין עמודים באתר MPA בלי שורת JavaScript אחת.
בחלק השני של הפרק הבחנתם בין Same-document transitions (SPA — React, Vue, Next.js client-side) ל-Cross-document transitions (MPA — Astro, static sites, Next.js App Router, WordPress) — ההבדל המושגי החשוב ביותר לפרויקט שלכם. קיבלתם decision framework מדויק לבחירה בין השניים, וטבלת שילוב ב-6 frameworks: Astro (1 שורה, מובנה), Next.js 15 (component experimental), React Router v7 (prop על Link), SvelteKit/Vue (wrapper ידני), ו-vanilla HTML (1 שורה CSS).
למדתם את מצב התמיכה באפריל 2026 — Chrome/Edge/Safari מלא, Firefox בדרך — ואת הפילוסופיה של progressive enhancement: View Transitions לא שובר שום דבר, אם אין תמיכה מקבלים ניווט רגיל. בנוסף, פיצחתם 5 Gotchas ש-99% מהמפתחים נתקלים בהם (display: none שובר morph; שמות זהים; mobile Safari stutter; window.location.href לא מפעיל מעבר; iframes לא נתמכים).
הכי חשוב — למדתם את 3 ה-AI Prompt Templates שהופכים בקשה עמומה ("add smooth transitions") לקוד production-ready: (א) Cross-fade עם reduced-motion fallback; (ב) Morph בין list view ל-detail view עם view-transition-name דינמיים לפי product id; (ג) Slide RTL לwizard 3-שלבי עם זיהוי כיוון ניווט. הפרומפטים האלה הם המפתח — לא הקוד, אלא היכולת לבקש את הקוד הנכון.
יש לכם עכשיו 4 deliverables מוחשיים: Cross-fade demo עובד, Morph transition על כרטיס מוצר, Slide wizard עם RTL, ורשימת frameworks עם ה-setup המדויק לכל אחד. Plus — 3 AI prompts מאומתים, Fallback Checklist של 6 פריטים, ומילון של 10 מונחים חדשים.
הגשר לפרק הבא: עד עכשיו בנינו את השכבות הבאות — Layout (פרק 5), Modern CSS primitives (פרק 6), Scroll animations (פרק 7), Page transitions (פרק 8). האתר שלכם כבר מתנהג כמו אפליקציה. בפרק 9 — "Glassmorphism, Liquid Glass, Aurora UI ומגמות עיצוב מודרניות" — נעבור ל-שכבת האפקטים: backdrop-filter: blur() שיוצר זכוכית חלבית; Apple Liquid Glass — הטרנד המרכזי של 2025-2026 עם שכבות של feTurbulence ו-feSpecularLighting; Aurora UI ו-mesh gradients אנימטיים; ומתי Neubrutalism מתאים ומתי הוא פשוט מכוער. אחרי פרק 9 יהיו לכם את כל השכבות של אתר מקצועי מ-2026 — לא רק "עובד" אלא "מרגיש כמו שסטודיו בנה אותו". View Transitions שבניתם בפרק 8 ישמשו בפרק 13 (capstone) כחלק מ-design brief מלא שתעבירו ל-AI.
- הבנתי את ההבדל היסודי בין
@keyframes(אלמנט יחיד) ל-View Transitions (מעבר בין מצבי DOM שלמים) - יודע/ת להשתמש ב-
document.startViewTransition(() => updateDOM())בקוד SPA - יודע/ת להשתמש ב-
@view-transition { navigation: auto }לאתר MPA - מבין/ה את הכלל שכל
view-transition-nameחייב להיות ייחודי בכל רגע - הכרתי את 7 ה-
::view-transition-*pseudo-elements ויודע/ת לעצב את::view-transition-old/new - השלמתי תרגיל 1 — Cross-fade site-wide עם 3 עמודים
- השלמתי תרגיל 2 — Morph Transition על 4 כרטיסי מוצר + 4 עמודי פרטים
- השלמתי תרגיל 3 — Astro site עם
<ViewTransitions />מובנה, deployed ל-URL חי - השלמתי תרגיל 4 — Reduced-motion audit של 3 פרויקטים עם Lighthouse 100/100
- הוספתי
@media (prefers-reduced-motion: reduce)fallback לכל הפרויקטים שלי - בדקתי שהפרויקטים עובדים ב-Firefox ללא שבירה (progressive enhancement)
- יודע/ת להחליט בין Cross-fade / Morph / Slide לפי סוג ה-context (framework החלטה מסעיף 8.13)
- יש לי 3 AI Prompt Templates שמורים (Cross-fade, Morph, Slide) מוכנים להעתקה לפרויקט חדש
- ביצעתי את "Just One Thing" — הוספתי 3 שורות cross-fade לפרויקט הכי חשוב שלי
- מכיר/ה את 5 ה-Gotchas (
display:none, שמות כפולים, mobile Safari,window.location, iframes) ויודע/ת איך להימנע מהן