जब दो अलग-अलग दस्तावेज़ों के बीच व्यू ट्रांज़िशन होता है, तो इसे क्रॉस-डॉक्यूमेंट व्यू ट्रांज़िशन कहा जाता है. आम तौर पर, ऐसा मल्टी-पेज ऐप्लिकेशन (एमपीए) में होता है. Chrome 126 से, Chrome में क्रॉस-डॉक्यूमेंट व्यू ट्रांज़िशन की सुविधा उपलब्ध है.
क्रॉस-डॉक्यूमेंट व्यू ट्रांज़िशन, एक ही दस्तावेज़ में व्यू ट्रांज़िशन के लिए इस्तेमाल किए जाने वाले बिल्डिंग ब्लॉक और सिद्धांतों पर आधारित होते हैं. ऐसा जान-बूझकर किया गया है:
- ब्राउज़र, उन एलिमेंट के स्नैपशॉट लेता है जिनमें पुराने और नए, दोनों पेजों पर यूनीक
view-transition-nameहोता है. - रेंडरिंग बंद होने पर, DOM अपडेट हो जाता है.
- आखिर में, ट्रांज़िशन को सीएसएस ऐनिमेशन की मदद से बनाया जाता है.
एक ही दस्तावेज़ में व्यू ट्रांज़िशन की तुलना में, अलग-अलग दस्तावेज़ों में व्यू ट्रांज़िशन की सुविधा में यह अंतर है कि व्यू ट्रांज़िशन शुरू करने के लिए, आपको document.startViewTransition को कॉल करने की ज़रूरत नहीं होती. इसके बजाय, क्रॉस-डॉक्यूमेंट व्यू ट्रांज़िशन के लिए ट्रिगर, एक पेज से दूसरे पेज पर एक ही ऑरिजिन से नेविगेट करना होता है. यह ऐसी कार्रवाई है जो आम तौर पर आपकी वेबसाइट का उपयोगकर्ता, किसी लिंक पर क्लिक करके करता है.
दूसरे शब्दों में कहें, तो दो दस्तावेज़ों के बीच व्यू ट्रांज़िशन शुरू करने के लिए, कॉल करने के लिए कोई एपीआई नहीं है. हालांकि, इसके लिए दो शर्तें पूरी होनी चाहिए:
- दोनों दस्तावेज़ एक ही ऑरिजिन पर मौजूद होने चाहिए.
- व्यू ट्रांज़िशन की सुविधा का इस्तेमाल करने के लिए, दोनों पेजों को ऑप्ट-इन करना होगा.
इन दोनों शर्तों के बारे में, इस दस्तावेज़ में बाद में बताया गया है.
अलग-अलग दस्तावेज़ों के बीच व्यू ट्रांज़िशन, सिर्फ़ एक ही ऑरिजिन से नेविगेट करने पर काम करते हैं
एक दस्तावेज़ से दूसरे दस्तावेज़ पर व्यू ट्रांज़िशन की सुविधा, सिर्फ़ एक ही ऑरिजिन से नेविगेट करने पर काम करती है. अगर नेविगेशन में शामिल दोनों पेजों का ऑरिजिन एक ही है, तो उसे सेम-ऑरिजिन नेविगेशन माना जाता है.
किसी पेज का ऑरिजिन, इस्तेमाल की गई स्कीम, होस्टनेम, और पोर्ट का कॉम्बिनेशन होता है. इसके बारे में web.dev पर ज़्यादा जानकारी दी गई है.
उदाहरण के लिए, developer.chrome.com से developer.chrome.com/blog पर नेविगेट करते समय, आपके पास क्रॉस-डॉक्यूमेंट व्यू ट्रांज़िशन हो सकता है, क्योंकि ये दोनों एक ही ऑरिजिन के हैं.
developer.chrome.com से www.chrome.com पर नेविगेट करते समय, आपको वह ट्रांज़िशन नहीं मिलेगा. ऐसा इसलिए, क्योंकि वे क्रॉस-ऑरिजिन और एक ही साइट के हैं.
क्रॉस-डॉक्यूमेंट व्यू ट्रांज़िशन के लिए ऑप्ट-इन करना ज़रूरी है
दो दस्तावेज़ों के बीच क्रॉस-डॉक्यूमेंट व्यू ट्रांज़िशन की सुविधा का इस्तेमाल करने के लिए, दोनों पेजों को इस सुविधा के लिए ऑप्ट-इन करना होगा. इसके लिए, सीएसएस में @view-transition ऐट-रूल का इस्तेमाल किया जाता है.
क्रॉस-डॉक्यूमेंट और एक ही ऑरिजिन से नेविगेट करने के लिए व्यू ट्रांज़िशन चालू करने के लिए, @view-transition at-rule में navigation डिस्क्रिप्टर को auto पर सेट करें.
@view-transition {
navigation: auto;
}
navigation डेस्क्रिप्टर को auto पर सेट करके, आपने इन NavigationType के लिए व्यू ट्रांज़िशन की अनुमति दी है:
traversepushयाreplace, अगर ब्राउज़र के यूज़र इंटरफ़ेस (यूआई) के ज़रिए उपयोगकर्ता ने इसे चालू नहीं किया है.
auto में शामिल न की गई नेविगेशन के उदाहरण के तौर पर, यूआरएल पता बार का इस्तेमाल करके नेविगेट करना या किसी बुकमार्क पर क्लिक करना शामिल है. इसके अलावा, उपयोगकर्ता या स्क्रिप्ट की ओर से शुरू किया गया रीलोड भी शामिल है.
अगर नेविगेशन में ज़्यादा समय लगता है, तो व्यू ट्रांज़िशन को TimeoutError DOMException के साथ स्किप कर दिया जाता है. Chrome के मामले में, यह समय चार सेकंड से ज़्यादा होता है.
क्रॉस-डॉक्यूमेंट व्यू ट्रांज़िशन का डेमो
यहां दिए गए डेमो में, व्यू ट्रांज़िशन का इस्तेमाल करके स्टैक नेविगेटर का डेमो बनाया गया है. इसे देखें. यहां document.startViewTransition() को कोई कॉल नहीं किया गया है. व्यू ट्रांज़िशन, एक पेज से दूसरे पेज पर नेविगेट करने पर ट्रिगर होते हैं.
दस्तावेज़ों के बीच व्यू ट्रांज़िशन को पसंद के मुताबिक बनाना
क्रॉस-डॉक्यूमेंट व्यू ट्रांज़िशन को पसंद के मुताबिक बनाने के लिए, वेब प्लैटफ़ॉर्म की कुछ सुविधाओं का इस्तेमाल किया जा सकता है.
ये सुविधाएं, View Transition API के स्पेसिफ़िकेशन का हिस्सा नहीं हैं. हालांकि, इन्हें इसके साथ इस्तेमाल करने के लिए डिज़ाइन किया गया है.
pageswap और pagereveal इवेंट
आपको अलग-अलग दस्तावेज़ों के बीच व्यू ट्रांज़िशन को पसंद के मुताबिक बनाने की अनुमति देने के लिए, एचटीएमएल स्पेसिफ़िकेशन में दो नए इवेंट शामिल किए गए हैं. इनका इस्तेमाल किया जा सकता है: pageswap और pagereveal.
ये दोनों इवेंट, एक ही ऑरिजिन के क्रॉस-डॉक्यूमेंट नेविगेशन के लिए ट्रिगर होते हैं. भले ही, व्यू ट्रांज़िशन होने वाला हो या नहीं. अगर दो पेजों के बीच व्यू ट्रांज़िशन होने वाला है, तो इन इवेंट पर मौजूद viewTransition प्रॉपर्टी का इस्तेमाल करके, ViewTransition ऑब्जेक्ट को ऐक्सेस किया जा सकता है.
pageswapइवेंट, पेज का आखिरी फ़्रेम रेंडर होने से पहले ट्रिगर होता है. इसका इस्तेमाल, आउटगोइंग पेज पर आखिरी समय में कुछ बदलाव करने के लिए किया जा सकता है. ऐसा पुराने स्नैपशॉट लिए जाने से ठीक पहले किया जाता है.pagerevealइवेंट, पेज पर तब फ़ायर होता है, जब पेज को शुरू या फिर से चालू कर दिया जाता है. हालांकि, यह इवेंट पहली रेंडरिंग से पहले फ़ायर होता है. इसकी मदद से, नए स्नैपशॉट लिए जाने से पहले, नए पेज को अपनी पसंद के मुताबिक बनाया जा सकता है.
उदाहरण के लिए, इन इवेंट का इस्तेमाल करके, कुछ view-transition-name वैल्यू को तुरंत सेट या बदला जा सकता है. इसके अलावा, sessionStorage से डेटा लिखकर और पढ़कर, एक दस्तावेज़ से दूसरे दस्तावेज़ में डेटा पास किया जा सकता है. इससे व्यू ट्रांज़िशन को रन होने से पहले पसंद के मुताबिक बनाया जा सकता है.
let lastClickX, lastClickY;
document.addEventListener('click', (event) => {
if (event.target.tagName.toLowerCase() === 'a') return;
lastClickX = event.clientX;
lastClickY = event.clientY;
});
// Write position to storage on old page
window.addEventListener('pageswap', (event) => {
if (event.viewTransition && lastClick) {
sessionStorage.setItem('lastClickX', lastClickX);
sessionStorage.setItem('lastClickY', lastClickY);
}
});
// Read position from storage on new page
window.addEventListener('pagereveal', (event) => {
if (event.viewTransition) {
lastClickX = sessionStorage.getItem('lastClickX');
lastClickY = sessionStorage.getItem('lastClickY');
}
});
अगर आपको लगता है कि दोनों इवेंट में ट्रांज़िशन नहीं होना चाहिए, तो ट्रांज़िशन को स्किप किया जा सकता है.
window.addEventListener("pagereveal", async (e) => {
if (e.viewTransition) {
if (goodReasonToSkipTheViewTransition()) {
e.viewTransition.skipTransition();
}
}
}
pageswap और pagereveal में मौजूद ViewTransition ऑब्जेक्ट, दो अलग-अलग ऑब्जेक्ट हैं. ये अलग-अलग वादों को भी अलग-अलग तरीके से पूरा करते हैं:
pageswap: दस्तावेज़ छिपाने के बाद, पुरानेViewTransitionऑब्जेक्ट को छोड़ दिया जाता है. ऐसा होने पर,viewTransition.readyअस्वीकार कर देता है औरviewTransition.finishedहल कर देता है.pagereveal: इस समय तक,updateCallBackप्रॉमिस पहले ही पूरा हो चुका है.viewTransition.readyऔरviewTransition.finishedके वादों का इस्तेमाल किया जा सकता है.
नेविगेशन की सुविधा चालू करने की जानकारी
pageswap और pagereveal, दोनों तरह के इवेंट में, पुराने और नए पेजों के यूआरएल के आधार पर भी कार्रवाई की जा सकती है.
उदाहरण के लिए, MPA स्टैक नेविगेटर में, इस्तेमाल किए जाने वाले ऐनिमेशन का टाइप, नेविगेशन पाथ पर निर्भर करता है:
- खास जानकारी वाले पेज से ज़्यादा जानकारी वाले पेज पर जाते समय, नया कॉन्टेंट दाईं ओर से बाईं ओर स्लाइड होना चाहिए.
- ज़्यादा जानकारी वाले पेज से खास जानकारी वाले पेज पर जाते समय, पुराने कॉन्टेंट को बाईं ओर से दाईं ओर स्लाइड होना चाहिए.
इसके लिए, आपको नेविगेशन के बारे में जानकारी चाहिए. pageswap के मामले में, यह जानकारी उस नेविगेशन के बारे में होती है जो होने वाला है. वहीं, pagereveal के मामले में, यह जानकारी उस नेविगेशन के बारे में होती है जो अभी-अभी हुआ है.
इसके लिए, ब्राउज़र अब NavigationActivation ऑब्जेक्ट दिखा सकते हैं. इनमें एक ही ऑरिजिन से नेविगेट करने के बारे में जानकारी होती है. यह ऑब्जेक्ट, इस्तेमाल किए गए नेविगेशन टाइप, मौजूदा, और फ़ाइनल डेस्टिनेशन के इतिहास की एंट्री दिखाता है. ये एंट्री, नेविगेशन एपीआई से मिले navigation.entries() में मौजूद होती हैं.
चालू किए गए पेज पर, navigation.activation के ज़रिए इस ऑब्जेक्ट को ऐक्सेस किया जा सकता है. pageswap इवेंट में, इसे e.activation के ज़रिए ऐक्सेस किया जा सकता है.
प्रोफ़ाइल के इस डेमो को देखें. इसमें pageswap और pagereveal इवेंट में NavigationActivation की जानकारी का इस्तेमाल किया गया है. इससे उन एलिमेंट पर view-transition-name की वैल्यू सेट की जा सकती हैं जिन्हें व्यू ट्रांज़िशन में शामिल होना है.
इस तरह, आपको सूची में मौजूद हर आइटम के लिए, पहले से ही view-transition-name एट्रिब्यूट की वैल्यू देने की ज़रूरत नहीं होती. इसके बजाय, यह JavaScript का इस्तेमाल करके सिर्फ़ उन एलिमेंट पर किया जाता है जिनकी ज़रूरत होती है.
कोड यहां दिया गया है:
// OLD PAGE LOGIC
window.addEventListener('pageswap', async (e) => {
if (e.viewTransition) {
const targetUrl = new URL(e.activation.entry.url);
// Navigating to a profile page
if (isProfilePage(targetUrl)) {
const profile = extractProfileNameFromUrl(targetUrl);
// Set view-transition-name values on the clicked row
document.querySelector(`#${profile} span`).style.viewTransitionName = 'name';
document.querySelector(`#${profile} img`).style.viewTransitionName = 'avatar';
// Remove view-transition-names after snapshots have been taken
// (this to deal with BFCache)
await e.viewTransition.finished;
document.querySelector(`#${profile} span`).style.viewTransitionName = 'none';
document.querySelector(`#${profile} img`).style.viewTransitionName = 'none';
}
}
});
// NEW PAGE LOGIC
window.addEventListener('pagereveal', async (e) => {
if (e.viewTransition) {
const fromURL = new URL(navigation.activation.from.url);
const currentURL = new URL(navigation.activation.entry.url);
// Navigating from a profile page back to the homepage
if (isProfilePage(fromURL) && isHomePage(currentURL)) {
const profile = extractProfileNameFromUrl(currentURL);
// Set view-transition-name values on the elements in the list
document.querySelector(`#${profile} span`).style.viewTransitionName = 'name';
document.querySelector(`#${profile} img`).style.viewTransitionName = 'avatar';
// Remove names after snapshots have been taken
// so that we're ready for the next navigation
await e.viewTransition.ready;
document.querySelector(`#${profile} span`).style.viewTransitionName = 'none';
document.querySelector(`#${profile} img`).style.viewTransitionName = 'none';
}
}
});
व्यू ट्रांज़िशन के चलने के बाद, कोड view-transition-name वैल्यू को हटाकर खुद को भी साफ़ कर लेता है. इस तरह, पेज को लगातार नेविगेशन के लिए तैयार किया जाता है. साथ ही, यह इतिहास को भी मैनेज कर सकता है.
इसके लिए, इस यूटिलिटी फ़ंक्शन का इस्तेमाल करें. यह फ़ंक्शन, view-transition-name को कुछ समय के लिए सेट करता है.
const setTemporaryViewTransitionNames = async (entries, vtPromise) => {
for (const [$el, name] of entries) {
$el.style.viewTransitionName = name;
}
await vtPromise;
for (const [$el, name] of entries) {
$el.style.viewTransitionName = '';
}
}
अब पिछले कोड को इस तरह से आसान बनाया जा सकता है:
// OLD PAGE LOGIC
window.addEventListener('pageswap', async (e) => {
if (e.viewTransition) {
const targetUrl = new URL(e.activation.entry.url);
// Navigating to a profile page
if (isProfilePage(targetUrl)) {
const profile = extractProfileNameFromUrl(targetUrl);
// Set view-transition-name values on the clicked row
// Clean up after the page got replaced
setTemporaryViewTransitionNames([
[document.querySelector(`#${profile} span`), 'name'],
[document.querySelector(`#${profile} img`), 'avatar'],
], e.viewTransition.finished);
}
}
});
// NEW PAGE LOGIC
window.addEventListener('pagereveal', async (e) => {
if (e.viewTransition) {
const fromURL = new URL(navigation.activation.from.url);
const currentURL = new URL(navigation.activation.entry.url);
// Navigating from a profile page back to the homepage
if (isProfilePage(fromURL) && isHomePage(currentURL)) {
const profile = extractProfileNameFromUrl(currentURL);
// Set view-transition-name values on the elements in the list
// Clean up after the snapshots have been taken
setTemporaryViewTransitionNames([
[document.querySelector(`#${profile} span`), 'name'],
[document.querySelector(`#${profile} img`), 'avatar'],
], e.viewTransition.ready);
}
}
});
रेंडर ब्लॉक करने की सुविधा के साथ कॉन्टेंट लोड होने का इंतज़ार करना
Browser Support
कुछ मामलों में, ऐसा हो सकता है कि आपको किसी पेज के पहले रेंडर को तब तक रोकना हो, जब तक कि नया DOM में कोई एलिमेंट मौजूद न हो. इससे फ़्लैशिंग से बचा जा सकता है. साथ ही, यह पक्का किया जा सकता है कि जिस स्थिति में ऐनिमेशन किया जा रहा है वह स्थिर हो.
<head> में, एक या उससे ज़्यादा ऐसे एलिमेंट आईडी तय करें जो पेज के पहले रेंडर से पहले मौजूद होने चाहिए. इसके लिए, यहां दिए गए मेटा टैग का इस्तेमाल करें.
<link rel="expect" blocking="render" href="#section1">
इस मेटा टैग का मतलब है कि एलिमेंट को डीओएम में मौजूद होना चाहिए, न कि कॉन्टेंट को लोड किया जाना चाहिए. उदाहरण के लिए, इमेज के मामले में, DOM ट्री में सिर्फ़ <img> टैग के साथ तय किया गया id मौजूद होने पर, शर्त को 'सही' के तौर पर आंका जाता है. ऐसा हो सकता है कि इमेज अब भी लोड हो रही हो.
रेंडरिंग को ब्लॉक करने की सुविधा का इस्तेमाल करने से पहले, ध्यान रखें कि इंक्रीमेंटल रेंडरिंग, वेब का एक बुनियादी पहलू है. इसलिए, रेंडरिंग को ब्लॉक करने की सुविधा चुनते समय सावधानी बरतें. रेंडरिंग को ब्लॉक करने के असर का आकलन, हर मामले के हिसाब से किया जाना चाहिए. डिफ़ॉल्ट रूप से, blocking=render का इस्तेमाल न करें. हालांकि, अगर आपको वेबसाइट की परफ़ॉर्मेंस की अहम जानकारी पर पड़ने वाले असर को मेज़र करना है, तो इसका इस्तेमाल किया जा सकता है.
क्रॉस-डॉक्यूमेंट व्यू ट्रांज़िशन में ट्रांज़िशन टाइप देखना
क्रॉस-डॉक्यूमेंट व्यू ट्रांज़िशन में, व्यू ट्रांज़िशन टाइप भी काम करते हैं. इनकी मदद से, ऐनिमेशन और कैप्चर किए जाने वाले एलिमेंट को पसंद के मुताबिक बनाया जा सकता है.
उदाहरण के लिए, पेज नंबर के हिसाब से क्रम में लगे पेजों में अगले या पिछले पेज पर जाते समय, आपको अलग-अलग ऐनिमेशन इस्तेमाल करने पड़ सकते हैं. ऐसा इस आधार पर किया जा सकता है कि आप क्रम में लगे पेजों में से किसी ज़्यादा नंबर वाले पेज पर जा रहे हैं या कम नंबर वाले पेज पर.
इन टाइप को पहले से सेट करने के लिए, @view-transition at-rule में टाइप जोड़ें:
@view-transition {
navigation: auto;
types: slide, forwards;
}
टाइप को तुरंत सेट करने के लिए, pageswap और pagereveal इवेंट का इस्तेमाल करके, e.viewTransition.types की वैल्यू में बदलाव करें.
window.addEventListener("pagereveal", async (e) => {
if (e.viewTransition) {
const transitionType = determineTransitionType(navigation.activation.from, navigation.activation.entry);
e.viewTransition.types.add(transitionType);
}
});
टाइप, पुराने पेज पर मौजूद ViewTransition ऑब्जेक्ट से नए पेज पर मौजूद ViewTransition ऑब्जेक्ट में अपने-आप ट्रांसफ़र नहीं होते हैं. ऐनिमेशन को उम्मीद के मुताबिक चलाने के लिए, आपको कम से कम नए पेज पर इस्तेमाल किए जाने वाले टाइप तय करने होंगे.
इन टाइप के जवाब देने के लिए, :active-view-transition-type() स्यूडो-क्लास सिलेक्टर का इस्तेमाल करें. इसे उसी तरह इस्तेमाल करें जिस तरह एक ही दस्तावेज़ में व्यू ट्रांज़िशन के लिए किया जाता है
/* Determine what gets captured when the type is forwards or backwards */
html:active-view-transition-type(forwards, backwards) {
:root {
view-transition-name: none;
}
article {
view-transition-name: content;
}
.pagination {
view-transition-name: pagination;
}
}
/* Animation styles for forwards type only */
html:active-view-transition-type(forwards) {
&::view-transition-old(content) {
animation-name: slide-out-to-left;
}
&::view-transition-new(content) {
animation-name: slide-in-from-right;
}
}
/* Animation styles for backwards type only */
html:active-view-transition-type(backwards) {
&::view-transition-old(content) {
animation-name: slide-out-to-right;
}
&::view-transition-new(content) {
animation-name: slide-in-from-left;
}
}
/* Animation styles for reload type only */
html:active-view-transition-type(reload) {
&::view-transition-old(root) {
animation-name: fade-out, scale-down;
}
&::view-transition-new(root) {
animation-delay: 0.25s;
animation-name: fade-in, scale-up;
}
}
टाइप सिर्फ़ चालू व्यू ट्रांज़िशन पर लागू होते हैं. इसलिए, व्यू ट्रांज़िशन खत्म होने पर टाइप अपने-आप हट जाते हैं. इस वजह से, टाइप BFCache जैसी सुविधाओं के साथ अच्छी तरह काम करते हैं.
डेमो
यहां दिए गए पेज नंबर डालने के डेमो में, पेज नंबर के हिसाब से पेज का कॉन्टेंट आगे या पीछे की ओर स्लाइड होता है.
pagereveal और pageswap इवेंट में, 'से' और 'तक' यूआरएल देखकर यह तय किया जाता है कि किस तरह का ट्रांज़िशन इस्तेमाल करना है.
const determineTransitionType = (fromNavigationEntry, toNavigationEntry) => {
const currentURL = new URL(fromNavigationEntry.url);
const destinationURL = new URL(toNavigationEntry.url);
const currentPathname = currentURL.pathname;
const destinationPathname = destinationURL.pathname;
if (currentPathname === destinationPathname) {
return "reload";
} else {
const currentPageIndex = extractPageIndexFromPath(currentPathname);
const destinationPageIndex = extractPageIndexFromPath(destinationPathname);
if (currentPageIndex > destinationPageIndex) {
return 'backwards';
}
if (currentPageIndex < destinationPageIndex) {
return 'forwards';
}
return 'unknown';
}
};
सुझाव/राय दें या शिकायत करें
डेवलपर के सुझाव, शिकायत या राय का हमेशा स्वागत है. सुझाव और सवालों के साथ, GitHub पर सीएसएस वर्किंग ग्रुप के साथ समस्या की शिकायत करें. अपनी समस्या के आगे [css-view-transitions] जोड़ें.
अगर आपको कोई गड़बड़ी मिलती है, तो Chromium में गड़बड़ी की शिकायत करें.