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
- 참인 경우 PIP 모드 창의 '탭으로 돌아가기' 버튼을 숨깁니다. 기본값은 false입니다.
preferInitialWindowPlacement
- 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()
의 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 모드 창을 기본 위치 및 크기로 엽니다.
이전 PIP 모드의 위치나 크기를 재사용하지 않으려면 documentPictureInPicture.requestWindow()
의 preferInitialWindowPlacement
옵션을 true
로 설정합니다.
pipButton.addEventListener("click", async () => {
// Open a Picture-in-Picture window in its default position / size.
const pipWindow = await documentPictureInPicture.requestWindow({
preferInitialWindowPlacement: 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()
창 메서드를 사용하여 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 디스플레이 모드
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 Picture-in-Picture API VideoJS 플레이어 데모를 사용해 볼 수 있습니다. 소스 코드를 확인하세요.
Pomodoro
포모도로 웹 앱인 Tomodoro도 가능한 경우 Document Picture-in-Picture API를 활용합니다. GitHub pull 요청을 참조하세요.
의견 공유하기
제안사항과 질문이 있으면 GitHub에서 문제 제출