توسعه فرانت‌اند

CSS View Transitions API: انتقال بین صفحات

تفاوت Same-document و Cross-document، Snapshot، کاهش حرکت و مسیر بدون پشتیبانی را با یک نمونه کامل HTML و JavaScript یاد بگیرید.

1404/12/23 2 دقیقه مطالعه 1,151 بازدید

وقتی یک کارت به نمای جزئیات تبدیل می‌شود، تغییر ناگهانی ممکن است رابطه دو وضعیت را نامشخص کند. View Transition API به مرورگر امکان می‌دهد میان نمای قبلی و جدید، انتقال بصری بسازد. این قابلیت فقط «انیمیشن بین صفحات» نیست؛ هم تغییر در همان سند و هم در شرایط مشخص، جابه‌جایی بین سندها را پوشش می‌دهد. استفاده درست باید Progressive Enhancement باشد: اگر قابلیت موجود نبود یا حرکت برای کاربر مناسب نبود، کار اصلی همچنان انجام شود. انیمیشن نباید شرط دسترسی به محتوا باشد.

Same-document و Cross-document

در انتقال همان سند، کد صفحه تغییر DOM را انجام می‌دهد و از API برای ساخت نمای انتقال استفاده می‌کند. در انتقال بین سندها، Navigation واقعی رخ می‌دهد و دو صفحه باید شرایط مربوط را داشته باشند. این دو مسیر API و محدودیت یکسان ندارند. پشتیبانی یک مرورگر از یکی، لزوماً همه جزئیات دیگری را ثابت نمی‌کند. پیش از انتخاب، نیاز دقیق و مرورگرهای مخاطب را با جدول سازگاری جاری بررسی کنید، نه با عبارت کلی «همه مرورگرهای جدید».

مرجع View Transition API در MDN اجزای این خانواده را معرفی می‌کند. این مقاله یک نمونه کامل Same-document دارد و نمونه چندصفحه‌ای ادعا نمی‌کند. تغییر نمونه فقط داخل صفحه است و URL، Routing یا داده سرور را مدیریت نمی‌کند. این محدوده به خواننده کمک می‌کند خروجی را با یک Router آماده اشتباه نگیرد. انتخاب روش انتقال باید پس از مشخص شدن نوع Navigation انجام شود.

مدل Snapshot و تغییر DOM

مرورگر نمای قبلی را برای انتقال ثبت می‌کند، تغییر DOM انجام می‌شود و سپس نمای جدید در فرایند انتقال قرار می‌گیرد. شما همچنان مسئول تغییر واقعی محتوا هستید. API داده را دریافت یا مجوز دسترسی را بررسی نمی‌کند. اگر Callback خطا دهد یا داده آماده نباشد، منطق برنامه باید رفتار مشخصی داشته باشد. انیمیشن زیبا نمی‌تواند نتیجه نامعلوم عملیات را به موفقیت تبدیل کند. ابتدا مسیر تغییر را درست بسازید و سپس انتقال را روی آن قرار دهید.

برای داده شبکه، بهتر است مشخص کنید آماده‌سازی چه زمانی انجام می‌شود و کاربر در انتظار چه می‌بیند. نگه داشتن تغییر DOM منتظر یک درخواست طولانی ممکن است تجربه نامناسب ایجاد کند. همه کارها را داخل Callback انتقال قرار ندهید فقط چون آنجا نقطه تغییر است. داده، وضعیت و انیمیشن مسئولیت‌های جدا دارند. اگر کاربر چند بار اقدام کرد، رفتار درخواست و تغییر باید قابل پیش‌بینی باشد و نتیجه قدیمی نباید وضعیت تازه را ناخواسته جایگزین کند.

نمونه کامل یک فایل

کد زیر یک کارت راهنمای فرضی را میان نمای خلاصه و جزئیات تغییر می‌دهد. همه HTML، CSS و JavaScript در یک فایل‌اند؛ تصویر، کتابخانه، API یا فایل دیگری لازم نیست. آن را با نام index.html ذخیره کنید و در مرورگر باز کنید. در مرورگر دارای document.startViewTransition و بدون ترجیح کاهش حرکت، تغییر با انتقال انجام می‌شود. در غیر این صورت، متن و ظاهر مستقیم عوض می‌شوند. نتیجه پایه در هر دو مسیر یکسان است.

<!doctype html>
<html lang="fa" dir="rtl">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>نمونه View Transition</title>
<style>
body {font-family:system-ui;max-width:44rem;margin:3rem auto;padding:1rem;background:#f3f5f7;color:#17212b}
#card {view-transition-name:guide-card;padding:2rem;border:1px solid #aab7c4;border-radius:1rem;background:white}
#card.expanded {background:#e5f1ff}
button {font:inherit;padding:.6rem 1rem;margin-top:1rem}
::view-transition-group(guide-card) {animation-duration:240ms}
@media(prefers-reduced-motion:reduce) {::view-transition-group(*),::view-transition-old(*),::view-transition-new(*) {animation:none!important}}
</style></head>
<body><main><article id="card"><h1 id="title">خلاصه راهنما</h1><p id="description">برای دیدن توضیح بیشتر دکمه را بزنید.</p></article><button id="toggle" type="button" aria-expanded="false" aria-controls="card">نمایش جزئیات</button></main>
<script>
const card=document.querySelector('#card');
const title=document.querySelector('#title');
const description=document.querySelector('#description');
const button=document.querySelector('#toggle');
let expanded=false;
function update(){
 expanded=!expanded;
 card.classList.toggle('expanded',expanded);
 title.textContent=expanded?'جزئیات راهنما':'خلاصه راهنما';
 description.textContent=expanded?'این تغییر فقط در همان سند انجام می‌شود و داده‌ای به سرور نمی‌فرستد.':'برای دیدن توضیح بیشتر دکمه را بزنید.';
 button.textContent=expanded?'بازگشت به خلاصه':'نمایش جزئیات';
 button.setAttribute('aria-expanded',String(expanded));
}
button.addEventListener('click',async()=>{
 if(!document.startViewTransition||matchMedia('(prefers-reduced-motion: reduce)').matches){update();return;}
 button.disabled=true;
 try{const transition=document.startViewTransition(update);await transition.finished;}
 catch(error){console.warn('انتقال بصری پایان نیافت.',error);}
 finally{button.disabled=false;}
});
</script></body></html>

پس از باز کردن فایل، دکمه «نمایش جزئیات» را بزنید. انتظار می‌رود عنوان و توضیح کارت تغییر کنند و دکمه امکان برگشت بدهد. این نمونه هیچ ثبت یا ارسال واقعی ندارد. اگر کاهش حرکت سیستم فعال باشد، مسیر بدون انتقال اجرا می‌شود. دستور اجرا برای خواننده توضیح داده شده است و این مقاله ادعای آزمون اجرایی در محیط انتشار ندارد. برای استفاده محصولی، رفتار را با مرورگرها و داده واقعی مخاطبان ارزیابی کنید.

Feature Detection و مسیر پایه

نمونه ابتدا ترجیح کاهش حرکت و وجود تابع را بررسی می‌کند. تابع update همان تغییر واقعی را انجام می‌دهد، چه انتقال فعال باشد چه نباشد. این جداسازی باعث می‌شود رفتار اصلی به قابلیت بصری وابسته نشود. وجود نام API تضمین نمی‌کند همه جزئیات انتقال دلخواه شما موجود باشند؛ اگر از ویژگی پیشرفته‌تری استفاده می‌کنید، همان ویژگی را جدا بررسی کنید. این روش از شکست کامل صفحه در محیط محدود جلوگیری می‌کند.

دکمه در طول انتقال کوتاه غیرفعال می‌شود تا نمونه تغییرهای هم‌پوشان ایجاد نکند. در محصول واقعی، این انتخاب باید با نوع کار و امکان لغو هماهنگ باشد. در finally دوباره فعال می‌شود تا خطای انتقال کنترل را برای همیشه نبندد. خطای لایه بصری نباید منطق داده را تکرار کند؛ اگر Callback اجرا شده، فراخوانی دوباره آن می‌تواند تغییر را معکوس کند. تفکیک خطای انیمیشن از تغییر اصلی، برای جلوگیری از رفتار تکراری اهمیت دارد.

نام‌گذاری عنصر و محدودیت‌ها

view-transition-name کمک می‌کند مرورگر یک عنصر را در نمای قدیم و جدید به هم مرتبط کند. نام باید در وضعیت مربوط به شکل سازگار و یکتا استفاده شود؛ چند عنصر هم‌زمان با نام یکسان می‌توانند مسئله ایجاد کنند. در فهرست کارت‌ها، یک نام ثابت را بی‌بررسی به همه عناصر ندهید. باید مشخص کنید کدام عنصر واقعاً انتقال مشترک دارد. نام‌گذاری بخشی از قرارداد رابط است، نه یک کلاس تزئینی عمومی برای تمام صفحه.

راهنمای استفاده MDN جزئیات ساخت و کنترل انتقال را توضیح می‌دهد. در نمونه، فقط یک کارت نام دارد و لازم نیست رابطه چند عنصر مدیریت شود. مدت حرکت کوتاه نگه داشته شده و انتقال با هدف فهم رابطه دو وضعیت است. اگر حرکت طولانی، پرش بزرگ یا چند لایه هم‌زمان اضافه کنید، ممکن است فهم و راحتی کاربر کمتر شود. «قابل اجرا بودن» هر افکت به معنی مناسب بودن آن برای محصول نیست.

کاهش حرکت و دسترس‌پذیری

ترجیح prefers-reduced-motion را در تصمیم JavaScript و سبک‌ها در نظر بگیرید. تنها کم کردن مدت یک افکت شدید ممکن است کافی نباشد؛ گاهی حذف حرکت مناسب‌تر است. تغییر واقعی محتوا باید بدون انیمیشن هم قابل فهم باشد. وضعیت و عنوان را روشن نگه دارید و از حرکت به‌عنوان تنها نشانه موفقیت استفاده نکنید. برای محتوای حساس یا کاربرانی که حرکت آزارشان می‌دهد، راه پایه باید تجربه کامل و قابل استفاده بدهد.

Focus و ترتیب صفحه‌کلید را هم مدیریت کنید. انتقال بصری خودکار به معنی جابه‌جایی درست Focus نیست. اگر دکمه یا ناحیه فعال حذف می‌شود، باید مقصد منطقی بعدی را طراحی کنید. در نمونه، دکمه باقی می‌ماند و فقط متن آن عوض می‌شود تا مسیر ساده باشد. در Modal، صفحه جزئیات یا Routing، شرایط متفاوت است. اعلام متن تازه به فناوری کمکی باید متناسب باشد و نباید همه تغییرهای جزئی را به پیام‌های پی‌درپی تبدیل کند.

Cross-document به طراحی جدا نیاز دارد

برای جابه‌جایی واقعی بین صفحه‌ها، شرایطی مانند هم‌مبدأ بودن و Opt-in مربوط مطرح‌اند. این مسیر را با قراردادن تابع Same-document روی هر لینک شبیه‌سازی نکنید. کارکرد لینک، باز کردن در تب تازه و تاریخچه باید درست بمانند. اگر از Framework استفاده می‌کنید، مستندات Routing و انتقال همان نسخه را بخوانید. مدیریت Snapshot، اسکرول و Focus می‌تواند با رفتار Router ارتباط داشته باشد و کپی نمونه مستقل، همه آن‌ها را حل نمی‌کند.

برای صفحه عمومی، انتقال نباید جای قرارداد URL و SEO فنی را بگیرد. یک صفحه زیبا با لینک‌های غیرقابل دنبال کردن یا وضعیت خطای نادرست، همچنان مشکل دارد. اگر دو سند محتوای متفاوت دارند، عنوان و اطلاعات صفحه باید جدا درست باشند. انیمیشن میان آن‌ها فقط یک لایه تجربه است. تصمیم درباره داده، کشف محتوا و وضعیت HTTP در لایه‌های مربوط باقی می‌ماند.

کارایی و دامنه استفاده

Snapshot و حرکت عناصر بزرگ می‌توانند هزینه داشته باشند. از ابتدا همه صفحه را با افکت پیچیده نپوشانید. یک مسیر مهم با رابطه بصری روشن انتخاب کنید و هزینه را در شرایط واقعی بسنجید. داده آزمایشگاهی روی دستگاه قوی، نماینده همه مخاطبان نیست. تصویر سنگین، چیدمان ناپایدار و درخواست کند، با افزودن انتقال اصلاح نمی‌شوند. حرکت باید روی رابطی قرار گیرد که رفتار پایه‌اش قابل اتکا است.

در طراحی Mobile-first، فضای کوچک و محدودیت دستگاه اهمیت دارند. افکتی که در دسکتاپ کوتاه به نظر می‌رسد، ممکن است در موبایل بخش بزرگی از صفحه را حرکت دهد. متن فارسی بلند و اندازه متفاوت کارت را هم در طراحی در نظر بگیرید. انتخاب مدت و دامنه حرکت باید با محتوا سازگار باشد، نه فقط با نمونه‌ای که چند کلمه کوتاه دارد.

تحویل با محدوده روشن

در مستند تغییر، نوع انتقال، مرورگر هدف، مسیر بدون پشتیبانی و رفتار کاهش حرکت را بنویسید. اگر داده یا Routing خارج از نمونه است، آن را صریح اعلام کنید. نمونه آموزشی باید همه عناصر و شناسه‌های لازم را نشان دهد؛ قطعه CSS بدون HTML مربوط، مسیر استفاده را ناقص می‌گذارد. View Transition API زمانی مفید است که رابطه تغییر را روشن‌تر کند و رفتار پایه را حفظ کند. از همان یک مسیر محدود شروع کنید و افکت را بر اساس نیاز کاربر گسترش دهید.

واکنش به این مقاله

اشتراک‌گذاری این مقاله:
دیدگاه‌ها 0
۰ / ۲۰۰۰

هنوز دیدگاهی ثبت نشده

اولین نفری باشید که نظر می‌دهد!