포털 실습: 웹에서 원활한 탐색

제안된 Portals API를 통해 어떻게 내비게이션 UX를 개선할 수 있는지 알아봅니다.

우츠노미야 유스케
우츠노미야 유스케

우수한 사용자 환경을 제공하려면 페이지가 빠르게 로드되어야 합니다. 하지만 사용자가 페이지 사이를 이동할 때 표시되는 페이지 전환이라는 것을 간과하는 경우가 많습니다.

Portals라는 새로운 웹 플랫폼 API 제안서는 사용자가 사이트 전반을 탐색할 때 환경을 간소화하여 이를 지원하는 것을 목표로 합니다.

실제 포탈 보기:

포털을 통한 원활한 삽입 및 탐색 제작자: Adam Argyle

포털을 통해 제공되는 기능

단일 페이지 애플리케이션 (SPA)은 멋진 전환을 제공하지만 빌드 복잡성이 높아진 비용이 발생합니다. 다중 페이지 애플리케이션 (MPA)은 빌드가 훨씬 더 쉽지만 페이지 사이에 빈 화면이 표시됩니다.

포털은 MPA의 복잡성이 낮고 SPA가 원활하게 전환된다는 점에서 두 가지 장점을 제공합니다. 임베딩을 사용할 수 있다는 점에서 <iframe>처럼 생각하세요. 하지만 <iframe>와 달리 콘텐츠로 이동할 수 있는 기능도 있습니다.

믿음을 가지세요. 먼저 Chrome Dev Summit 2018에서 선보인 내용을 확인해 보세요.

기존 탐색을 사용하면 브라우저가 대상 렌더링을 완료할 때까지 사용자가 빈 화면을 보고 기다려야 합니다. 포털을 통해 사용자는 애니메이션을 경험할 수 있으며 <portal>는 콘텐츠를 사전 렌더링하고 원활한 탐색 환경을 만듭니다.

포탈 이전에는 <iframe>를 사용하여 다른 페이지를 렌더링할 수 있습니다. 페이지에서 프레임을 이동하는 애니메이션도 추가할 수 있었습니다. 하지만 <iframe>를 사용하면 콘텐츠로 이동할 수 없습니다. 포털은 이러한 간극을 메우므로 흥미로운 사용 사례를 만들 수 있습니다.

Portal 사용해 보기

about://flags를 통해 사용 설정 중입니다.

실험용 플래그를 전환하여 Chrome 85 이상 버전에서 포털을 사용해 보세요.

  • 동일 출처 탐색에 about://flags/#enable-portals 플래그를 사용 설정합니다.
  • 교차 출처 탐색을 테스트하려면 about://flags/#enable-portals-cross-origin 플래그도 사용 설정합니다.

또한 포털 실험 초기 단계에서는 --user-data-dir 명령줄 플래그를 설정하여 완전히 별개의 사용자 데이터 디렉터리를 테스트에 사용하는 것이 좋습니다. 포털이 사용 설정되면 DevTools에서 새로운 HTMLPortalElement가 있는지 확인합니다.

HTMLPortalElement를 보여주는 DevTools 콘솔의 스크린샷

포털 구현

기본 구현 예를 살펴보겠습니다.

// 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 콘솔에서 다음 코드를 사용하면 위키백과 페이지가 열립니다.

포털 스타일 데모의 gif.

위의 데모와 같이 작동하는 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');
  ...
}

Portal이 어떤 모습인지 빠르게 확인하고 싶다면 uskay-portals-demo.glitch.me를 사용해 보세요. Chrome 85 이상 버전에서 액세스하고 실험용 플래그를 사용 설정해야 합니다.

  1. 미리 보려는 URL을 입력합니다.
  2. 그러면 페이지가 <portal> 요소로 삽입됩니다.
  3. 미리보기를 클릭합니다.
  4. 애니메이션이 끝난 후 미리보기가 활성화됩니다.

포탈 사용 글리치 데모 사용 gif

사양 확인

Web Incubation Community Group (WICG)에서 포털 사양에 대해 활발하게 논의하고 있습니다. 빠르게 알아보려면 몇 가지 주요 시나리오를 살펴보세요. 다음은 숙지해야 할 중요한 세 가지 기능입니다.

  • <portal> 요소: HTML 요소 자체입니다. API는 매우 간단합니다. src 속성, activate 함수, 메시지 인터페이스 (postMessage)로 구성됩니다. activate는 선택적 인수를 사용하여 활성화 시 <portal>에 데이터를 전달합니다.
  • portalHost 인터페이스: portalHost 객체를 window 객체에 추가합니다. 이를 통해 페이지가 <portal> 요소로 삽입되었는지 확인할 수 있습니다. 또한 호스트에 다시 메시지 (postMessage)를 보내기 위한 인터페이스도 제공합니다.
  • PortalActivateEvent 인터페이스: <portal>가 활성화될 때 실행되는 이벤트입니다. 이전 페이지를 <portal> 요소로 검색하는 데 사용할 수 있는 adoptPredecessor라는 멋진 함수가 있습니다. 이를 통해 두 페이지 간에 원활한 탐색과 구성된 환경을 만들 수 있습니다.

기본 사용 패턴 너머를 살펴보겠습니다. 다음은 샘플 코드와 함께 포탈을 사용하여 달성할 수 있는 이점의 일부 목록입니다.

<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
    });
  }
});

Portal에서 지원하는 모든 기능을 결합하여 멋진 사용자 환경을 구축할 수 있습니다. 예를 들어 아래 데모는 포털이 웹사이트와 서드 파티 삽입 콘텐츠 간에 원활한 사용자 환경을 지원하는 방법을 보여줍니다.

사용 사례 및 계획

이 짧은 Portal 둘러보기가 도움이 되었기를 바랍니다. 어떤 프로젝트를 제출하실지 기대되네요. 예를 들어 제품 카테고리 등록정보 페이지에서 베스트셀러 제품 페이지를 사전 렌더링하는 것과 같은 간단한 탐색을 위해 포털을 사용하기 시작할 수 있습니다.

또 다른 중요한 점은 <iframe>와 마찬가지로 교차 출처 탐색에서 Portal을 사용할 수 있다는 것입니다. 따라서 서로 참조하는 웹사이트가 여러 개 있는 경우 포털을 사용하여 서로 다른 두 웹사이트 간에 원활한 탐색을 만들 수도 있습니다. 이러한 교차 출처 사용 사례는 포털에만 적용할 수 있으며 SPA의 사용자 환경을 개선할 수도 있습니다.

의견 보내기

포털은 Chrome 85 이상 버전에서 실험할 수 있습니다. 커뮤니티의 의견은 새로운 API를 설계하는 데 중요한 역할을 합니다. 사용해 보고 의견을 들려주세요. 기능 요청 또는 의견이 있는 경우 WICG GitHub 저장소를 방문하세요.