Практический опыт работы с порталами: плавная навигация в Интернете

Узнайте, как предлагаемый API порталов может улучшить UX вашей навигации.

Юсуке Уцуномия
Yusuke Utsunomiya

Обеспечение быстрой загрузки страниц является ключом к обеспечению хорошего пользовательского опыта. Но одна область, которую мы часто упускаем из виду, — это переходы страниц — то, что видят наши пользователи, когда перемещаются между страницами.

Новое предложение API веб-платформы под названием «Порталы» призвано помочь в этом, упрощая работу пользователей при навигации по вашему сайту.

Посмотрите порталы в действии:

Бесшовное встраивание и навигация с порталами. Создан Адамом Аргайлом .

Что позволяют порталы

Одностраничные приложения (SPA) предлагают хорошие переходы, но их создание требует большей сложности. Многостраничные приложения (MPA) создавать гораздо проще, но между страницами остаются пустые экраны.

Порталы предлагают лучшее из обоих миров: низкую сложность MPA и плавные переходы SPA. Думайте о них как о <iframe> , поскольку они допускают встраивание, но в отличие от <iframe> они также имеют функции для перехода к их содержимому.

Увидеть – значит поверить: сначала посмотрите, что мы продемонстрировали на Chrome Dev Summit 2018:

При классической навигации пользователям приходится ждать с пустым экраном, пока браузер не завершит отображение пункта назначения. С помощью порталов пользователи могут увидеть анимацию, а <portal> предварительно отображает контент и обеспечивает плавную навигацию.

До появления порталов мы могли визуализировать другую страницу с помощью <iframe> . Мы также могли бы добавить анимацию для перемещения рамки по странице. Но <iframe> не позволит вам перемещаться по его содержимому. Порталы закрывают этот пробел, обеспечивая интересные варианты использования.

Попробуйте порталы

Включение через about://flags

Попробуйте порталы в Chrome 85 и более поздних версиях, установив экспериментальный флаг:

  • Включите about://flags/#enable-portals для навигации по тому же источнику.
  • Для тестирования навигации между источниками дополнительно включите флаг about://flags/#enable-portals-cross-origin .

На этом раннем этапе эксперимента с порталами мы также рекомендуем использовать для ваших тестов совершенно отдельный каталог пользовательских данных, установив флаг командной строки --user-data-dir . После включения порталов подтвердите в DevTools, что у вас есть новый блестящий HTMLPortalElement .

Снимок экрана консоли DevTools, показывающий HTMLPortalElement.

Реализация порталов

Давайте рассмотрим базовый пример реализации.

// Create a portal with the wikipedia page, and embed it
// (like an iframe). You can also use the <portal> tag instead.
portal = document.createElement('portal');
portal.src = 'https://en.wikipedia.org/wiki/World_Wide_Web';
portal.style = '...';
document.body.appendChild(portal);

// When the user touches the preview (embedded portal):
// do fancy animation, e.g. expand …
// and finish by doing the actual transition.
// For the sake of simplicity, this snippet will navigate
// on the `onload` event of the Portals element.
portal.addEventListener('load', (evt) => {
   portal.activate();
});

Это так просто. Попробуйте этот код в консоли DevTools, должна открыться страница Википедии.

Гифка демо-версии стиля предварительного просмотра портала

Если вы хотите создать что-то вроде того, что мы показали на Chrome Dev Summit, которое работает так же, как демо-версия выше, вам будет интересен следующий фрагмент.

// Adding some styles with transitions
const style = document.createElement('style');
style.innerHTML = `
  portal {
    position:fixed;
    width: 100%;
    height: 100%;
    opacity: 0;
    box-shadow: 0 0 20px 10px #999;
    transform: scale(0.4);
    transform-origin: bottom left;
    bottom: 20px;
    left: 20px;
    animation-name: fade-in;
    animation-duration: 1s;
    animation-delay: 2s;
    animation-fill-mode: forwards;
  }
  .portal-transition {
    transition: transform 0.4s;
  }
  @media (prefers-reduced-motion: reduce) {
    .portal-transition {
      transition: transform 0.001s;
    }
  }
  .portal-reveal {
    transform: scale(1.0) translateX(-20px) translateY(20px);
  }
  @keyframes fade-in {
    0%   { opacity: 0; }
    100% { opacity: 1; }
  }
`;
const portal = document.createElement('portal');
// Let's navigate into the WICG Portals spec page
portal.src = 'https://wicg.github.io/portals/';
// Add a class that defines the transition. Consider using
// `prefers-reduced-motion` media query to control the animation.
// https://developers.google.com/web/updates/2019/03/prefers-reduced-motion
portal.classList.add('portal-transition');
portal.addEventListener('click', (evt) => {
  // Animate the portal once user interacts
  portal.classList.add('portal-reveal');
});
portal.addEventListener('transitionend', (evt) => {
  if (evt.propertyName == 'transform') {
    // Activate the portal once the transition has completed
    portal.activate();
  }
});
document.body.append(style, portal);

Также легко определить функции для постепенного улучшения веб-сайта с помощью порталов.

if ('HTMLPortalElement' in window) {
  // If this is a platform that have Portals...
  const portal = document.createElement('portal');
  ...
}

Если вы хотите быстро ощутить, что такое порталы, попробуйте использовать uskay-portals-demo.glitch.me . Убедитесь, что вы получаете доступ к нему с помощью Chrome 85 или более поздних версий и включите экспериментальный флаг !

  1. Введите URL-адрес, который вы хотите просмотреть.
  2. Затем страница будет встроена как элемент <portal> .
  3. Нажмите на предварительный просмотр.
  4. Предварительный просмотр будет активирован после анимации.

Гифка использования демо-версии порталов с ошибками.

Ознакомьтесь со спецификацией

Мы активно обсуждаем спецификацию порталов в группе сообщества веб-инкубации (WICG). Чтобы быстро освоиться, взгляните на некоторые ключевые сценарии . Вот три важные особенности, с которыми вам следует ознакомиться:

  • Элемент <portal> : сам элемент HTML. API очень простой. Он состоит из атрибута src , функции activate и интерфейса для обмена сообщениями ( postMessage ). activate принимает необязательный аргумент для передачи данных на <portal> после активации.
  • Интерфейс portalHost : добавляет объект portalHost к объекту window . Это позволяет вам проверить, встроена ли страница как элемент <portal> . Он также предоставляет интерфейс для обмена сообщениями ( postMessage ) обратно на хост.
  • Интерфейс PortalActivateEvent: событие, которое срабатывает при активации <portal> . Существует изящная функция adoptPredecessor , которую можно использовать для получения предыдущей страницы в виде элемента <portal> . Это позволяет создавать плавную навигацию и комбинировать взаимодействие между двумя страницами.

Давайте выйдем за рамки базового шаблона использования. Вот неисчерпывающий список того, чего вы можете достичь с помощью порталов, а также пример кода.

Настройте стиль при внедрении в качестве элемента <portal>

// Detect whether this page is hosted in a portal
if (window.portalHost) {
  // Customize the UI when being embedded as a portal
}

Обмен сообщениями между элементом <portal> и portalHost

// Send message to the portal element
const portal = document.querySelector('portal');
portal.postMessage({someKey: someValue}, ORIGIN);

// Receive message via window.portalHost
window.portalHost.addEventListener('message', (evt) => {
  const data = evt.data.someKey;
  // handle the event
});

Активация элемента <portal> и получение portalactivate

// You can optionally add data to the argument of the activate function
portal.activate({data: {somekey: 'somevalue'}});

// The portal content will receive the portalactivate event
// when the activate happens
window.addEventListener('portalactivate', (evt) => {
  // Data available as evt.data
  const data = evt.data;
});

Получение предшественника

// Listen to the portalactivate event
window.addEventListener('portalactivate', (evt) => {
  // ... and creatively use the predecessor
  const portal = evt.adoptPredecessor();
  document.querySelector('someElm').appendChild(portal);
});

Зная, что ваша страница была принята в качестве предшественницы

// The activate function returns a Promise.
// When the promise resolves, it means that the portal has been activated.
// If this document was adopted by it, then window.portalHost will exist.
portal.activate().then(() => {
  // Check if this document was adopted into a portal element.
  if (window.portalHost) {
    // You can start communicating with the portal element
    // i.e. listen to messages
    window.portalHost.addEventListener('message', (evt) => {
      // handle the event
    });
  }
});

Объединив все функции, поддерживаемые порталами, вы можете создать действительно необычный пользовательский интерфейс. Например, приведенная ниже демонстрация демонстрирует, как порталы могут обеспечить беспрепятственный пользовательский интерфейс между веб-сайтом и встроенным контентом третьих сторон.

Варианты использования и планы

Надеемся, вам понравилась эта краткая экскурсия по Порталам! Нам не терпится увидеть, что вы сможете придумать. Например, вы можете начать использовать порталы для нетривиальной навигации, такой как: предварительная обработка страницы вашего бестселлера со страницы со списком категорий продуктов.

Еще одна важная вещь, которую следует знать, — это то, что порталы можно использовать в навигации между источниками, как и <iframe> . Итак, если у вас есть несколько веб-сайтов, которые ссылаются друг на друга, вы также можете использовать порталы для создания плавной навигации между двумя разными веб-сайтами. Этот вариант использования перекрестного происхождения уникален для порталов и может даже улучшить взаимодействие с пользователем SPA.

Обратная связь приветствуется

Порталы готовы к экспериментированию в Chrome 85 и более поздних версиях. Обратная связь с сообществом имеет решающее значение для разработки новых API, поэтому, пожалуйста, попробуйте и расскажите нам, что вы думаете! Если у вас есть пожелания по функциям или отзывы, перейдите в репозиторий WICG на GitHub .