문서 PIP 모드 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입니다.
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 모드 창 열기
다음 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 모드 창을 기본 위치와 크기로 엽니다.
이전 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 모드 창이 닫힐 때 처리
PIP 모드 창이 닫히는 시점을 알려면 (웹사이트에서 시작했거나 사용자가 수동으로 닫았기 때문에) 창 "pagehide"
이벤트를 수신 대기합니다. 이벤트 핸들러는 여기에서와 같이 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 Picture-in-Picture API VideoJS 플레이어 데모를 사용해 볼 수 있습니다.
포모도로
포모도로 웹 앱인 Tomodoro도 사용 가능한 경우 문서 PIP API를 활용합니다. GitHub 풀 요청을 참고하세요.

의견 공유
GitHub에 문제 제출을 통해 제안사항과 질문을 보내주세요.