بررسی عمیق موتور شبهعنصر در CSS View Transition API، با تمرکز بر مدیریت عناصر انتقال برای ایجاد تجارب کاربری یکپارچه و جذاب.
موتور شبهعنصر (Pseudo-Element) در CSS View Transition: تسلط بر مدیریت عناصر انتقال
CSS View Transitions API روشی قدرتمند برای ایجاد انتقالهای روان و جذاب از نظر بصری بین حالتهای مختلف یک اپلیکیشن وب فراهم میکند. در قلب این API یک موتور شبهعنصر قرار دارد که ایجاد و دستکاری عناصر انتقال را مدیریت میکند. درک نحوه عملکرد این موتور برای استفاده مؤثر از View Transitions API و دستیابی به تجارب کاربری واقعاً یکپارچه بسیار مهم است.
درک ساختار شبهعنصر
هنگامی که یک انتقال نما (view transition) فعال میشود، مرورگر به طور خودکار یک سلسلهمراتب از شبهعنصرها را ایجاد میکند که مراحل مختلف انتقال را نشان میدهند. این سلسلهمراتب به توسعهدهندگان اجازه میدهد تا ظاهر و رفتار هر عنصر را در طول انتقال به دقت کنترل کنند. شبهعنصرهای کلیدی عبارتند از:
- ::view-transition: این شبهعنصر ریشه است که کل انتقال نما را در بر میگیرد. این عنصر به عنوان یک کانتینر برای سایر عناصر انتقال عمل میکند.
- ::view-transition-group: این شبهعنصر نماهای «قدیمی» و «جدید» متناظر را که یک شناسه انتقال مشترک (
view-transition-name
) دارند، با هم گروهبندی میکند. هر عنصری با یکview-transition-name
منحصربهفرد،::view-transition-group
مخصوص به خود را خواهد داشت. - ::view-transition-image-pair: در هر
::view-transition-group
، این شبهعنصر شامل جفت تصاویر «قدیمی» و «جدید» برای عنصر در حال انتقال است. این کار اعمال سبکهای هماهنگ را ساده میکند. - ::view-transition-old: این شبهعنصر نمای «قدیمی» را نشان میدهد، یعنی عنصری که انتقال *از* آن شروع میشود. این اساساً یک عکس زنده از عنصر قبل از شروع انتقال است.
- ::view-transition-new: این شبهعنصر نمای «جدید» را نشان میدهد، یعنی عنصری که انتقال *به* آن ختم میشود. این یک عکس زنده از عنصر پس از تکمیل انتقال است.
این شبهعنصرها بخشی از DOM معمولی نیستند؛ آنها فقط در محدوده انتقال نما وجود دارند. آنها به طور خودکار توسط مرورگر با پیشرفت انتقال ایجاد و حذف میشوند.
نقش view-transition-name
خاصیت CSS به نام view-transition-name
حلقهی اصلی اتصال است که عناصر را در نماهای مختلف به هم متصل کرده و به آنها امکان شرکت در انتقال نما را میدهد. این یک شناسه رشتهای است که شما به عناصری که میخواهید در طول یک انتقال نما انیمیشن داشته باشند، اختصاص میدهید. عناصری که view-transition-name
یکسانی دارند، به لحاظ مفهومی یک عنصر در نظر گرفته میشوند، حتی اگر در بخشهای مختلفی از DOM یا حتی در صفحات مختلف (در مورد یک SPA) قرار داشته باشند. بدون این خاصیت، مرورگر نمیتواند به طور هوشمند عناصر را برای انیمیشنهای انتقال جفت کند.
آن را مانند یک کلید در نظر بگیرید: اگر دو عنصر کلید یکسانی (view-transition-name
) داشته باشند، برای مدت زمان انتقال به یکدیگر متصل میشوند. اینگونه است که مرورگر میفهمد یک عنصر خاص در نمای «قدیمی» با یک عنصر خاص در نمای «جدید» مطابقت دارد.
به عنوان مثال، یک صفحه لیست محصولات و یک صفحه جزئیات محصول را در نظر بگیرید. هر دو صفحه تصویری از محصول را نمایش میدهند. برای ایجاد یک انتقال روان که در آن تصویر محصول به نظر میرسد از صفحه لیست به صفحه جزئیات انیمیشن میشود، شما باید view-transition-name
یکسانی را به عنصر تصویر محصول در هر دو صفحه اختصاص دهید.
مثال: انتقال تصویر محصول
HTML (صفحه لیست محصولات):
<a href="/product/123">
<img src="product123.jpg" style="view-transition-name: product-image-123;" alt="Product 123">
</a>
HTML (صفحه جزئیات محصول):
<img src="product123.jpg" style="view-transition-name: product-image-123;" alt="Product 123">
در این مثال، هم تصویر محصول در صفحه لیست و هم تصویر محصول در صفحه جزئیات، دارای view-transition-name
با مقدار `product-image-123` هستند. هنگامی که کاربر از صفحه لیست به صفحه جزئیات میرود، مرورگر یک ::view-transition-group
برای این تصویر ایجاد میکند و تصویر به آرامی بین موقعیتها و اندازههای قدیمی و جدید خود انتقال مییابد.
کنترل استایلهای عناصر انتقال
قدرت واقعی موتور شبهعنصر در توانایی استایلدهی به این شبهعنصرها با استفاده از CSS نهفته است. این به شما امکان میدهد تا هر جنبه از انتقال را سفارشی کنید، از موقعیت و اندازه عناصر گرفته تا شفافیت، چرخش و سایر ویژگیهای بصری آنها.
برای هدف قرار دادن یک شبهعنصر خاص، از انتخابگر شبهعنصر مناسب در CSS خود استفاده میکنید:
::view-transition-group(transition-name)
:::view-transition-group
مرتبط با یکview-transition-name
خاص را انتخاب میکند.::view-transition-image-pair(transition-name)
:::view-transition-image-pair
مرتبط با یکview-transition-name
خاص را انتخاب میکند.::view-transition-old(transition-name)
:::view-transition-old
مرتبط با یکview-transition-name
خاص را انتخاب میکند.::view-transition-new(transition-name)
:::view-transition-new
مرتبط با یکview-transition-name
خاص را انتخاب میکند.
آرگومان transition-name
مقدار خاصیت view-transition-name
است که میخواهید هدف قرار دهید. اگر transition-name
را حذف کنید، انتخابگر برای *همه* شبهعنصرهای آن نوع اعمال خواهد شد.
مثال: محو کردن نمای قدیمی
برای محو کردن نمای قدیمی در طول انتقال، میتوانید از CSS زیر استفاده کنید:
::view-transition-old(product-image-123) {
animation: fade-out 0.5s forwards;
}
@keyframes fade-out {
from { opacity: 1; }
to { opacity: 0; }
}
این کد CSS، شبهعنصر ::view-transition-old
مرتبط با نام انتقال product-image-123
را هدف قرار میدهد و یک انیمیشن محو شدن را به آن اعمال میکند. کلمه کلیدی `forwards` تضمین میکند که عنصر پس از اتمام انیمیشن در حالت نهایی آن (opacity: 0) باقی بماند.
مثال: بزرگنمایی نمای جدید
برای بزرگنمایی نمای جدید در طول انتقال، میتوانید از CSS زیر استفاده کنید:
::view-transition-new(product-image-123) {
transform: scale(1.2);
transition: transform 0.5s ease-in-out;
}
این کد CSS، شبهعنصر ::view-transition-new
مرتبط با نام انتقال product-image-123
را هدف قرار میدهد و یک تبدیل مقیاس (scale) به آن اعمال میکند. خاصیت transition
تضمین میکند که تبدیل مقیاس به آرامی در طول 0.5 ثانیه با یک تابع زمانبندی ease-in-out انیمیشن شود.
مدیریت انتقالهای پیچیده
موتور شبهعنصر در هنگام کار با انتقالهای پیچیده شامل چندین عنصر، واقعاً میدرخشد. با ساختاردهی دقیق HTML و تخصیص مقادیر مناسب view-transition-name
، میتوانید انیمیشنهای هماهنگی ایجاد کنید که تجربه کاربری را بهبود میبخشد.
در اینجا چند نکته برای مدیریت انتقالهای پیچیده آورده شده است:
- انتقالهای خود را برنامهریزی کنید: قبل از شروع کدنویسی، طرحی از حالتهای مختلف UI خود و نحوه انتقال عناصر بین آنها را ترسیم کنید. این به شما کمک میکند تا عناصری را که نیاز به انیمیشن دارند و مقادیر مناسب
view-transition-name
برای تخصیص را شناسایی کنید. - از نامهای انتقال معنادار استفاده کنید: مقادیر
view-transition-name
را انتخاب کنید که به وضوح عنصر در حال انتقال را توصیف کنند. این کار کد شما را برای درک و نگهداری آسانتر میکند. به عنوان مثال، به جای `element-1`، از `product-image` یا `modal-title` استفاده کنید. - عناصر مرتبط را گروهبندی کنید: اگر چندین عنصر دارید که باید با هم انیمیشن شوند، آنها را در یک کانتینر مشترک گروهبندی کنید و همان
view-transition-name
را به کانتینر اختصاص دهید. این به شما امکان میدهد انیمیشنهای هماهنگ را به کل گروه اعمال کنید. - از متغیرهای CSS استفاده کنید: از متغیرهای CSS برای تعریف مقادیر انیمیشن قابل استفاده مجدد، مانند مدت زمان، تأخیر و توابع easing استفاده کنید. این کار حفظ ثبات در سراسر انتقالهای شما را آسانتر میکند.
- دسترسپذیری را در نظر بگیرید: اطمینان حاصل کنید که انتقالهای شما برای کاربران دارای معلولیت قابل دسترس هستند. از استفاده از انیمیشنهای بیش از حد پر زرق و برق یا منحرف کننده خودداری کنید و راههای جایگزین برای دسترسی به همان اطلاعات فراهم کنید. از مدیا کوئری `prefers-reduced-motion` برای غیرفعال کردن انتقالها برای کاربرانی که درخواست حرکت کاهشیافته در تنظیمات سیستم عامل خود کردهاند، استفاده کنید.
مثال: انتقال یک پنجره مودال
یک پنجره مودال را در نظر بگیرید که از کنار صفحه به داخل میلغزد. پنجره مودال شامل یک عنوان، یک توضیحات و یک دکمه بستن است. برای ایجاد یک انتقال روان، میتوانید مقادیر view-transition-name
را به خود پنجره مودال و همچنین به اجزای جداگانه آن اختصاص دهید.
HTML:
<div class="modal" style="view-transition-name: modal-window;">
<h2 style="view-transition-name: modal-title;">Modal Title</h2>
<p style="view-transition-name: modal-description;">Modal Description</p>
<button>Close</button>
</div>
CSS:
::view-transition-group(modal-window) {
animation: slide-in 0.3s ease-out forwards;
transform-origin: top right;
}
@keyframes slide-in {
from { transform: translateX(100%); }
to { transform: translateX(0); }
}
::view-transition-old(modal-title) {
opacity: 0;
}
::view-transition-new(modal-title) {
animation: fade-in 0.3s ease-in forwards;
}
@keyframes fade-in {
from { opacity: 0; }
to { opacity: 1; }
}
/* Consider users who prefer reduced motion */
@media (prefers-reduced-motion: reduce) {
::view-transition-group(modal-window) {
animation: none;
transform: translateX(0);
}
::view-transition-old(modal-title) {
opacity: 1;
}
::view-transition-new(modal-title) {
animation: none;
opacity: 1;
}
}
در این مثال، پنجره مودال از سمت راست به داخل میلغزد، در حالی که عنوان مودال محو و ظاهر میشود. با اختصاص مقادیر مختلف view-transition-name
به پنجره مودال و عنوان آن، میتوانید انیمیشنهای آنها را به طور مستقل کنترل کنید.
تکنیکهای پیشرفته
هنگامی که درک کاملی از اصول اولیه پیدا کردید، میتوانید برخی از تکنیکهای پیشرفته را برای ایجاد انتقالهای پیچیدهتر بررسی کنید:
- سفارشیسازی
::view-transition-image-pair
: شما میتوانید شبهعنصر::view-transition-image-pair
را استایلدهی کنید تا افکتهایی مانند تاری، ماسکگذاری یا اعمال فیلترها بر روی تصویر در حال انتقال ایجاد کنید. - استفاده از جاوا اسکریپت برای کنترل انتقال: در حالی که CSS راه اصلی برای استایلدهی به انتقالهای نما است، شما همچنین میتوانید از جاوا اسکریپت برای کنترل برنامهریزی شده انتقال استفاده کنید. این به شما امکان میدهد تا انتقالهای پویاتر و تعاملیتری را بر اساس ورودی کاربر یا عوامل دیگر ایجاد کنید. API
document.startViewTransition
یک promise را برمیگرداند که پس از تکمیل انتقال resolve میشود، و به شما امکان میدهد کدی را پس از پایان انیمیشن اجرا کنید. - مدیریت عملیات ناهمزمان (asynchronous): اگر انتقال نمای شما شامل عملیات ناهمزمان، مانند دریافت داده از سرور، باشد، باید اطمینان حاصل کنید که انتقال تا زمانی که دادهها بارگیری نشدهاند، شروع نشود. میتوانید از API
document.startViewTransition
در ترکیب با `async/await` برای مدیریت این موضوع استفاده کنید.
مثال: دریافت داده قبل از انتقال
async function navigateToProductDetails(productId) {
const transition = document.startViewTransition(async () => {
// Fetch product data
const product = await fetchProductData(productId);
// Update the DOM with the product details
updateProductDetails(product);
});
await transition.finished;
console.log("Transition complete!");
}
در این مثال، تابع navigateToProductDetails
ابتدا دادههای محصول را با استفاده از تابع fetchProductData
دریافت میکند. پس از بارگیری دادهها، DOM را با جزئیات محصول بهروزرسانی میکند. promise transition.finished
تضمین میکند که انتقال تا زمانی که دادهها بارگیری و DOM بهروزرسانی نشده است، شروع نشود.
سازگاری با مرورگرها و جایگزینها (Fallbacks)
CSS View Transitions API نسبتاً جدید است و پشتیبانی مرورگرها هنوز در حال تکامل است. تا اواخر سال 2023، در Chrome، Edge و Firefox پشتیبانی میشود. Safari پشتیبانی آزمایشی دارد که باید فعال شود. بررسی سازگاری مرورگر قبل از استفاده از API در محیط production بسیار مهم است.
برای اطمینان از یک تجربه کاربری یکسان در همه مرورگرها، ارائه جایگزین برای مرورگرهایی که از View Transitions API پشتیبانی نمیکنند، ضروری است. میتوانید از at-rule @supports
در CSS برای تشخیص پشتیبانی از API و اعمال استایلها یا انیمیشنهای جایگزین بر این اساس استفاده کنید.
مثال: ارائه یک جایگزین
@supports (view-transition-name: none) {
/* View Transitions API is supported */
}
@supports not (view-transition-name: none) {
/* View Transitions API is NOT supported */
/* Provide alternative styles or animations */
.modal {
animation: fade-in 0.3s ease-in forwards;
}
}
در این مثال، at-rule @supports
بررسی میکند که آیا خاصیت view-transition-name
پشتیبانی میشود یا خیر. اگر پشتیبانی نشود، کد داخل بلوک @supports not
اجرا میشود و یک انیمیشن ساده محو شدن و ظاهر شدن به پنجره مودال اعمال میکند.
ملاحظات بینالمللیسازی و بومیسازی
هنگام پیادهسازی انتقالهای نما در یک اپلیکیشن جهانی، مهم است که بینالمللیسازی و بومیسازی را در نظر بگیرید. فرهنگهای مختلف ممکن است ترجیحات متفاوتی برای انیمیشنها و انتقالها داشته باشند. به عنوان مثال، برخی فرهنگها ممکن است انیمیشنهای ظریف و کماهمیت را ترجیح دهند، در حالی که برخی دیگر ممکن است انیمیشنهای پر زرق و برق و پویاتر را بپسندند.
در اینجا چند نکته برای ایجاد انتقالهای نمای بینالمللی و بومیشده آورده شده است:
- استفاده از متغیرهای CSS برای مقادیر انیمیشن: از متغیرهای CSS برای تعریف مدت زمان، تأخیر و توابع easing انیمیشن استفاده کنید. این به شما امکان میدهد تا به راحتی مقادیر انیمیشن را برای زبانهای مختلف تنظیم کنید.
- زبانهای راستبهچپ (RTL) را در نظر بگیرید: اگر اپلیکیشن شما از زبانهای RTL پشتیبانی میکند، باید اطمینان حاصل کنید که انتقالهای نمای شما به درستی برای طرحبندیهای RTL آینهای میشوند. از خواص منطقی CSS، مانند
margin-inline-start
وmargin-inline-end
، برای اطمینان از سازگاری طرحبندیهای شما با جهتهای نوشتاری مختلف استفاده کنید. - انتقالهای خود را در زبانهای مختلف آزمایش کنید: انتقالهای نمای خود را به طور کامل در زبانهای مختلف آزمایش کنید تا اطمینان حاصل کنید که ظاهر و احساس آنها برای هر فرهنگ مناسب است.
بهترین شیوهها
- انتقالها را کوتاه و مختصر نگه دارید: سعی کنید مدت زمان انتقالها حدود 300-500 میلیثانیه باشد. انتقالهای طولانیتر میتوانند احساس کندی ایجاد کرده و تجربه کاربری را مختل کنند.
- از توابع easing برای ایجاد انیمیشنهای با ظاهر طبیعی استفاده کنید: با توابع easing مختلف آزمایش کنید تا آنهایی را که بهترین تناسب را با اپلیکیشن شما دارند، پیدا کنید.
- از انیمیشنهای بیش از حد خودداری کنید: انیمیشنهای زیاد میتوانند طاقتفرسا و منحرفکننده باشند. از انیمیشنها به صورت محدود و تنها زمانی که تجربه کاربری را بهبود میبخشند، استفاده کنید.
- بر روی دستگاهها و مرورگرهای مختلف آزمایش کنید: انتقالهای نمای خود را به طور کامل بر روی دستگاهها و مرورگرهای مختلف آزمایش کنید تا اطمینان حاصل کنید که همانطور که انتظار میرود کار میکنند.
- عملکرد را در اولویت قرار دهید: انتقالهای خود را برای عملکرد بهینه کنید تا اطمینان حاصل شود که باعث هیچگونه تأخیر یا لکنت نمیشوند. هر زمان که ممکن است از خواص CSS با شتاب سختافزاری مانند `transform` و `opacity` استفاده کنید. از انیمیشن کردن خواصی که باعث reflow طرحبندی میشوند، مانند `width` و `height`، خودداری کنید.
- از مدیا کوئری `prefers-reduced-motion` برای احترام به ترجیحات کاربر استفاده کنید.