<동영상> 뿐만 아니라 모든 요소에 대한 PIP 모드

François Beaufort
François Beaufort

브라우저 지원

  • Chrome: 116 <ph type="x-smartling-placeholder">
  • Edge: 116. <ph type="x-smartling-placeholder">
  • Firefox: 지원되지 않음 <ph type="x-smartling-placeholder">
  • Safari: 지원되지 않음 <ph type="x-smartling-placeholder">

소스

Document Picture-in-Picture API를 사용하면 임의의 HTML 콘텐츠로 채울 수 있는 상시 사용 설정 창을 열 수 있습니다. 이는 HTML <video> 요소만 PIP 모드 창에 배치할 수 있도록 하는 기존의 <video>용 PIP 모드 API를 확장합니다.

Document Picture-in-Picture API의 PIP 창은 window.open()를 통해 열린 빈 동일한 출처 창과 비슷하지만 몇 가지 차이점이 있습니다.

  • PIP 모드 창은 다른 창 위에 떠 있습니다.
  • PIP 모드 창이 여는 창보다 오래 지속되지 않습니다.
  • PIP 모드 창을 탐색할 수 없습니다.
  • 웹사이트에서 PIP 모드 창 위치를 설정할 수 없습니다.
를 통해 개인정보처리방침을 정의할 수 있습니다. <ph type="x-smartling-placeholder">
</ph> <ph type="x-smartling-placeholder">Sintel 트레일러 동영상이 재생되는 PIP 모드 창입니다.</ph>
Document Picture-in-Picture API (데모)로 생성된 PIP 창

현재 상태

단계 상태
1. 설명 만들기 완전함
2. 사양의 초기 초안 만들기 진행 중
3. 의견 수집 및 디자인 반복 진행 중
4. 오리진 트라이얼 완전함
5. 개시 완료 (데스크톱)

사용 사례

맞춤 동영상 플레이어

웹사이트에서 기존 <video>용 PIP 모드 API로 PIP 동영상 환경을 제공할 수는 있지만 매우 제한적입니다. 기존의 PIP 모드 창은 몇 가지 입력을 허용하며 스타일 지정 기능이 제한되어 있습니다. 웹사이트에서 PIP 모드 전체 문서를 사용하면 맞춤 컨트롤 및 입력 (예: 자막, 재생목록, 시간 스크러버, 동영상에 좋아요 및 싫어요 표시)을 제공하여 사용자의 PIP 모드 동영상 경험을 개선할 수 있습니다.

화상 회의

사용자가 통화 중에 다른 탭을 표시하거나 멀티태스킹을 하는 등 다양한 이유로 화상 회의 세션 중에 브라우저 탭을 닫는 경우가 많지만 통화를 보고 싶어 하는 경우가 많으므로 PIP 모드의 주요 사용 사례입니다. 다시 한번 말하지만, <video>용 PIP API를 통해 화상 회의 웹사이트에서 제공할 수 있는 현재의 경험은 스타일과 입력 측면에서 제한적입니다. PIP 모드의 전체 문서를 사용하면 웹사이트에서 캔버스 해킹에 의존하지 않고도 여러 동영상 스트림을 하나의 PIP 창으로 쉽게 결합할 수 있으며 메시지 보내기, 다른 사용자 음소거, 손 들기와 같은 맞춤 제어 기능을 제공할 수 있습니다.

생산성

연구에 따르면 사용자가 웹에서 생산성을 발휘하려면 더 많은 방법이 필요합니다. PIP 모드로 문서를 사용하면 웹 앱에서 더 많은 작업을 할 수 있습니다. 이제 웹 앱은 텍스트 편집, 메모 작성, 작업 목록, 메시지 및 채팅, 디자인 및 개발 도구 등 어떤 작업을 하든 콘텐츠에 항상 액세스할 수 있습니다.

인터페이스

속성

documentPictureInPicture.window
현재 PIP 모드 창을 반환합니다(있는 경우). 그렇지 않은 경우 null을 반환합니다.

메서드

documentPictureInPicture.requestWindow(options)

PIP 모드 창이 열릴 때 확인되는 프로미스를 반환합니다. 프로미스가 사용자 동작 없이 호출되면 거부됩니다. options 사전에는 다음과 같은 선택적 멤버가 포함됩니다.

width
PIP 모드 창의 초기 너비를 설정합니다.
height
PIP 모드 창의 초기 높이를 설정합니다.
disallowReturnToOpener
'탭으로 돌아가기' 숨기기 True로 설정한 경우 PIP 모드 창에 표시됩니다. 기본적으로 false입니다.

이벤트

documentPictureInPicture.onenter
PIP 모드 창이 열릴 때 documentPictureInPicture에 실행됩니다.

다음 HTML은 맞춤 동영상 플레이어와 버튼 요소를 설정하여 PIP 모드 창에서 동영상 플레이어를 엽니다.

<div id="playerContainer">
  <div id="player">
    <video id="video"></video>
  </div>
</div>
<button id="pipButton">Open Picture-in-Picture window</button>

PIP 모드 창 열기

사용자가 버튼을 클릭하여 빈 PIP 모드 창을 열 때 다음 JavaScript는 documentPictureInPicture.requestWindow()를 호출합니다. 반환된 프로미스는 PIP 모드 창 JavaScript 객체로 확인됩니다. append()를 사용하여 동영상 플레이어가 창으로 이동합니다.

pipButton.addEventListener('click', async () => {
  const player = document.querySelector("#player");

  // Open a Picture-in-Picture window.
  const pipWindow = await documentPictureInPicture.requestWindow();

  // Move the player to the Picture-in-Picture window.
  pipWindow.document.body.append(player);
});

PIP 모드 창의 크기 설정

PIP 모드의 크기를 설정하려면 documentPictureInPicture.requestWindow()widthheight 옵션을 원하는 PIP 모드 창 크기로 설정합니다. Chrome에서 옵션 값이 너무 크거나 사용자 친화적인 창 크기에 맞지 않는 경우 이 값을 고정할 수 있습니다.

pipButton.addEventListener("click", async () => {
  const player = document.querySelector("#player");

  // Open a Picture-in-Picture window whose size is
  // the same as the player's.
  const pipWindow = await documentPictureInPicture.requestWindow({
    width: player.clientWidth,
    height: player.clientHeight,
  });

  // Move the player to the Picture-in-Picture window.
  pipWindow.document.body.append(player);
});

'탭으로 돌아가기' 숨기기 PIP 모드 창의 버튼

사용자가 시작 탭으로 돌아갈 수 있는 PIP 모드 창에서 버튼을 숨기려면 documentPictureInPicture.requestWindow()disallowReturnToOpener 옵션을 true로 설정합니다.

pipButton.addEventListener("click", async () => {
  // Open a Picture-in-Picture window which hides the "back to tab" button.
  const pipWindow = await documentPictureInPicture.requestWindow({
    disallowReturnToOpener: true,
  });
});

PIP 모드로 스타일 시트를 복사

원래 창에서 모든 CSS 스타일 시트를 복사하려면 문서에 명시적으로 연결되거나 문서에 삽입된 styleSheets를 반복하여 PIP 모드 창에 추가합니다. 이 사본은 일회성이므로

pipButton.addEventListener("click", async () => {
  const player = document.querySelector("#player");

  // Open a Picture-in-Picture window.
  const pipWindow = await documentPictureInPicture.requestWindow();

  // Copy style sheets over from the initial document
  // so that the player looks the same.
  [...document.styleSheets].forEach((styleSheet) => {
    try {
      const cssRules = [...styleSheet.cssRules].map((rule) => rule.cssText).join('');
      const style = document.createElement('style');

      style.textContent = cssRules;
      pipWindow.document.head.appendChild(style);
    } catch (e) {
      const link = document.createElement('link');

      link.rel = 'stylesheet';
      link.type = styleSheet.type;
      link.media = styleSheet.media;
      link.href = styleSheet.href;
      pipWindow.document.head.appendChild(link);
    }
  });

  // Move the player to the Picture-in-Picture window.
  pipWindow.document.body.append(player);
});
드림

PIP 모드 창이 닫힐 때 처리

"pagehide" 이벤트를 수신 대기하여 PIP 모드 창이 언제 닫히는지 알 수 있습니다 (웹사이트에서 시작했거나 사용자가 수동으로 창을 닫음). 이벤트 핸들러는 아래와 같이 요소를 PIP 모드 창 밖으로 다시 가져오기에 적합합니다.

pipButton.addEventListener("click", async () => {
  const player = document.querySelector("#player");

  // Open a Picture-in-Picture window.
  const pipWindow = await documentPictureInPicture.requestWindow();

  // Move the player to the Picture-in-Picture window.
  pipWindow.document.body.append(player);

  // Move the player back when the Picture-in-Picture window closes.
  pipWindow.addEventListener("pagehide", (event) => {
    const playerContainer = document.querySelector("#playerContainer");
    const pipPlayer = event.target.querySelector("#player");
    playerContainer.append(pipPlayer);
  });
});

close() 메서드를 사용하여 프로그래매틱 방식으로 PIP 모드 창을 닫습니다.

// Close the Picture-in-Picture window programmatically. 
// The "pagehide" event will fire normally.
pipWindow.close();

웹사이트가 PIP 모드로 전환될 때 듣기

documentPictureInPicture에서 "enter" 이벤트를 수신 대기하여 PIP 모드 창이 언제 열리는지 확인합니다. 이벤트에는 PIP 모드 창에 액세스할 수 있는 window 객체가 포함되어 있습니다.

documentPictureInPicture.addEventListener("enter", (event) => {
  const pipWindow = event.window;
});

PIP 모드 창의 요소에 액세스

아래와 같이 documentPictureInPicture.requestWindow()에서 반환한 객체 또는 documentPictureInPicture.window를 사용하여 PIP 모드 창의 요소에 액세스합니다.

const pipWindow = documentPictureInPicture.window;
if (pipWindow) {
  // Mute video playing in the Picture-in-Picture window.
  const pipVideo = pipWindow.document.querySelector("#video");
  pipVideo.muted = true;
}

PIP 모드 창에서 이벤트 처리

자바스크립트에서 일반적으로 하는 것처럼 버튼과 컨트롤을 만들고 "click"과 같은 사용자의 입력 이벤트에 응답합니다.

// Add a "mute" button to the Picture-in-Picture window.
const pipMuteButton = pipWindow.document.createElement("button");
pipMuteButton.textContent = "Mute";
pipMuteButton.addEventListener("click", () => { 
  const pipVideo = pipWindow.document.querySelector("#video");
  pipVideo.muted = true;
});
pipWindow.document.body.append(pipMuteButton);

PIP 모드 창 크기 조정

resizeBy()resizeTo() Window 메서드를 사용하여 PIP 모드 창의 크기를 조절합니다. 두 메서드 모두 사용자 동작이 필요합니다.

const resizeButton = pipWindow.document.createElement('button');
resizeButton.textContent = 'Resize';
resizeButton.addEventListener('click', () => {
  // Expand the Picture-in-Picture window's width by 20px and height by 30px.
  pipWindow.resizeBy(20, 30);
});
pipWindow.document.body.append(resizeButton);

오프너 창에 포커스

focus() Window 메서드를 사용하여 PIP 모드 창에서 오프너 창에 포커스를 맞춥니다. 이 메서드에는 사용자 동작이 필요합니다.

const returnToTabButton = pipWindow.document.createElement("button");
returnToTabButton.textContent = "Return to opener tab";
returnToTabButton.addEventListener("click", () => {
  window.focus();
});
pipWindow.document.body.append(returnToTabButton);

CSS PIP 표시 모드

웹 앱이 PIP 모드로 표시될 때만 적용되는 특정 CSS 규칙을 작성하려면 CSS picture-in-picture 표시 모드를 사용하세요.

@media all and (display-mode: picture-in-picture) {
  body {
    margin: 0;
  }
  h1 {
    font-size: 0.8em;
  }
}

특성 감지

Document Picture-in-Picture API가 지원되는지 확인하려면 다음을 사용합니다.

if ('documentPictureInPicture' in window) {
  // The Document Picture-in-Picture API is supported.
}

데모

VideoJS 플레이어

Document Picture-in-Picture API VideoJS 플레이어 데모로 재생할 수 있습니다. 소스 코드를 확인하세요.

포모도로

pomodoro 웹 앱인 Tomodoro도 가능한 경우 Document Picture-in-Picture API를 활용하고 있습니다 (GitHub pull 요청 참고).

<ph type="x-smartling-placeholder">
</ph> pomodoro 웹 앱 Tomodoro 스크린샷
토모도로의 PIP 모드 창

의견

제안사항 및 질문이 있으면 GitHub에서 문제를 제출하세요.

감사의 말씀

히어로 이미지: Jakob Owens