Document Picture-in-Picture API를 사용하면 임의의 HTML 콘텐츠로 채울 수 있는 상시 사용 설정 창을 열 수 있습니다. HTML <video>
요소만 PIP 창에 배치할 수 있도록 하는 기존 <video>
용 PIP 모드 API를 확장합니다.
Document Picture-in-Picture API의 PIP 창은 window.open()
를 통해 열리는 빈 동일 출처 창과 비슷하지만 몇 가지 차이점이 있습니다.
- PIP 모드 창이 다른 창 위에 떠 있습니다.
- PIP 모드 창은 항상 열린 창보다 오래 지속됩니다.
- PIP 창은 탐색할 수 없습니다.
- 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
documentPictureInPicture
에 PIP 모드 창이 열릴 때 실행됩니다.
예
다음 HTML은 맞춤 동영상 플레이어와 버튼 요소를 설정하여 PIP 모드에서 동영상 플레이어를 엽니다.
<div id="playerContainer">
<div id="player">
<video id="video"></video>
</div>
</div>
<button id="pipButton">Open Picture-in-Picture window</button>
PIP 모드 창 열기
다음 JavaScript는 사용자가 버튼을 클릭하여 빈 PIP 모드 창을 열 때 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()
의 width
및 height
옵션을 원하는 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 모드 창에서 이벤트 처리
JavaScript에서 일반적으로 하는 것처럼 버튼과 컨트롤을 만들고 "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()
창 메서드를 사용하여 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()
창 메서드를 사용하여 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 모드 표시 모드
CSS picture-in-picture
표시 모드를 사용하여 웹 앱이 PIP 모드로 표시될 때만 적용되는 특정 CSS 규칙을 작성할 수 있습니다.
@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 PIP 모드 API VideoJS 플레이어 데모로 재생할 수 있습니다. 소스 코드를 확인합니다.
포모도로
pomodoro 웹 앱인 Tomodoro도 가능한 경우 Document Picture-in-Picture API를 활용하고 있습니다 (GitHub pull 요청 참고).
의견
제안사항과 질문이 있으시면 GitHub에서 문제를 제출해 주세요.
유용한 링크
- 공개 설명
- WICG 사양
- Chromium 추적 버그
- ChromeStatus.com 항목
- 깜박임 구성요소:
Blink>Media>PictureInPicture
- TAG 검토
- 실험 의도
- 배송 의도
감사의 말
Jakob Owens의 히어로 이미지