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

منتشر شده: ۲۸ آگوست ۲۰۲۵

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

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

انتقال بین اسناد در ابزارهای مرورگر بومی، انقلابی در این زمینه ایجاد می‌کند و ما مشتاقیم ببینیم که چگونه آینده وب را شکل خواهد داد.

Browser Support

  • کروم: ۱۲۶.
  • لبه: ۱۲۶.
  • فایرفاکس: پشتیبانی نمی‌شود.
  • سافاری: ۱۸.۲.

Source

تغییر وضع موجود

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

ما ابتدا این استراتژی بهبود تدریجی را با کاربران داخلی خود آزمایش کردیم. این کار بازخورد اولیه‌ای را برای ما فراهم کرد که بسیار مثبت بود. بازخوردهای دریافتی همچنین اشکالاتی را نشان داد، از جمله مشکلات عملکرد و تعاملات ناخواسته با سایر ویژگی‌ها مانند همپوشانی زمینه‌های پشته‌سازی.

ما این استراتژی را موفقیت‌آمیز یافتیم و من معتقدم که در آینده آن را با سایر ویژگی‌های جدید مرورگر امتحان خواهیم کرد.

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

تایمرهای تأخیر، مسدود کردن رندر و واچ‌داگ

در مجموع، تأخیر اضافه‌ای که با انتقال نمای MPA همراه است، برای ۹۹٪ موارد استفاده، به خصوص در سخت‌افزارهای مدرن، ناچیز است. با این حال، جستجوی گوگل از نظر تأخیر، استاندارد بسیار بالایی دارد و ما تلاش می‌کنیم تا تجربیات کاربری ایجاد کنیم که در همه دستگاه‌ها به خوبی کار کند. برای ما، حتی چند میلی‌ثانیه اضافی هم مهم است، بنابراین مجبور شدیم روی نحوه پیاده‌سازی صحیح انتقال نمای بین اسناد بدون آسیب رساندن به تجربه کاربری برای هر کسی سرمایه‌گذاری کنیم.

مسدود کردن رندر تکنیکی است که به خوبی با انتقال‌های نمای بین سندی جفت می‌شود. عکس‌های فوری شبه عنصر از سند ورودی فقط می‌توانند محتوایی را نمایش دهند که قبلاً رندر شده است. بنابراین، برای متحرک‌سازی محتوا از سند ورودی، باید بلوک رندر را تا زمانی که عنصر هدفی که می‌خواهید متحرک‌سازی کنید رندر شود، نگه دارید. برای انجام این کار از ویژگی blocking در یک HTMLLinkElement استفاده کنید. مسدود کردن رندر دارای معایبی است زیرا انتظار برای عنصری که در انتهای درخت DOM سند ورودی قرار دارد، ممکن است تأثیر تأخیر قابل توجهی داشته باشد. ما مجبور بودیم این بده‌بستان را بر این اساس متعادل کنیم و فقط بلوک رندر را روی عناصری که در چرخه عمر صفحه بسیار زود رندر می‌شوند، اعمال کنیم.

<!-- Link tag in the <head> of the incoming document -->
<link blocking="render" href="#target-id" rel="expect">
<!-- Element you want to animate in the <body> of the incoming document -->
<div id="target-id">
  some content
</div>

در برخی موارد، دقت در مورد اینکه روی کدام عنصر بلوک رندر را اجرا می‌کنید کافی نبود. برخی دستگاه‌ها یا اتصالات حتی هنگام رندر بلاک روی عنصری نزدیک به ابتدای درخت DOM، همچنان تأخیر بیشتری را مشاهده می‌کردند. برای مدیریت این موارد، ما یک اسکریپت تایمر watchdog نوشتیم تا HTMLLinkElement را پس از گذشت مدت زمان مشخصی حذف کند تا رندر سند ورودی را از حالت مسدود خارج کند.

یک روش ساده برای انجام این کار به شرح زیر است:

function unblockRendering() {
  const renderBlockingElements = document.querySelectorAll(
    'link[blocking=render]',
  );
  for (const element of renderBlockingElements) {
    element.remove();
  }
}

const timeToUnblockRendering = t - performance.now();

if (timeToUnblockRendering > 0) {
  setTimeout(unblockRendering, timeToUnblockRendering);
} else {
  unblockRendering();
}

محدودیت‌های پوشش

مشکل دیگری که با آن مواجه شدیم این است که انتقال نمای بین اسنادی navigation: auto به صورت سراسری در سند اتفاق می‌افتد. هیچ راه داخلی برای محدود کردن فعال‌سازی انتقال نمای بین اسنادی فقط به اهداف کلیک خاص وجود ندارد. از آنجایی که این تغییر بزرگی است، ما نمی‌توانستیم انتقال نمای بین اسنادی را در ۱۰۰٪ ناوبری‌ها در جستجوی گوگل فعال کنیم. ما به روشی نیاز داشتیم تا انتقال نمای بین اسنادی را بسته به اینکه کاربر با چه ویژگی‌ای در تعامل است، به صورت پویا فعال یا غیرفعال کنیم. در مورد ما، ما فقط آنها را برای تغییر حالت به حالت هوش مصنوعی و از حالت هوش مصنوعی فعال کردیم. ما این کار را با به‌روزرسانی برنامه‌ریزی‌شده‌ی ناوبری در حالت at-rule بسته به اینکه کدام هدف کلیک یا لمس شده است، انجام دادیم.

روشی برای تغییر وضعیت انتقال نما در at-rule به شرح زیر است:

let viewTransitionAtRule: HTMLElement | undefined;
const DISABLED_VIEW_TRANSITION = '@view-transition{navigation:none;}';
const ENABLED_VIEW_TRANSITION = '@view-transition{navigation:auto;}';

function getVtAtRule(): HTMLElement {
  if (!viewTransitionAtRule) {
    viewTransitionAtRule = document.createElement('style');
    document.head.append(viewTransitionAtRule);
  }
  return viewTransitionAtRule;
}

function disableVt() {
  getVtAtRule().textContent = DISABLED_VIEW_TRANSITION;
}

function enableVt() {
  getVtAtRule().textContent = ENABLED_VIEW_TRANSITION;
}

انیمیشن‌های Jank و ترکیبی

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

const pseudoElement = `::view-transition-group(${name})`;
const animation = document
  .getAnimations()
  .find(
    (animation) =>
      (animation.effect as KeyframeEffect)?.pseudoElement === pseudoElement,
  );

برای اطلاعات بیشتر در مورد نوشتن فریم‌های کلیدی انتقال نمای کارآمد، به بخش «انتقال‌های نمای اعمال‌شده: کار با بلوک حاوی اسنپ‌شات» مراجعه کنید.

موارد دیگری که باید مراقب آنها باشید

یکی از مسائل برجسته‌تر این است که برچسب‌گذاری عناصر با ویژگی CSS مربوط به view-transition-name بر روی زمینه‌ی پشته‌سازی تأثیر می‌گذارد ( مشخصات انتقال‌های View: بخش 2.1.1 ). این موضوع منشأ چندین اشکال بود که نیاز به اصلاح z-index عناصر نگهدارنده داشتند.

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

مثال CSS برای اضافه کردن view-transition-name مربوط به the-element به یک عنصر، تنها زمانی که نوع انتقال نمای ai-mode فعال باشد:

html:active-view-transition-type(ai-mode) {
  #target {
    view-transition-name: the-element;
  }
}

زمانی که این قوانین CSS را برای همه انتقال‌های نمای خود تنظیم کردید، می‌توانید به صورت پویا نوع انتقال نمای فعلی را برای هر ناوبری در طول رویدادهای pageswap و pagereveal تغییر دهید.

مثالی از به‌روزرسانی نوع انتقال نما به ai-mode در طول رویداد pageswap .

function updateViewTransitionTypes(
  event: ViewTransitionEvent,
  types: string[],
): void {
  event.viewTransition.types.clear();
  for (const type of types) {
    event.viewTransition.types.add(type);
  }
}

window.addEventListener(
  'pageswap',
  (e) => {
    updateViewTransitionTypes(
      e as ViewTransitionEvent,
      ['ai-mode'],
    );
  }
);

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

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

::view-transition-group(the-element) {
  z-index: 100;
}

قدم بعدی چیست؟

ما برنامه‌هایی برای استفاده از انتقال‌های نمای بین اسنادی برای جستجوی گوگل داریم، از جمله ادغام با API ناوبری پس از در دسترس قرار گرفتن آن در مرورگرهای مختلف. منتظر باشید تا ببینید در نهایت چه چیزی خواهیم ساخت!