जब दो अलग-अलग दस्तावेज़ों के बीच व्यू ट्रांज़िशन होता है, तो इसे क्रॉस-दस्तावेज़ व्यू ट्रांज़िशन कहा जाता है. आम तौर पर, ऐसा कई पेज वाले ऐप्लिकेशन (MPA) में होता है. Chrome 126 से, Chrome में क्रॉस-दस्तावेज़ व्यू ट्रांज़िशन काम करते हैं.
क्रॉस-दस्तावेज़ व्यू ट्रांज़िशन, एक ही दस्तावेज़ वाले व्यू में होने वाले ट्रांज़िशन की तरह ही एक जैसे बिल्डिंग ब्लॉक और सिद्धांतों पर निर्भर करता है. इस प्रोसेस को सोच-समझकर ही किया जा सकता है:
- ब्राउज़र उन एलिमेंट का स्नैपशॉट लेता है जिनका पुराने और नए, दोनों पेजों पर एक खास
view-transition-name
होता है. - रेंडरिंग को बंद करने पर, डीओएम अपडेट हो जाता है.
- आखिर में, ट्रांज़िशन की प्रोसेस सीएसएस ऐनिमेशन की मदद से होती है.
एक ही दस्तावेज़ के व्यू ट्रांज़िशन से तुलना करने पर, यह अंतर यह होता है कि क्रॉस-दस्तावेज़ व्यू ट्रांज़िशन के लिए, आपको व्यू ट्रांज़िशन शुरू करने के लिए, document.startViewTransition
को कॉल करने की ज़रूरत नहीं है. इसके बजाय, क्रॉस-दस्तावेज़ व्यू ट्रांज़िशन का ट्रिगर एक पेज से दूसरे पेज पर जाने के लिए, एक ही ऑरिजिन वाला नेविगेशन होता है. यह एक ऐसी कार्रवाई है जो आम तौर पर आपकी वेबसाइट का उपयोगकर्ता किसी लिंक पर क्लिक करके करता है.
दूसरे शब्दों में, दो दस्तावेज़ों के बीच व्यू ट्रांज़िशन शुरू करने के लिए, कोई एपीआई नहीं है. हालांकि, इन दो शर्तों को पूरा करना ज़रूरी है:
- दोनों दस्तावेज़ एक ही ऑरिजिन पर होने चाहिए.
- व्यू ट्रांज़िशन की अनुमति देने के लिए, दोनों पेजों में ऑप्ट-इन करना ज़रूरी है.
इन दोनों शर्तों के बारे में इस दस्तावेज़ में बाद में बताया गया है.
क्रॉस-दस्तावेज़ व्यू में होने वाले ट्रांज़िशन, सेम-ऑरिजिन नेविगेशन तक ही सीमित होते हैं
क्रॉस-दस्तावेज़ व्यू में होने वाले ट्रांज़िशन, सिर्फ़ एक ही ऑरिजिन वाले नेविगेशन तक सीमित हैं. अगर सहमति देने वाले दोनों पेजों का ऑरिजिन एक ही है, तो नेविगेशन को एक ही ऑरिजिन वाला माना जाएगा.
किसी पेज का ऑरिजिन, इस्तेमाल की गई स्कीम, होस्टनेम, और पोर्ट का एक कॉम्बिनेशन होता है. इस बारे में web.dev पर ज़्यादा जानकारी दी गई है.
उदाहरण के लिए, developer.chrome.com
से developer.chrome.com/blog
पर नेविगेट करते समय, क्रॉस-दस्तावेज़ व्यू ट्रांज़िशन हो सकता है. ऐसा इसलिए, क्योंकि ये दोनों ऑरिजिन से ही शुरू होते हैं.
developer.chrome.com
से www.chrome.com
पर नेविगेट करते समय, यह ट्रांज़िशन नहीं हो सकता. ऐसा इसलिए, क्योंकि ये क्रॉस-ऑरिजिन और एक ही साइट के होते हैं.
क्रॉस-दस्तावेज़ व्यू ट्रांज़िशन के लिए ऑप्ट-इन करना होता है
दो दस्तावेज़ों के बीच क्रॉस-दस्तावेज़ व्यू को ट्रांसफ़र करने के लिए, इस सुविधा का इस्तेमाल करने वाले दोनों पेजों को ऑप्ट-इन करना होगा. यह सीएसएस में @view-transition
के नियम के साथ किया जाता है.
@view-transition
एट-रूल में, navigation
डिस्क्रिप्टर को auto
पर सेट करें, ताकि क्रॉस-दस्तावेज़, एक ही ऑरिजिन नेविगेशन के लिए व्यू ट्रांज़िशन चालू किए जा सकें.
@view-transition {
navigation: auto;
}
navigation
डिस्क्रिप्टर को auto
पर सेट करने का मतलब है कि आपने इन NavigationType के लिए, व्यू ट्रांज़िशन की अनुमति देने के लिए ऑप्ट-इन किया है:
traverse
push
याreplace
, अगर उपयोगकर्ता ने ब्राउज़र के यूज़र इंटरफ़ेस (यूआई) तरीकों से चालू नहीं किया था.
auto
से बाहर रखे गए नेविगेशन. उदाहरण के लिए, यूआरएल पता बार का इस्तेमाल करके या किसी बुकमार्क पर क्लिक करके, नेविगेट करने के साथ-साथ किसी भी तरह के उपयोगकर्ता या स्क्रिप्ट के ज़रिए फिर से लोड किए जाने वाले नेविगेशन.
अगर Chrome के मामले में, नेविगेशन में चार सेकंड से ज़्यादा समय लगता है, तो व्यू ट्रांज़िशन को TimeoutError
DOMException
से स्किप कर दिया जाता है.
क्रॉस-दस्तावेज़ व्यू ट्रांज़िशन का डेमो
नीचे दिया गया डेमो देखें जो स्टैक नेविगेटर डेमो बनाने के लिए व्यू ट्रांज़िशन का इस्तेमाल करता है. यहां document.startViewTransition()
के लिए कोई कॉल नहीं है. एक पेज से दूसरे पेज पर नेविगेट करने पर व्यू ट्रांज़िशन ट्रिगर होते हैं.
क्रॉस-दस्तावेज़ व्यू ट्रांज़िशन को पसंद के मुताबिक बनाएं
क्रॉस-दस्तावेज़ व्यू ट्रांज़िशन को पसंद के मुताबिक बनाने के लिए, वेब प्लैटफ़ॉर्म की कुछ सुविधाएं इस्तेमाल की जा सकती हैं.
ये सुविधाएं, व्यू ट्रांज़िशन एपीआई स्पेसिफ़िकेशन का हिस्सा नहीं हैं. हालांकि, इन्हें इसके साथ इस्तेमाल करने के लिए डिज़ाइन किया गया है.
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);
}
}
});
रेंडर होने की सुविधा से कॉन्टेंट के लोड होने का इंतज़ार करें
कुछ मामलों में, हो सकता है कि आप पेज के पहले रेंडर को तब तक रोकना चाहें, जब तक कि नए DOM में कोई खास एलिमेंट मौजूद न हो. इससे, फ़्लैशिंग से बचा जा सकता है. साथ ही, यह पक्का किया जाता है कि ऐनिमेशन की स्थिति एक जैसी हो.
<head>
में, नीचे दिए गए मेटा टैग का इस्तेमाल करके, एक या उससे ज़्यादा ऐसे एलिमेंट आईडी तय करें जो पेज को पहली बार रेंडर होने से पहले मौजूद होने चाहिए.
<link rel="expect" blocking="render" href="#section1">
इस मेटा टैग का मतलब है कि एलिमेंट को डीओएम में मौजूद होना चाहिए, न कि कॉन्टेंट लोड होना. इमेज के उदाहरण के लिए, डीओएम ट्री में तय किए गए id
के साथ <img>
टैग की मौजूदगी ही शर्त के सही का आकलन करने के लिए काफ़ी है. इमेज अब भी लोड हो सकती है.
रेंडर को ब्लॉक करने की प्रक्रिया पूरी करने से पहले, ध्यान रखें कि इंक्रीमेंटल रेंडरिंग, वेब का बुनियादी पहलू है. इसलिए, रेंडरिंग को ब्लॉक करते समय सावधानी बरतें. रेंडरिंग को ब्लॉक करने से होने वाले असर का आकलन, अलग-अलग मामलों के हिसाब से किया जाना चाहिए. डिफ़ॉल्ट रूप से, blocking=render
का इस्तेमाल तब तक न करें, जब तक आप अपने उपयोगकर्ताओं पर पड़ने वाले असर को सही तरीके से मेज़र और मेज़र न कर पाएं. इसके लिए, वेबसाइट की परफ़ॉर्मेंस की जानकारी को मेज़र करें.
क्रॉस-दस्तावेज़ व्यू ट्रांज़िशन में ट्रांज़िशन टाइप देखें
ऐनिमेशन को पसंद के मुताबिक बनाने और कैप्चर किए जाने वाले एलिमेंट के लिए, क्रॉस-दस्तावेज़ व्यू ट्रांज़िशन भी व्यू ट्रांज़िशन टाइप के साथ काम करता है.
उदाहरण के लिए, पेज पर नंबर डालने की प्रक्रिया में अगले या पिछले पेज पर जाते समय, आप अलग-अलग ऐनिमेशन का इस्तेमाल कर सकते हैं. यह इस बात पर निर्भर करेगा कि आप क्रम से बड़े पेज पर जा रहे हैं या निचले पेज पर.
इन टाइप को पहले से सेट करने के लिए, @view-transition
के नियम वाले टाइप में ये टाइप जोड़ें:
@view-transition {
navigation: auto;
types: slide, forwards;
}
टाइप को तुरंत सेट करने के लिए, e.viewTransition.types
की वैल्यू में बदलाव करने के लिए, pageswap
और pagereveal
इवेंट का इस्तेमाल करें.
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 की गड़बड़ी की शिकायत करें.