'תמונה בתוך תמונה' לכל רכיב, לא רק ל<סרטון>

François Beaufort
François Beaufort

Browser Support

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

Source

Document Picture-in-Picture API מאפשר לפתוח חלון שתמיד מוצג בחזית, שאפשר לאכלס אותו בתוכן HTML שרירותי. הוא מרחיב את Picture-in-Picture API הקיים עבור <video> שמאפשר רק להציב רכיב HTML <video> בחלון Picture-in-Picture.

חלון התמונה בתוך תמונה ב-API של תמונה בתוך תמונה במסמך דומה לחלון ריק מאותו מקור שנפתח באמצעות window.open(), עם כמה הבדלים:

  • החלון של 'תמונה בתוך תמונה' צף מעל חלונות אחרים.
  • החלון של 'תמונה בתוך תמונה' אף פעם לא נסגר לפני החלון שממנו הוא נפתח.
  • אי אפשר לנווט בחלון של תמונה בתוך תמונה.
  • האתר לא יכול להגדיר את המיקום של חלון התמונה בתוך תמונה.
חלון של תמונה בתוך תמונה שמוצג בו טריילר של הסרט Sintel.
חלון תמונה בתוך תמונה שנוצר באמצעות Document Picture-in-Picture API (הדגמה).

הסטטוס הנוכחי

שלב סטטוס
1. יצירת הסבר השלמה
2. יצירת טיוטה ראשונה של המפרט בתהליך
3. איסוף משוב ושיפור העיצוב בתהליך
4. גרסת מקור לניסיון השלמה
5. הפעלה הושלם (מחשב)

תרחישים לדוגמה

נגן וידאו בהתאמה אישית

אתר יכול לספק חוויית צפייה בסרטון במצב 'תמונה בתוך תמונה' באמצעות Picture-in-Picture API הקיים ל-<video>, אבל האפשרויות מוגבלות מאוד. חלון התמונה בתוך תמונה הקיים מקבל מעט קלטים, והיכולת לעצב אותם מוגבלת. כשמסמך שלם מוצג בתמונה בתוך תמונה, האתר יכול לספק אמצעי בקרה וקלט בהתאמה אישית (לדוגמה, כתוביות, פלייליסטים, סרגל ניווט בזמן, סימון לייק או דיסלייק לסרטונים) כדי לשפר את חוויית הצפייה בסרטונים בתמונה בתוך תמונה.

שיחת ועידה בווידאו

במהלך שיחות ועידה בווידאו, משתמשים רבים יוצאים מהכרטיסייה בדפדפן מסיבות שונות (למשל, כדי להציג כרטיסייה אחרת בשיחה או כדי לבצע כמה משימות בו-זמנית), אבל עדיין רוצים לראות את השיחה. לכן, זהו תרחיש שימוש מצוין לתמונה בתוך תמונה. שוב, החוויה הנוכחית שאפשר לספק באתר של ועידות וידאו באמצעות Picture-in-Picture API ל-<video> מוגבלת בסגנון ובקלט. כשמסמך שלם מוצג במצב 'תמונה בתוך תמונה', האתר יכול לשלב בקלות כמה סרטונים בחלון PiP אחד בלי להסתמך על פריצות של canvas, ולספק אמצעי בקרה מותאמים אישית כמו שליחת הודעה, השתקת משתמש אחר או הרמת יד.

פרודוקטיביות

מחקרים הראו שהמשתמשים צריכים יותר דרכים להיות פרודוקטיביים באינטרנט. התכונה 'מסמך במצב תמונה בתוך תמונה' מאפשרת לאפליקציות אינטרנט לבצע יותר פעולות. בין אם מדובר בעריכת טקסט, בסיכום פגישות, ברשימות משימות, בהודעות ובצ'אטים, או בכלי עיצוב ופיתוח, אפליקציות אינטרנט יכולות עכשיו לשמור על הנגישות של התוכן שלהן.

ממשק

מאפיינים

documentPictureInPicture.window
מחזירה את חלון התמונה בתוך תמונה הנוכחי, אם יש כזה. אחרת, הפונקציה מחזירה את הערך null.

Methods

documentPictureInPicture.requestWindow(options)

מחזירה הבטחה שמושלמת כשחלון עם תמונה בתוך תמונה נפתח. ההבטחה נדחית אם היא נקראת ללא תנועת משתמש. המילון options מכיל את החברים האופציונליים הבאים:

width
הגדרה של הרוחב הראשוני של החלון 'תמונה בתוך תמונה'.
height
הגדרה של הגובה הראשוני של החלון של 'תמונה בתוך תמונה'.
disallowReturnToOpener
אם הערך הוא true, הכפתור 'חזרה לכרטיסייה' מוסתר בחלון של 'תמונה בתוך תמונה'. ברירת המחדל היא false.
preferInitialWindowPlacement
אם הערך הוא true, חלון התמונה בתוך תמונה ייפתח במיקום ובגודל ברירת המחדל שלו. ברירת המחדל היא False.

אירועים

documentPictureInPicture.onenter
Fired on 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() כשמשתמש לוחץ על הלחצן כדי לפתוח חלון ריק של תמונה בתוך תמונה. ההבטחה שמוחזרת נפתרת עם אובייקט 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() לגודל הרצוי של החלון של 'תמונה בתוך תמונה'. יכול להיות ש-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);
});

הסתרת הלחצן 'חזרה לכרטיסייה' בחלון של 'תמונה בתוך תמונה'

כדי להסתיר את הלחצן בחלון 'תמונה בתוך תמונה' שמאפשר למשתמש לחזור לכרטיסייה שבה נפתח הסרטון, מגדירים את האפשרות 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,
  });
});

פתיחת החלון של 'תמונה בתוך תמונה' במיקום ובגודל ברירת המחדל

כדי לא להשתמש מחדש במיקום או בגודל של החלון הקודם של 'תמונה בתוך תמונה', מגדירים את האפשרות 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,
  });
});

העתקת גיליונות סגנונות לחלון של 'תמונה בתוך תמונה'

כדי להעתיק את כל גיליונות הסגנונות של 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);
});

טיפול בסגירת החלון של 'תמונה בתוך תמונה'

כדי לדעת מתי חלון התמונה בתוך תמונה נסגר (כי האתר יזם את הסגירה או שהמשתמש סגר אותו באופן ידני), צריך להאזין לאירוע "pagehide" של החלון. ה-event handler הוא מקום טוב להוציא את הרכיבים חזרה מחלון התמונה בתוך תמונה, כמו שמוצג כאן.

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

האזנה להפעלה של מצב 'תמונה בתוך תמונה' באתר

כדי לדעת מתי נפתח חלון של תמונה בתוך תמונה, אפשר להאזין לאירוע "enter" ב-documentPictureInPicture. האירוע מכיל אובייקט window כדי לגשת לחלון תמונה בתוך תמונה.

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

גישה לרכיבים בחלון 'תמונה בתוך תמונה'

אפשר לגשת לרכיבים בחלון של תמונה בתוך תמונה מהאובייקט שמוחזר על ידי 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;
}

טיפול באירועים מחלון תמונה בתוך תמונה

יוצרים כפתורים ואמצעי בקרה ומגיבים לאירועי קלט של משתמשים, כמו "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);

שינוי הגודל של החלון של 'תמונה בתוך תמונה'

כדי לשנות את גודל החלון של 'תמונה בתוך תמונה', משתמשים בשיטות resizeBy() ו-resizeTo() של Window. שתי השיטות דורשות תנועת משתמש.

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() כדי להתמקד בחלון הפותח מתוך חלון התמונה בתוך תמונה. השיטה הזו דורשת תנועת משתמש.

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

מצב תצוגה של תמונה בתוך תמונה ב-CSS

אפשר להשתמש במצב התצוגה 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.
}

הדגמות

נגן VideoJS

אפשר להתנסות ב-API של Document Picture-in-Picture בהדגמה של נגן VideoJS.

פומודורו

גם Tomodoro, אפליקציית אינטרנט לשיטת פומודורו, משתמשת ב-Document Picture-in-Picture API כשהוא זמין. אפשר לראות את בקשת המיזוג ב-GitHub.

Tomodoro, אפליקציית פומודורו לאינטרנט.
חלון מסוג תמונה בתוך תמונה ב-Tomodoro.

שיתוף משוב

דיווח על בעיות ב-GitHub עם הצעות ושאלות.