جلوگیری از مشکلات برش (و موارد دیگر) در انتقال‌های نما بااستفاده از گروه‌های انتقال نمای تودرتو

تاریخ انتشار: ۲۲ سپتامبر ۲۰۲۵

وقتی انتقال نما را شروع می‌کنید، مرورگر به‌طور خودکار عکس‌های آنی قبل و بعد از عناصر برچسب‌گذاری‌شده با view-transition-name را می‌گیرد. این عکس‌های آنی در درختی از شبه‌عناصر رندر می‌شوند. به‌طور پیش‌فرض، درخت تولیدشده «مسطح» است. این یعنی سلسله‌مراتب اصلی در DOM ازبین می‌رود و همه گروه‌های انتقال نمای ضبط‌شده به‌عنوان خواهر و برادر تحت یک شبه‌عنصر ::view-transition قرار می‌گیرند.

این رویکرد درخت مسطح برای بسیاری از موارد استفاده کافی است، اما برخی موارد استفاده سبک‌بندی وجود دارد که با آن قابل دستیابی نیست. در زیر نمونه‌هایی از جلوه‌هایی آورده شده است که می‌توانند جلوه دیداری غیرمنتظره‌ای در درخت مسطح داشته باشند:

  • برش (overflow، clip-path، border-radius): برش بر فرزندان عنصر تأثیر می‌گذارد، به این معنی که خواهر و برادرهای گروه انتقال نما نمی‌توانند یکدیگر را برش دهند.
  • ‫opacity، mask-image، و filter: به‌طور مشابه، این جلوه‌ها برای اعمال شدن روی تصویر کاملاً شطرنجی‌شده درخت طراحی شده‌اند و به‌جای اینکه روی هر مورد به‌طور جداگانه تأثیر بگذارند، روی فرزندان تأثیر می‌گذارند.
  • تبدیل‌های سه‌بعدی (transform-style، transform، perspective): برای نمایش طیف کامل پویانمایی‌های تبدیل سه‌بعدی، باید سلسله‌مراتبی حفظ شود.

مثال زیر یک شبه‌درخت مسطح را نشان می‌دهد که عناصر آن توسط یک عنصر والد در درخت DOM بریده شده‌اند. این عناصر درطول انتقال نما، برش خود را ازدست می‌دهند و درنتیجه جلوه بصری خراب می‌شود.

ضبط جلوه برش خراب هنگام اجرای گذار نما. نوشتار باید توسط کادر گفتگو بریده شود، اما این اتفاق نمی‌افتد. زمان پویانمایی برای اغراق در جلوه کند شده است.

گروه‌های انتقال نمای تودرتو افزونه‌ای برای انتقال‌های نما است که به شما امکان می‌دهد شبه‌عناصر ::view-transition-group را در یکدیگر تودرتو کنید. وقتی گروه‌های انتقال نما تودرتو هستند، می‌توان جلوه‌هایی مانند برش را درطول انتقال بازیابی کرد.

Browser Support

  • Chrome: 140.
  • Edge: 140.
  • Firefox: not supported.
  • Safari: not supported.

از شبه‌درخت مسطح به شبه‌درخت تودرتو

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

نسخه نمایشی زنده

ضبط نمایشی

ضبط نمایشی (آهسته شده)

اگر به نسخه نمایشی دقت کنید، متوجه می‌شوید که مشکلی در انتقال وجود دارد: با اینکه پاراگراف‌های حاوی توضیحات فرزندان عنصر <dialog> در DOM هستند، اما متن درطول انتقال توسط کادر <dialog> بریده نمی‌شود:

<dialog id="info_bramus" closedby="any">
  <h2><img alt="…" class="avatar" height="96" width="96" src="avatar_bramus.jpg"> <span>Bramus</span></h2>
  <p>Bramus is …</p>
  <p>…</p>
</dialog>

اعمال کردن overflow: clip روی <dialog> هم کاری انجام نمی‌دهد.

مشکل نحوه ساخت و ارائه درخت شبه‌عنصر توسط انتقال‌های نما است:

  • در شبه‌درخت، به‌طور پیش‌فرض، همه عکس‌های آنی خواهر و برادر یکدیگر هستند.
  • شبه‌درخت در شبه‌عنصر ::view-transition رندر می‌شود که در بالای کل سند رندر می‌شود.

به‌طور خاص برای این نسخه نمایشی، درخت DOM به‌صورت زیر است:

html
  ├─ ::view-transition
  │  ├─ ::view-transition-group(card)
  │  │  └─ ::view-transition-image-pair(card)
  │  │     ├─ ::view-transition-old(card)
  │  │     └─ ::view-transition-new(card)
  │  ├─ ::view-transition-group(name)
  │  │  └─ ::view-transition-image-pair(name)
  │  │     ├─ ::view-transition-old(name)
  │  │     └─ ::view-transition-new(name)
  │  ├─ ::view-transition-group(avatar)
  │  │  └─ ::view-transition-image-pair(avatar)
  │  │     ├─ ::view-transition-old(avatar)
  │  │     └─ ::view-transition-new(avatar)
  │  ├─ ::view-transition-group(paragraph1.text)
  │  │  └─ ::view-transition-image-pair(paragraph1.text)
  │  │     └─ ::view-transition-new(paragraph1.text)
  │  └─ ::view-transition-group(paragraph2.text)
  │     └─ ::view-transition-image-pair(paragraph2.text)
  │        └─ ::view-transition-new(paragraph2.text)
  ├─ head
  └─ body
        └─ …

چون شبه‌های ::view-transition-group(.text) خواهر و برادران موفق شبه ::view-transition-group(card) هستند، روی کارت رنگ‌آمیزی می‌شوند.

برای اینکه ::view-transition-group(card) کلیپ ::view-transition-group(.text) داشته باشد، شبه‌های ::view-transition-group(.text) باید فرزندان ::view-transition-group(card) باشند. برای این کار، از view-transition-group استفاده کنید که به شما امکان می‌دهد یک «گروه والد» برای شبه‌عنصر ::view-transition-group() تولیدشده اختصاص دهید.

برای تغییر گروه ولی، دو گزینه دارید:

  • در والد، view-transition-group را روی contain تنظیم کنید تا همه فرزندان را با view-transition-name دربرگیرد.
  • در همه عناصر فرزند، view-transition-group را روی view-transition-name عنصر ولی تنظیم کنید. همچنین می‌توانید از nearest برای هدف‌یابی نزدیک‌ترین گروه اجدادی استفاده کنید.

بنابراین برای این نسخه نمایشی، برای استفاده از گروه‌های انتقال نمای تودرتو، کد به این صورت می‌شود:

button.clicked,
dialog {
  view-transition-group: contain;
}

یا

button.clicked,
dialog *,
  view-transition-group: nearest;
}

با قرار دادن این کد، شبه‌های ::view-transition-group(.text) اکنون در شبه ::view-transition-group(card) تودرتو می‌شوند. این کار در یک شبه‌کلاس ::view-transition-group-children(…) اضافی انجام می‌شود که همه شبه‌کلاس‌های تودرتو را باهم نگه می‌دارد:

html
  ├─ ::view-transition
  │  ├─ ::view-transition-group(card)
  │  │  ├─::view-transition-group-children(card)
  │  │  │ ├─ ::view-transition-group(paragraph1.text)
  │  │  │ │  └─ ::view-transition-image-pair(paragraph1.text)
  │  │  │ │     └─ ::view-transition-new(paragraph1.text)
  │  │  │ └─ ::view-transition-group(paragraph2.text)
  │  │  │    └─ ::view-transition-image-pair(paragraph2.text)
  │  │  │       └─ ::view-transition-new(paragraph2.text)
  │  │  └─ ::view-transition-image-pair(card)
  │  │     ├─ ::view-transition-old(card)
  │  │     └─ ::view-transition-new(card)
  │  ├─ ::view-transition-group(name)
  │  │  └─ ::view-transition-image-pair(name)
  │  │     ├─ ::view-transition-old(name)
  │  │     └─ ::view-transition-new(name)
  │  └─ ::view-transition-group(avatar)
  │     └─ ::view-transition-image-pair(avatar)
  │        ├─ ::view-transition-old(avatar)
  │        └─ ::view-transition-new(avatar)
  ├─ head
  └─ body
        └─ …

درنهایت، برای اینکه ::view-transition-group(card) پاراگراف‌ها را شبه‌برش دهد، overflow: clip را روی شبه ::view-transition-group-children(card) اعمال کنید:

::view-transition-group-children(card) {
  overflow: clip;
}

نتیجه به‌صورت زیر است:

نسخه نمایشی زنده

ضبط نمایشی

ضبط نمایشی (آهسته شده)

شبه ::view-transition-group-children فقط زمانی وجود دارد که از گروه‌های تودرتو استفاده شود. اندازه آن با border-box عنصر اصلی مطابقت دارد و یک حاشیه شفاف با همان شکل و ضخامت حاشیه عنصر تولیدکننده شبه‌عنصر (card در مثال قبلی) به آن اختصاص داده می‌شود.

برش دادن و موارد دیگر

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

html:active-view-transition-type(open) {
    &::view-transition-old(card) {
        animation-name: rotate-out;
    }
    &::view-transition-new(card) {
        animation-name: rotate-in;
    }
}
html:active-view-transition-type(close) {
    &::view-transition-old(card) {
        animation-name: rotate-in;
    }
    &::view-transition-new(card) {
        animation-name: rotate-out;
    }
}

بدون گروه‌های انتقال نمای تودرتو، چهرک و نام همراه با کارت نمی‌چرخند.

نسخه نمایشی زنده

ضبط نمایشی

ضبط نمایشی (آهسته شده)

با تودرتو کردن شبه‌عنصرهای چهرک و نام در داخل کارت، جلوه سه‌بعدی را می‌توان بازیابی کرد. اما این تنها کاری نیست که باید انجام دهید. علاوه‌بر چرخاندن شبه‌های ::view-transition-old(card) و ::view-transition-new(card)، باید شبه ::view-transition-group-children(card) را هم بچرخانید.

html:active-view-transition-type(open) {
    &::view-transition-group-children(card) {
        animation: rotate-in var(--duration) ease;
        backface-visibility: hidden;
    }
}
html:active-view-transition-type(close) {
    &::view-transition-group-children(card) {
        animation: rotate-out var(--duration) ease;
        backface-visibility: hidden;
    }
}

نسخه نمایشی زنده

ضبط نمایشی

ضبط نمایشی (آهسته شده)

نسخه‌های نمایشی بیشتر

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

نسخه نمایشی زنده

ضبط نمایشی

نکته جالب درباره این نسخه نمایشی این است که همه شبه‌عناصر ::view-transition-group(.card) در داخل شبه‌عنصر جد ::view-transition-group(cards) تودرتو می‌شوند و توسط آن برش می‌خورند. #targeted-card مستثنی شده است زیرا پویانمایی ورود/خروج آن نباید توسط ::view-transition-group(cards) بریده شود.

/* The .cards wrapper contains all children */
.cards {
  view-transition-name: cards;
  view-transition-group: contain;
}

/* Contents that bleed out get clipped */
&::view-transition-group-children(cards) {
  overflow: clip;
}

/* Each card is given a v-t-name and v-t-class */
.card {
  view-transition-name: match-element;
  view-transition-class: card;
}

/* The targeted card is given a unique name (to style the pseudo differently)
   and shouldn't be contained by the ::view-transition-group-children(cards) pseudo */
#targeted-card {
  view-transition-name: targeted-card;
  view-transition-group: none;
}

خلاصه

انتقال‌های نمای تودرتو به شما امکان می‌دهند هنگام ساختن عناصر کاذب، بخشی از توپولوژی درخت DOM را حفظ کنید. این کار انواع مختلفی از جلوه‌ها را باز می‌کند که قبلاً با انتقال‌های نما امکان‌پذیر نبود، برخی‌از آن‌ها را در اینجا شرح داده‌ایم.

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