การแสดงภาพซ้อนภาพสำหรับองค์ประกอบใดๆ ไม่ใช่แค่ <วิดีโอ>

François Beaufort
François Beaufort

Browser Support

  • Chrome: 116.
  • Edge: 116.
  • Firefox: not supported.
  • Safari: not supported.

Source

API การแสดงภาพซ้อนภาพของเอกสารช่วยให้เปิดหน้าต่างที่อยู่ด้านบนสุดเสมอซึ่งสามารถแสดงเนื้อหา HTML ที่กำหนดเองได้ โดยจะขยาย Picture-in-Picture API ที่มีอยู่สำหรับ <video> ซึ่งอนุญาตให้วางองค์ประกอบ HTML <video> ลงในหน้าต่างการแสดงภาพซ้อนภาพ (PIP) เท่านั้น

หน้าต่างการแสดงภาพซ้อนภาพใน Document Picture-in-Picture API จะคล้ายกับ หน้าต่างที่ไม่มีเนื้อหาซึ่งมีต้นทางเดียวกันที่เปิดโดยใช้ window.open() โดยมีความแตกต่างบางประการดังนี้

  • หน้าต่างการแสดงภาพซ้อนภาพจะลอยอยู่เหนือหน้าต่างอื่นๆ
  • หน้าต่างการแสดงภาพซ้อนภาพจะไม่มีวันอยู่ได้นานกว่าหน้าต่างที่เปิด
  • ไปยังหน้าต่างการแสดงภาพซ้อนภาพไม่ได้
  • เว็บไซต์ไม่สามารถกำหนดตำแหน่งของหน้าต่างการแสดงภาพซ้อนภาพได้
หน้าต่างการแสดงภาพซ้อนภาพที่เล่นวิดีโอตัวอย่าง Sintel
หน้าต่างภาพซ้อนภาพที่สร้างด้วย Document Picture-in-Picture API (การสาธิต)

สถานะ

ขั้นตอน สถานะ
1. สร้างคำอธิบาย เสร็จสมบูรณ์
2. สร้างร่างข้อกำหนดเบื้องต้น กำลังดำเนินการ
3. รวบรวมความคิดเห็นและทำซ้ำการออกแบบ กำลังดำเนินการ
4. ช่วงทดลองใช้จากต้นทาง เสร็จสมบูรณ์
5. เปิดตัว เสร็จสมบูรณ์ (เดสก์ท็อป)

กรณีการใช้งาน

คุณสามารถใช้ API นี้ได้หลายวิธี เช่น เครื่องเล่นวิดีโอที่กำหนดเอง การประชุมทางวิดีโอ และแอปเพิ่มประสิทธิภาพการทำงาน

วิดีโอเพลเยอร์ที่กำหนดเอง

เว็บไซต์สามารถมอบประสบการณ์การใช้งานวิดีโอแบบ Picture-in-Picture ด้วย Picture-in-Picture API ที่มีอยู่สำหรับ <video> แต่ก็มีข้อจำกัดอย่างมาก หน้าต่าง PIP ที่มีอยู่รับอินพุตได้เพียงไม่กี่รายการ และมีความสามารถในการจัดรูปแบบจำกัด เมื่อใช้เอกสารแบบเต็มในโหมดภาพซ้อนภาพ เว็บไซต์จะให้การควบคุมและอินพุตที่กำหนดเองได้ (เช่น คำบรรยายแทนเสียง เพลย์ลิสต์ แถบเลื่อนเวลา การกดชอบและไม่ชอบวิดีโอ) เพื่อปรับปรุงประสบการณ์การใช้งานวิดีโอ PiP ของผู้ใช้

การประชุมทางวิดีโอ

ผู้ใช้มักจะออกจากแท็บเบราว์เซอร์ชั่วคราวในระหว่างเซสชันการประชุมทางวิดีโอ เช่น เมื่อนำเสนอจากแท็บอื่นในการโทร จดบันทึก หรือกิจกรรมอื่นๆ ที่ต้องทำหลายอย่างพร้อมกัน อย่างไรก็ตาม ในกรณีส่วนใหญ่ ผู้ใช้ยังคงต้องการดูการโทร ดังนั้นนี่จึงเป็นกรณีการใช้งานที่เหมาะสำหรับการแสดงภาพซ้อนภาพ อีกครั้งที่ประสบการณ์การใช้งานปัจจุบันที่เว็บไซต์การประชุมทางวิดีโอสามารถมอบให้ได้ด้วย Picture-in-Picture API สำหรับ <video> มีข้อจำกัดด้านสไตล์และอินพุต เมื่อใช้เอกสารแบบเต็มในโหมดภาพซ้อนภาพ เว็บไซต์จะรวมสตรีมวิดีโอหลายรายการไว้ในหน้าต่าง PIP เดียวได้อย่างง่ายดายโดยไม่ต้องใช้แฮ็ก Canvas และมีตัวควบคุมที่กำหนดเอง เช่น การส่งข้อความ การปิดเสียงผู้ใช้รายอื่น หรือการยกมือ

ประสิทธิภาพการทำงาน

งานวิจัยแสดงให้เห็นว่าผู้ใช้ต้องการวิธีเพิ่มเติมในการทำงานบนเว็บอย่างมีประสิทธิภาพ เอกสารในการแสดงภาพซ้อนภาพช่วยให้เว็บแอปมีความยืดหยุ่นในการทำงานต่างๆ มากขึ้น ไม่ว่าจะเป็นการแก้ไขข้อความ การจดบันทึก รายการงาน การรับส่งข้อความและแชท หรือเครื่องมือออกแบบและพัฒนา เว็บแอปก็สามารถทำให้เนื้อหาเข้าถึงได้เสมอ

SDK โฆษณา B

พร็อพเพอร์ตี้

documentPictureInPicture.window
แสดงหน้าต่างการแสดงภาพซ้อนภาพปัจจุบัน (หากมี) ไม่เช่นนั้นจะแสดงผล null

เมธอด

documentPictureInPicture.requestWindow(options)

แสดงผล Promise ที่จะทำงานเมื่อเปิดหน้าต่างการแสดงภาพซ้อนภาพ Promise จะปฏิเสธหากมีการเรียกใช้โดยไม่มีท่าทางของผู้ใช้ พจนานุกรม options มีสมาชิกต่อไปนี้ซึ่งระบุหรือไม่ก็ได้

width
กำหนดความกว้างเริ่มต้นของหน้าต่างการแสดงภาพซ้อนภาพ
height
กำหนดความสูงเริ่มต้นของหน้าต่างการแสดงภาพซ้อนภาพ
disallowReturnToOpener
ซ่อนปุ่ม "กลับไปที่แท็บ" ในหน้าต่างการแสดงภาพซ้อนภาพหากเป็นจริง โดยค่าเริ่มต้นจะเป็นเท็จ
preferInitialWindowPlacement
เปิดหน้าต่างการแสดงภาพซ้อนภาพในตำแหน่งและขนาดเริ่มต้นหากเป็นจริง โดยค่าเริ่มต้นจะเป็นเท็จ

กิจกรรม

documentPictureInPicture.onenter
เริ่มทำงานใน documentPictureInPicture เมื่อมีการเปิดหน้าต่างการแสดงภาพซ้อนภาพ

ตัวอย่าง

HTML ต่อไปนี้จะตั้งค่าโปรแกรมเล่นวิดีโอที่กำหนดเองและองค์ประกอบปุ่มเพื่อเปิดโปรแกรมเล่นวิดีโอในหน้าต่างการแสดงภาพซ้อนภาพ

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

เปิดหน้าต่างการแสดงภาพซ้อนภาพ

JavaScript ต่อไปนี้จะเรียกใช้ documentPictureInPicture.requestWindow() เมื่อผู้ใช้คลิกปุ่มเพื่อเปิดหน้าต่าง Picture-in-Picture ว่างเปล่า Promise ที่แสดงผลจะได้รับการแก้ไขด้วยออบเจ็กต์ 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);
});

กำหนดขนาดหน้าต่างการแสดงภาพซ้อนภาพ

หากต้องการตั้งค่าขนาดของหน้าต่างภาพซ้อนภาพ ให้ตั้งค่าตัวเลือก width และ height ของ documentPictureInPicture.requestWindow() เป็นขนาดหน้าต่าง 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

หากต้องการซ่อนปุ่มในหน้าต่างการแสดงภาพซ้อนภาพที่อนุญาตให้ผู้ใช้กลับไปที่แท็บที่เปิด ให้ตั้งค่าdisallowReturnToOpenerของ documentPictureInPicture.requestWindow() เป็น 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 ไปยังตำแหน่งและขนาดเริ่มต้น

หากไม่ต้องการใช้ตำแหน่งหรือขนาดของหน้าต่างภาพซ้อนภาพก่อนหน้าอีก ให้ตั้งค่าpreferInitialWindowPlacementของdocumentPictureInPicture.requestWindow()เป็น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 ที่ลิงก์อย่างชัดเจนหรือฝังอยู่ในเอกสาร แล้วต่อท้ายลงในหน้าต่างภาพซ้อนภาพ โปรดทราบว่านี่เป็นการคัดลอกเพียงครั้งเดียว

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" ของหน้าต่างเพื่อดูว่าเมื่อใดที่หน้าต่างการแสดงภาพซ้อนภาพปิด (ไม่ว่าจะเป็นเพราะเว็บไซต์เริ่มต้นหรือผู้ใช้ปิดด้วยตนเอง) ตัวแฮนเดิลเหตุการณ์เป็นตำแหน่งที่เหมาะในการนำองค์ประกอบออกจากหน้าต่าง Picture-in-Picture ดังที่แสดงที่นี่

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()

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

ฟังเสียงเมื่อเว็บไซต์เข้าสู่โหมด PIP

ฟังเหตุการณ์ "enter" ใน documentPictureInPicture เพื่อทราบเมื่อมีการเปิดหน้าต่างการแสดงภาพซ้อนภาพ เหตุการณ์มีออบเจ็กต์ window สำหรับเข้าถึงหน้าต่างการแสดงภาพซ้อนภาพ

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

เข้าถึงองค์ประกอบในหน้าต่าง PIP

เข้าถึงองค์ประกอบในหน้าต่างภาพในภาพจากออบเจ็กต์ที่ส่งคืนโดย documentPictureInPicture.requestWindow() หรือด้วย documentPictureInPicture.window

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") ใน JavaScript ได้เช่นเคย

// 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 เพื่อปรับขนาดหน้าต่างการแสดงภาพซ้อนภาพ ทั้ง 2 วิธีต้องมีการกระทำของผู้ใช้

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 เพื่อโฟกัสหน้าต่างที่เปิดจากหน้าต่างการแสดงภาพซ้อนภาพ วิธีนี้ต้องใช้ท่าทางของผู้ใช้

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

โหมดการแสดงผล CSS PiP

ใช้picture-in-pictureโหมดการแสดงผล CSS เพื่อเขียนกฎ 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.
}

การสาธิต

Tomodoro ซึ่งเป็นเว็บแอป Pomodoro
หน้าต่างการแสดงภาพซ้อนภาพใน Tomodoro

แชร์ความคิดเห็น

แจ้งปัญหาใน GitHub พร้อมคำแนะนำและคำถาม