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

François Beaufort
François Beaufort

תמיכה בדפדפן

  • 116
  • 116
  • x
  • x

מקור

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

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

פומודורו

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

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

משוב

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

אישורים

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