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 모드 창 열기
다음 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 모드 창 닫힘 처리
창 "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()
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);
opener 창에 포커스 맞추기
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에서 문제 제출