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

François Beaufort
François Beaufort

תמיכה בדפדפן

  • Chrome: 116.
  • קצה: 116.
  • Firefox: לא נתמך.
  • Safari: לא נתמך.

מקור

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

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

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

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

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

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

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

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

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

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

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

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

ממשק

מאפיינים

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

שיטות

documentPictureInPicture.requestWindow(options)

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

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

אירועים

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

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

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

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

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

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

פומודורו

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

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

משוב

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

אישורים

תמונה ראשית (Hero) של Jakob Owens.