समस्या
क्रॉस-डॉक्यूमेंट व्यू ट्रांज़िशन, एक ही ऑरिजिन वाले नेविगेशन के दौरान दो पेजों के बीच एलिमेंट को ऐनिमेट करते हैं. ब्राउज़र, पुराने पेज का स्नैपशॉट कैप्चर करता है, नेविगेट करता है, और फिर स्नैपशॉट से नए पेज पर ऐनिमेशन दिखाता है. अगर नए पेज पर ज़रूरी रिसॉर्स लोड नहीं हुए हैं, तो ट्रांज़िशन अधूरा या बिना स्टाइल वाला दिखेगा. इन रिसॉर्स में स्टाइलशीट, लेआउट स्क्रिप्ट या मुख्य डीओएम एलिमेंट शामिल हैं. इसकी वजह से, विज़ुअल से जुड़ी गड़बड़ियां होती हैं. जैसे, एलिमेंट का गलत जगहों पर दिखना, ऐनिमेशन के बीच में कॉन्टेंट का फिर से फ़्लो होना या ट्रांज़िशन पूरा होने के बाद, फ़ॉलबैक फ़ॉन्ट का वेब फ़ॉन्ट में फ़्लैश होना.
समस्या का हल
नए पेज के <head> में, ज़रूरी <link> और <script> एलिमेंट पर blocking="render" का इस्तेमाल करें. साथ ही, रेंडरिंग को तब तक ब्लॉक करने के लिए <link rel="expect"> का इस्तेमाल करें, जब तक कि कुछ खास डीओएम एलिमेंट को पार्स न कर लिया जाए. इससे यह पक्का होता है कि ब्राउज़र, व्यू ट्रांज़िशन ऐनिमेशन तब तक शुरू न करे, जब तक नए पेज की विज़ुअल स्थिति स्थिर न हो जाए. ब्राउज़र, बैकग्राउंड में एचटीएमएल को पार्स करना जारी रखता है — सिर्फ़ पेंटिंग को रोक दिया जाता है.
लागू करने की रणनीति
- ज़रूरी: दोनों पेजों पर
@view-transitionसीएसएस ऐट-रूल की मदद से, क्रॉस-डॉक्यूमेंट व्यू ट्रांज़िशन के लिए शामिल हों. - ज़रूरी: पक्का करें कि ज़रूरी स्टाइलशीट,
<head>में हों.<head>में मौजूद स्टाइलशीट, डिफ़ॉल्ट रूप से रेंडर-ब्लॉकिंग होती हैं. डाइनैमिक तरीके से इंजेक्ट की गई स्टाइलशीट के लिए, साफ़ तौर परblocking="render"की ज़रूरत होती है. blocking="render"का इस्तेमाल उन<script>एलिमेंट पर करें जिन्हें ट्रांज़िशन ऐनिमेशन से पहले लागू करना ज़रूरी है. उदाहरण के लिए, ऐसी स्क्रिप्ट जो थीम लागू करती हैं या लेआउट पर असर डालती हैं.- ज़रूर करें:
<link rel="expect" href="#element-id" blocking="render">का इस्तेमाल करके, रेंडरिंग को तब तक ब्लॉक करें, जब तक पेज के ऊपरी हिस्से में मौजूद कॉन्टेंट को पार्स न कर लिया जाए. यह सभी तरह के ट्रांज़िशन पर लागू होता है: फ़ुल-पेज क्रॉस-फ़ेड (खाली पेज पर ऐनिमेशन दिखाने से बचने के लिए), मॉर्फ़ ऐनिमेशन (यह पक्का करने के लिए कि नाम वाले एलिमेंट, डीओएम में मौजूद हों), और स्क्रिप्ट पर निर्भर लेआउट (यह पक्का करने के लिए कि स्टाइल किए गए कॉन्टेंट को पार्स किया गया हो). - गैर-ज़रूरी कॉन्टेंट को रेंडर होने से न रोकें. सिर्फ़ उन रिसॉर्स और एलिमेंट को ब्लॉक करें जो शुरुआती व्यूपोर्ट पर असर डालते हैं. बहुत ज़्यादा कॉन्टेंट को ब्लॉक करने से, ट्रांज़िशन में देरी होती है और परफ़ॉर्मेंस खराब होती है.
लागू करने के बारे में जानकारी
पहला चरण: क्रॉस-डॉक्यूमेंट व्यू ट्रांज़िशन के लिए ऑप्ट इन करना
ज़रूरी: सोर्स और डेस्टिनेशन, दोनों पेजों में @view-transition ऐट-रूल शामिल होना चाहिए. इसके बिना, एक से दूसरे दस्तावेज़ पर ट्रांज़िशन नहीं होता.
/*
MANDATORY: Include this rule in every page that participates
in cross-document view transitions.
`navigation: auto` enables transitions for standard navigations
(link clicks, form submissions, back/forward).
*/
@view-transition {
navigation: auto;
}
/* MANDATORY Copy-Paste Safety: Disable cross-document view transitions for users requesting reduced motion */
@media (prefers-reduced-motion: reduce) {
@view-transition {
navigation: none;
}
}
दूसरा चरण: ज़रूरी स्क्रिप्ट के लागू होने तक रेंडरिंग को ब्लॉक करना
अगर <head> में मौजूद नॉन-ब्लॉकिंग स्क्रिप्ट को ट्रांज़िशन ऐनिमेशन से पहले चलाना ज़रूरी है (उदाहरण के लिए, थीम क्लास लागू करने या लेआउट पर असर डालने के लिए), तो उसे blocking="render" से मार्क करें. इसके बिना, async, defer या type="module" स्क्रिप्ट, ट्रांज़िशन शुरू होने के बाद एक्ज़ीक्यूट हो सकती हैं.
<head>
<!--
DO: Mark layout-critical scripts with blocking="render".
-->
<script type=module blocking="render">
// Example: apply a stored theme before the page renders,
// so the transition snapshot reflects the correct theme.
document.documentElement.dataset.theme =
localStorage.getItem('theme') || 'light';
</script>
</head>
तीसरा चरण: मुख्य डीओएम एलिमेंट पार्स होने तक रेंडरिंग को ब्लॉक करना
<head> में मौजूद स्टाइलशीट और blocking="render" स्क्रिप्ट से सिर्फ़ यह गारंटी मिलती है कि <head> को पूरी तरह से प्रोसेस कर लिया गया है. वे किसी भी <body> कॉन्टेंट के पार्स होने का इंतज़ार नहीं करते. अगर अतिरिक्त ब्लॉकिंग नहीं की जाती है, तो हो सकता है कि ब्राउज़र, डीओएम में पेज के फ़ोल्ड के ऊपर मौजूद एलिमेंट के दिखने से पहले ही नए पेज का स्नैपशॉट ले ले. इससे ट्रांज़िशन के दौरान, खाली या अधूरा रेंडर किया गया पेज दिखेगा.
<link rel="expect">, रेंडरिंग को तब तक ब्लॉक करके इस समस्या को हल करता है, जब तक कि किसी खास एलिमेंट (इसकी पहचान id से की जाती है) को पार्स नहीं कर लिया जाता. href वैल्यू, फ़्रैगमेंट आइडेंटिफ़ायर (जैसे, #hero) होनी चाहिए. यह वैल्यू, टारगेट एलिमेंट के id एट्रिब्यूट से मैच होनी चाहिए. उस एलिमेंट के क्लोज़िंग टैग को पार्स करने के बाद, रेंडर ब्लॉक को रिलीज़ कर दिया जाता है. ध्यान दें कि <link rel="expect"> सिर्फ़ यह गारंटी देता है कि टारगेट डीओएम एलिमेंट, दस्तावेज़ में मौजूद है. यह बाहरी सब-रिसोर्स (जैसे, <img> पिक्सल) के डाउनलोड या डिकोड होने का इंतज़ार नहीं करता.
इन सभी स्थितियों में <link rel="expect"> का इस्तेमाल करें:
इस्तेमाल का पहला उदाहरण: पूरे पेज पर क्रॉस-फ़ेड इफ़ेक्ट
अगर किसी भी एलिमेंट में view-transition-name नहीं है, तो भी डिफ़ॉल्ट root ट्रांज़िशन, पूरे पेज को क्रॉस-फ़ेड कर देता है. अगर नए पेज का स्नैपशॉट, पेज के सबसे ऊपर दिखने वाले कॉन्टेंट को पार्स करने से पहले लिया जाता है, तो क्रॉस-फ़ेड ऐनिमेशन, पुराने पेज से खाली या अधूरे पेज पर ले जाता है. पेज के ऊपरी हिस्से में दिखने वाले कॉन्टेंट के आखिर में मौजूद एलिमेंट को रेंडर होने से रोकना.
<head>
<link rel="stylesheet" href="/css/styles.css">
<!--
DO: Block rendering until the main content area is parsed,
even for a simple cross-fade. Without this, the browser may
snapshot the page before visible content exists in the DOM,
causing the cross-fade to reveal a blank or partial page.
-->
<link rel="expect" href="#main-content" blocking="render">
</head>
<body>
<header>...</header>
<main id="main-content">
<h1>Page Title</h1>
<p>Above-the-fold content the user should see immediately.</p>
</main>
<!-- Content below the fold does NOT need to be blocked on -->
<section>...</section>
</body>
इस्तेमाल का दूसरा उदाहरण: कुछ खास एलिमेंट के बीच मॉर्फ़ ऐनिमेशन का इस्तेमाल करना
जब दोनों पेजों पर मौजूद एलिमेंट एक ही view-transition-name शेयर करते हैं, तब ब्राउज़र उन्हें नेविगेशन के दौरान आसानी से मॉर्फ़ कर देता है. अगर ट्रांज़िशन शुरू होने पर टारगेट एलिमेंट को पार्स नहीं किया गया है, तो ब्राउज़र उसे नहीं ढूंढ पाएगा. ऐसे में, मॉर्फ़ इफ़ेक्ट, एग्ज़िट और एंट्री ऐनिमेशन को अलग-अलग कर देता है. view-transition-name वाले एलिमेंट को पार्स किए जाने तक, रेंडरिंग को ब्लॉक करें.
<link rel="expect"> सिर्फ़ तब तक रेंडरिंग को रोकता है, जब तक टारगेट डीओएम एलिमेंट को पार्स नहीं कर लिया जाता. साथ ही, यह इमेज डेटा के डाउनलोड या डिकोड होने का इंतज़ार नहीं करता. इसलिए, कैश मेमोरी में सेव नहीं किए गए <img> को नए पेज के स्नैपशॉट में खाली रेक्टैंगल के तौर पर कैप्चर किया जा सकता है. इमेज मॉर्फ़ के दौरान खाली स्नैपशॉट या लेआउट शिफ़्ट होने से रोकने के लिए, ट्रांज़िशन वाली ज़रूरी इमेज को पहले से लोड या डिकोड करें. उदाहरण के लिए, <link rel="preload" as="image"> का इस्तेमाल करके या डेस्टिनेशन पेज को प्रीरेंडर करके. साथ ही, साइज़ के लिए साफ़ तौर पर फ़ॉलबैक दें. जैसे, width और height एट्रिब्यूट या सीएसएस aspect-ratio के साथ-साथ प्लेसहोल्डर का बैकग्राउंड कलर.
<head>
<link rel="stylesheet" href="/css/styles.css">
<!--
DO: Preload critical transition images so their pixels are
available to decode before the new-page snapshot is captured.
<link rel="expect"> only waits for the DOM element to be parsed,
NOT for image pixels to download or decode.
-->
<link rel="preload" as="image" href="/img/product.webp" fetchpriority="high">
<!--
DO: Block rendering until the element participating in the
morph animation has been parsed. Without this, the browser
may start the transition before #hero exists, causing the
morph to degrade to a fade-out/fade-in.
-->
<link rel="expect" href="#hero" blocking="render">
<!--
When multiple blocking="render" resources are present,
rendering is blocked until ALL of them are satisfied.
Here, the browser waits for both the script to execute
AND the #hero element to be parsed — whichever comes last.
-->
<script async blocking="render" src="/js/transition-setup.js"></script>
</head>
<body>
<header>...</header>
<section id="hero">
<h1 style="view-transition-name: page-title">Product Name</h1>
<!--
DO: Provide explicit dimensions (width/height or aspect-ratio)
as a sizing fallback so the snapshot captures the correct layout
box even if image decoding is still in progress.
-->
<img
style="view-transition-name: hero-image"
src="/img/product.webp"
width="800"
height="600"
alt="Product"
>
</section>
</body>
चौथा चरण: रिस्पॉन्सिव रेंडर ब्लॉकिंग के लिए मीडिया क्वेरी का इस्तेमाल करना
अलग-अलग व्यूपोर्ट साइज़ के हिसाब से, पेज के फ़ोल्ड के ऊपर अलग-अलग मात्रा में कॉन्टेंट दिख सकता है. <link rel="expect"> पर media एट्रिब्यूट का इस्तेमाल करें, ताकि सिर्फ़ व्यूपोर्ट की दी गई चौड़ाई पर दिखने वाले कॉन्टेंट को रेंडर होने से रोका जा सके.
<head>
<!--
DO: Use media queries to conditionally block rendering.
On wide screens, both the hero and the sidebar are visible,
so block until both are parsed. On narrow screens, only the
hero is visible initially.
-->
<link
rel="expect"
href="#hero"
blocking="render"
media="screen and (width <= 768px)"
>
<link
rel="expect"
href="#sidebar"
blocking="render"
media="screen and (width > 768px)"
>
</head>
पांचवां चरण: कॉन्टेक्स्ट के हिसाब से ट्रांज़िशन के लिए, pagereveal का इस्तेमाल करना (ज़रूरी नहीं)
pagereveal इवेंट, रेंडर-ब्लॉकिंग की मुख्य रणनीति के लिए ज़रूरी नहीं है. इसकी ज़रूरत सिर्फ़ तब होती है, जब view-transition-name वैल्यू को डाइनैमिक तौर पर असाइन करना हो. ऐसा इस आधार पर किया जाता है कि उपयोगकर्ता ने कहां से नेविगेट किया है. उदाहरण के लिए, सूची के किसी आइटम को ज़्यादा जानकारी वाले पेज के हेडिंग में बदलना.
अगर सीएसएस में view-transition-name वैल्यू को स्टैटिक तौर पर असाइन किया गया है या सिर्फ़ डिफ़ॉल्ट फ़ुल-पेज क्रॉस-फ़ेड का इस्तेमाल किया जा रहा है, तो इस चरण को पूरी तरह से छोड़ दें.
<head>
<!--
MANDATORY: The pagereveal listener must be registered before
the page renders. Inline small setup scripts with blocking="render"
to avoid an extra network round-trip on cold loads, or use an
external async script with blocking="render" so the listener is
registered early without blocking HTML parsing.
If the listener is registered too late (e.g., in a deferred
script), the event may have already fired.
-->
<script async blocking="render" src="/js/transition-setup.js"></script>
</head>
// transition-setup.js
window.addEventListener('pagereveal', async (event) => {
if (!event.viewTransition) return;
const from = navigation.activation?.from;
if (!from) return;
const fromUrl = new URL(from.url);
// DO: Assign view-transition-name based on navigation context.
// This enables a morph animation from the product card on the
// list page to the heading on the detail page.
if (fromUrl.pathname === '/products/') {
const heading = document.querySelector('main h1');
if (!heading) return;
heading.style.viewTransitionName = 'product-title';
try {
await event.viewTransition.ready;
} catch (error) {
// Skipped view transitions reject `ready` with InvalidStateError.
if (error.name !== 'InvalidStateError') {
throw error;
}
} finally {
// MANDATORY: Remove the temporary name after the transition
// finishes. Stale names interfere with subsequent navigations
// and prevent the page from entering the bfcache.
await event.viewTransition.finished;
heading.style.viewTransitionName = '';
}
}
});
सबसे सही तरीके
- जब भी संभव हो, सीएसएस की मदद से
view-transition-nameअसाइन करें. JavaScript असाइनमेंट (pagerevealके ज़रिए) को उन मामलों के लिए रिज़र्व करें जहां नाम, नेविगेशन के संदर्भ पर निर्भर करता है. - DO रेंडर-ब्लॉकिंग स्क्रिप्ट को छोटा और तेज़ रखें. ब्राउज़र में पहले से तय टाइम आउट (करीब चार सेकंड) होता है. इसके बाद, ट्रांज़िशन को पूरी तरह से स्किप कर दिया जाता है. अगर ट्रांज़िशन शुरू किया गया था, तो
viewTransition.readyकोInvalidStateErrorके साथ अस्वीकार कर दिया जाता है. - पेज के अंदर मौजूद उन एलिमेंट को ब्लॉक करने के लिए
<link rel="expect">का इस्तेमाल न करें जो शुरुआती व्यूपोर्ट में नहीं दिखते. इससे ट्रांज़िशन में देरी होती है और कोई विज़ुअल फ़ायदा भी नहीं मिलता. - भूलकर भी ऐनलिटिक्स, विज्ञापन नेटवर्क कंपनी, Tag Manager या तीसरे पक्ष के अन्य लोडर को
blocking="render"के तौर पर मार्क न करें. भले ही, वे शुरुआती व्यूपोर्ट में कॉन्टेंट इंजेक्ट करते हों. उनके नेटवर्क की इंतज़ार का समय, ट्रांज़िशन टाइम आउट में गिना जाता है. साथ ही, उनका आउटपुट पेज की स्टेबल स्टेट का हिस्सा नहीं होता. - एक ही पेज पर मौजूद कई एलिमेंट को एक ही
view-transition-nameअसाइन न करें. डुप्लीकेट नाम होने पर, पूरा ट्रांज़िशन स्किप हो जाता है. - सहायक टेक्नोलॉजी की टाइमिंग का असर:
blocking="render"का इस्तेमाल करने से, विज़ुअल अपडेट और शुरुआती पेंट में देरी होती है. इससे, देखने में सक्षम उपयोगकर्ताओं को विज़ुअल से जुड़ी गड़बड़ियां नहीं दिखती हैं. हालांकि, इससे स्क्रीन रीडर और अन्य सहायक टेक्नोलॉजी के लिए, प्रोसेसिंग में देरी हो सकती है या उन्हें शुरू होने में ज़्यादा समय लग सकता है. ये टेक्नोलॉजी, रेंडर किए गए सुलभता ट्री पर निर्भर करती हैं. विज़ुअल कॉन्टेंट को लगातार दिखाने के फ़ायदों की तुलना, विज़ुअल कॉन्टेंट न देख पाने वाले उपयोगकर्ताओं के लिए, शुरुआती रीड लेटेंसी से करें. साथ ही, पक्का करें कि रेंडर-ब्लॉकिंग स्क्रिप्ट कम से कम हों और उन्हें बेहतर तरीके से ऑप्टिमाइज़ किया गया हो.
फ़ॉलबैक रणनीतियां
क्रॉस-डॉक्यूमेंट व्यू ट्रांज़िशन, परतदार वृद्धि के लिए एक बेहतरीन विकल्प है. जिन ब्राउज़र में यह सुविधा काम नहीं करती उनमें @view-transition नियम को अनदेखा कर दिया जाता है. साथ ही, स्टैंडर्ड सेम-ऑरिजिन नेविगेशन ठीक उसी तरह होता है जैसे इस सुविधा के बिना होता. इस सुविधा के साथ काम करने वाले ब्राउज़र पर, ट्रांज़िशन आसानी से दिखते हैं. वहीं, अन्य ब्राउज़र पर स्टैंडर्ड नेविगेशन दिखता है. ब्राउज़र में सीमित सहायता मिलने की वजह से, इसे अपनाने से बचना नहीं चाहिए.
क्रॉस-डॉक्यूमेंट व्यू ट्रांज़िशन के साथ काम करने वाले सभी ब्राउज़र, blocking="render" और <link rel="expect"> के साथ भी काम करते हैं. इसलिए, इस गाइड में बताई गई रेंडर-ब्लॉकिंग सुविधाओं के लिए, अलग से फ़ॉलबैक की ज़रूरत नहीं होती.
ध्यान में रखने लायक अन्य बातें
- परफ़ॉर्मेंस पर असर: रेंडर-ब्लॉकिंग रिसॉर्स की वजह से, व्यू ट्रांज़िशन ऐनिमेशन शुरू होने में देरी होती है. रेंडर-ब्लॉकिंग स्क्रिप्ट की संख्या कम से कम रखें. साथ ही,
<link rel="expect">का इस्तेमाल सिर्फ़ उन एलिमेंट के लिए करें जो पेज के ऊपरी हिस्से में मौजूद हैं. Speculation Rules API का इस्तेमाल करके, डेस्टिनेशन पेजों को प्रीरेंडर करें, ताकि पेज लोड होने में लगने वाले समय को पूरी तरह से खत्म किया जा सके. - टाइम आउट होने पर क्या होता है: अगर रेंडर-ब्लॉकिंग का कुल समय करीब चार सेकंड से ज़्यादा हो जाता है, तो ब्राउज़र ट्रांज़िशन को स्किप कर देता है. साथ ही, कोई भी चालू
viewTransition.readyप्रॉमिस,InvalidStateErrorके साथ अस्वीकार हो जाता है. पक्का करें कि ज़रूरी संसाधन इस विंडो के अंदर ही लोड हो जाएं. - बीएफ़कैश के साथ काम करना: ट्रांज़िशन के बाद, कुछ समय के लिए असाइन किए गए
view-transition-nameको न हटाने पर, पेज को बीएफ़कैश में सेव होने से रोका जा सकता है.finishedकॉलबैक में, डाइनैमिक तौर पर असाइन किए गए नाम हमेशा हटाएं.