समस्या
वेबसाइटें अक्सर किसी ऑब्जेक्ट के कई व्यू उपलब्ध कराती हैं. उदाहरण के लिए, प्रॉडक्ट की सूची और फिर हर प्रॉडक्ट के लिए ज़्यादा जानकारी वाला पेज. दोनों व्यू के बीच नेविगेट करने पर, अक्सर ऐसा लगता है कि वे एक-दूसरे से जुड़े नहीं हैं. जब कोई उपयोगकर्ता किसी प्रॉडक्ट की जानकारी देखने के लिए उसके थंबनेल पर क्लिक करता है, तो थंबनेल गायब हो जाता है और स्क्रीन पर कहीं और तुरंत एक नई, बड़ी इमेज दिखने लगती है. इस वजह से, उपयोगकर्ताओं के लिए एलिमेंट के बीच के संबंध को ट्रैक करना मुश्किल हो जाता है.
समस्या का हल
View Transitions API की मदद से, एलिमेंट के ऐसे पेयर तय किए जा सकते हैं जो ट्रांज़िशन से पहले और बाद में अलग-अलग स्थितियों में मौजूद होते हैं. सिंगल पेज नेविगेशन (एसपीए) में document.startViewTransition() की मदद से ट्रांज़िशन ट्रिगर करने पर, ब्राउज़र इन शेयर किए गए एलिमेंट की पहचान उनके शेयर किए गए यूनीक view-transition-name से करता है. इसके बाद, यह उनकी पोज़िशन, साइज़, और स्टाइल में अंतर का अपने-आप हिसाब लगाता है. साथ ही, उन्हें पुरानी स्थिति से नई स्थिति में आसानी से ऐनिमेट करता है. यह ट्रांज़िशन सबसे ऊपर वाली लेयर में होता है. यहां तक कि ज़्यादा z-index वैल्यू वाले एलिमेंट के ऊपर भी.
लागू करने के बारे में जानकारी
पहला चरण: स्टेट में होने वाले बदलावों को startViewTransition में रैप करना
एक पेज के ऐप्लिकेशन (एसपीए) या सामान्य स्थिति में बदलावों के लिए, डीओएम को अपडेट करने वाले लॉजिक को document.startViewTransition में रैप करें. ब्राउज़र, मौजूदा स्थिति का स्नैपशॉट कैप्चर करता है, अपडेट चलाता है, और फिर नई स्थिति कैप्चर करता है.
function navigate(view) {
// MANDATORY: Wrap the update in startViewTransition
document.startViewTransition(() => updateDOM(view));
}
दूसरा चरण: शेयर किए गए ट्रांज़िशन के नाम असाइन करना
ब्राउज़र को यह बताने के लिए कि किन एलिमेंट को मॉर्फ़ करना है, view-transition-name सीएसएस प्रॉपर्टी का इस्तेमाल करें. नाम कुछ भी हो सकता है. हालांकि, वह none नहीं होना चाहिए. ज़रूरी शर्त: दिए गए view-transition-name से पहले और बाद में, एक से ज़्यादा एलिमेंट नहीं होने चाहिए. अगर दिए गए view-transition-name के साथ दो या उससे ज़्यादा एलिमेंट हैं, तो डीओएम को बिना किसी ट्रांज़िशन के तुरंत नई स्थिति में अपडेट कर दिया जाएगा.
एलिमेंट के कई जोड़ों को मॉर्फ़ करने के लिए, कई view-transition-name का इस्तेमाल किया जा सकता है. उदाहरण के लिए, हो सकता है कि आपको प्रॉडक्ट की इमेज और टाइटल, दोनों को अलग-अलग ट्रांज़िशन के साथ दिखाना हो.
सूची वाले व्यू में कई आइटम मौजूद हैं. इसलिए, उन सभी को एक ही view-transition-name नहीं दिया जा सकता. एसपीए में इस समस्या को दो तरीकों से हल किया जा सकता है.
डाइनैमिक तरीके से ज़्यादा जानकारी वाला पेज: सूची वाले पेज पर मौजूद हर आइटम को एक यूनीक
view-transition-nameअसाइन करें. इसके बाद, सूची में मौजूद आइटम को चुने जाने पर, ज़्यादा जानकारी वाले पेज पर मौजूद मिलते-जुलते एलिमेंट पर डाइनैमिक तरीके से वह नाम लागू करें. इसे यहां दिखाया गया है./* In the list view, give each */ #product-1 { view-transition-name: p1 } #product-2 { view-transition-name: p2 } #product-3 { view-transition-name: p3 }function updateDOM(clickedTransitionName){ const hero = document.getElementById("hero"); hero.style.viewTransitionName = clickedTransitionName; }डाइनैमिक सूची का आइटम: ज़्यादा जानकारी वाले पेज पर मौजूद एलिमेंट को
view-transition-nameअसाइन करें. साथ ही, सूची वाले पेज पर मौजूद आइटम को चुने जाने पर, उस नाम को लागू करें. सूची वाले पेज पर वापस जाने पर, आइटम सेview-transition-nameको हटा दें.
ज़्यादा जानकारी वाले पेज पर मौजूद #hero एलिमेंट और सूची वाले पेज पर चुना गया .thumbnail एलिमेंट, view-transition-name शेयर करते हैं.
#hero{
view-transition-name: hero;
}
.thumbnail.selected {
view-transition-name: hero;
}
जब किसी थंबनेल पर क्लिक किया जाता है, तो हमें सूची वाले व्यू को तैयार करना होता है. इसके लिए, .selected क्लास सिलेक्टर का इस्तेमाल करके view-transition-name को असाइन करना होता है. साथ ही, ट्रांज़िशन शुरू करने से पहले डीओएम में कोई भी बदलाव करना होता है.
इसके बाद, document.startViewTransition() को कॉल करके, पेज को ज़्यादा जानकारी वाले व्यू से सूची वाले व्यू में बदलने के लिए, बदलावों को लागू किया जा सकता है.
सूची वाले व्यू पर वापस जाने के बाद, आपको व्यू ट्रांज़िशन क्लास को हटाना होगा. इससे अगली बार नेविगेट करने पर गड़बड़ी नहीं होगी. ट्रांज़िशन के finished प्रॉमिस के रिज़ॉल्व होने के बाद, यह क्लीनअप किया जा सकता है.
// Function called when a thumbnail is clicked
function goFromListToDetail(e){
e.currentTarget.classList.add("selected");
const hero = document.getElementById("hero");
const bgColor = getComputedStyle(e.currentTarget).backgroundColor;
hero.style.background = bgColor;
// Trigger the transition, checking for support
if (!document.startViewTransition) {
document.body.classList.add("detail");
// MANDATORY Accessibility Routing: Route focus to the newly revealed heading to announce context and preserve logical tab flow
document.getElementById("detail-heading")?.focus();
return; // MANDATORY: End function execution if view transitions are not supported.
}
const transition = document.startViewTransition(() => {
document.body.classList.add("detail");
});
// MANDATORY Accessibility Routing: Route focus after the view transition resolves
transition.finished.finally(() => {
document.getElementById("detail-heading")?.focus();
});
}
// Function called when navigating from detail back to list view
function goFromDetailToList() {
if (!document.startViewTransition) {
document.body.classList.remove("detail");
document.getElementById("list-heading")?.focus();
return;
}
const transition = document.startViewTransition(() => {
document.body.classList.remove("detail");
});
// Clean up the list view and route focus
transition.finished.finally(() => {
// Route focus back to list view
document.getElementById("list-heading")?.focus();
// Remove selected classList to remove view-transition-names
document.querySelectorAll(".selected").forEach(
(element) => {
element.classList.remove("selected");
},
);
});
}
आपको कौनसा तरीका चुनना है, यह इस बात पर निर्भर करेगा कि आपको किस तरह का डेटा इंपोर्ट करना है. डाइनैमिक सूची के आइटम के लिए, सीएसएस को बार-बार दोहराने की ज़रूरत नहीं होती. हालांकि, JavaScript को मैन्युअल तरीके से साफ़ करने की ज़रूरत ज़्यादा होती है.
तीसरा चरण: आसपेक्ट रेशियो (लंबाई-चौड़ाई का अनुपात) "स्ट्रेच" होने की समस्या को ठीक करना
डिफ़ॉल्ट रूप से, ब्राउज़र किसी ग्रुप में मौजूद पुराने और नए स्नैपशॉट को क्रॉस-फ़ेड करता है. यह ग्रुप, दोनों स्नैपशॉट को फ़िट करने के लिए स्ट्रेच होता है. अगर आपको टेक्स्ट को ट्रांज़िशन करना है, तो पुराने और नए, दोनों व्यू में टेक्स्ट एलिमेंट की चौड़ाई को fit-content पर सेट करें. इससे ट्रांज़िशन किए गए एलिमेंट का आसपेक्ट रेशियो (लंबाई-चौड़ाई का अनुपात) स्थिर रहता है.
#list-page .title {
width: fit-content;
}
#detail-page #title {
width: fit-content;
}
अगर आपको ऐसे एलिमेंट के बीच ट्रांज़िशन करना है जिनका आसपेक्ट रेशियो (लंबाई-चौड़ाई का अनुपात) बदलता है, तो आपको पुराने और नए सूडो-एलिमेंट की ऊंचाई को ::view-transition-pair() सूडो-एलिमेंट के 100% पर सेट करना पड़ सकता है.
::view-transition-old(hero),
::view-transition-new(hero){
height: 100%;
}
स्यूडो-एलिमेंट, लाइव एलिमेंट के स्नैपशॉट होते हैं. इसलिए, ट्रांज़िशन इफ़ेक्ट को ज़्यादा कंट्रोल करने के लिए, object-fit और object-position डिक्लेरेशन का भी इस्तेमाल किया जा सकता है.
सबसे सही तरीके
- बहुत ज़्यादा ट्रांज़िशन न जोड़ें. शेयर किए गए एलिमेंट का इस्तेमाल सिर्फ़ उस मुख्य कॉन्टेंट के लिए करें जिसे उपयोगकर्ता ऐक्टिव तौर पर ट्रैक कर रहा है. जैसे, हीरो इमेज, हेडिंग.
- ट्रांज़िशन खत्म होने के बाद, अस्थायी
view-transition-nameवैल्यू को हटा दें, ताकि आने वाले समय में होने वाले ट्रांज़िशन पर कोई खराब असर न पड़े. - ऐक्टिव ऐनिमेशन वाले एलिमेंट को ट्रांज़िशन न करें. व्यू ट्रांज़िशन, स्नैपशॉट पर काम करते हैं. इसलिए, व्यू ट्रांज़िशन के दौरान कोई भी ऐनिमेशन रुका हुआ दिखेगा.
- DO
prefers-reduced-motionमीडिया क्वेरी का इस्तेमाल करके, कम मोशन के लिए उपयोगकर्ता की प्राथमिकताओं का सम्मान करें. - सुलभता के लिए ज़रूरी रूटिंग: व्यू ट्रांज़िशन, पेज के लेआउट को डाइनैमिक तौर पर बदलते हैं. हालांकि, ये प्रोग्राम के हिसाब से फ़ोकस को मैनेज नहीं करते. अगर ट्रांज़िशन के दौरान छिपाए गए या हटाए गए किसी एलिमेंट पर फ़ोकस बना रहता है, तो फ़ोकस हट जाता है. इससे कीबोर्ड और सहायक टेक्नोलॉजी का इस्तेमाल करने वाले लोगों को कॉन्टेक्स्ट नहीं मिलता. डीओएम अपडेट होने के तुरंत बाद या व्यू ट्रांज़िशन का
finishedप्रॉमिस रिज़ॉल्व होने पर, प्रोग्राम के हिसाब से फ़ोकस को अपडेट किए गए पेज हेडिंग या व्यू कंटेनर (tabindex="-1"का इस्तेमाल करके) पर शिफ़्ट करें.
@media (prefers-reduced-motion: reduce) {
::view-transition-group(*),
::view-transition-old(*),
::view-transition-new(*) {
animation: none !important;
}
}
फ़ॉलबैक रणनीतियां
View Transitions API को प्रोग्रेसिव एन्हांसमेंट के लिए डिज़ाइन किया गया है. जिन ब्राउज़र पर यह सुविधा काम नहीं करती वे बिना ऐनिमेशन के, डीओएम अपडेट को तुरंत लागू कर देंगे.
function navigate(){
if (!document.startViewTransition) {
// Fallback: Just update the DOM
updateDOM();
} else {
document.startViewTransition(() => updateDOM());
}
}