התאמה אישית של שכבת-העל של פקדי החלון בסרגל הכותרת של PWA'

כדי לתת ל-PWA תחושה שדומה יותר לאפליקציה, אפשר להשתמש באזור של סרגל הכותרת שליד פקדי החלונות.

אם אתם זוכרים את המאמר שלי לגרום ל-PWA להרגיש יותר כמו אפליקציה, אולי אתם זוכרים איך הזכרתי את התאמה אישית של סרגל הכותרת באפליקציה כאסטרטגיה ליצירת חוויה שדומה יותר לאפליקציה. הדוגמה הבאה ממחישה איך זה יכול להיראות כשאפליקציית הפודקאסטים של macOS.

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

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

רכיבי שכבת-על של פקדי החלונות

שכבת-העל של פקדי החלונות מורכבת מארבע תכונות משנה:

  1. הערך "window-controls-overlay" עבור השדה "display_override" בקובץ המניפסט של אפליקציית אינטרנט.
  2. משתני הסביבה של ה-CSS titlebar-area-x, titlebar-area-y, titlebar-area-width ו-titlebar-area-height.
  3. תקינה של מאפיין ה-CSS הקודם -webkit-app-region כנכס app-region, כדי להגדיר אזורים שניתן לגרור בתוכן אינטרנט.
  4. מנגנון לשליחת שאילתות לגבי האזור לבקרת החלון ולעקיפת האזור הזה באמצעות החבר windowControlsOverlay ב-window.navigator.

מהי שכבת-על של פקדי החלונות

אזור סרגל הכותרת מתייחס למרחב שמשמאל או מימין לפקדי החלונות (כלומר, הלחצנים למזעור, להגדלה, לסגירה וכו') ובדרך כלל הוא מכיל את כותרת האפליקציה. 'חלון בקרה על שכבת-על' מאפשר לאפליקציות Progressive Web App (PWA) לספק תחושה שדומה יותר לאפליקציה על ידי החלפת סרגל הכותרת הקיים ברוחב מלא בשכבת-על קטנה שמכילה את פקדי החלונות. כך המפתחים יכולים להציב תוכן מותאם אישית באזור של שורת הכותרת שבשליטת הדפדפן.

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

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

איך משתמשים בשכבת-העל של פקדי החלונות

מתבצעת הוספה של window-controls-overlay לקובץ המניפסט של אפליקציית האינטרנט

כדי להצטרף לשכבת-העל של פקדי החלונות, Progressive Web App צריך להוסיף את "window-controls-overlay" בתור החבר הראשי ב-"display_override" בקובץ המניפסט של אפליקציית האינטרנט:

{
  "display_override": ["window-controls-overlay"]
}

שכבת-העל של פקדי החלונות תהיה גלויה רק כאשר כל התנאים הבאים מתקיימים:

  1. האפליקציה לא נפתחת בדפדפן, אלא בחלון PWA נפרד.
  2. המניפסט כולל "display_override": ["window-controls-overlay"]. (ערכים אחרים מותרים לאחר מכן).
  3. אפליקציית ה-PWA פועלת במערכת הפעלה במחשב.
  4. המקור הנוכחי תואם למקור שעבורו הותקנה ה-PWA.

התוצאה היא אזור ריק של שורת הכותרת, עם פקדי החלון הרגילים משמאל או מימין, בהתאם למערכת ההפעלה.

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

העברת תוכן לסרגל הכותרת

עכשיו, כשיש רווח בסרגל הכותרת, אפשר להזיז אליו משהו. עבור המאמר הזה, בניתי PWA של תוכן מומלץ ב-Wikimedia. תכונה שימושית לאפליקציה הזו יכולה להיות חיפוש מילים בכותרות המאמרים. קוד ה-HTML של תכונת החיפוש נראה כך:

<div class="search">
  <img src="logo.svg" alt="Wikimedia logo." width="32" height="32" />
  <label>
    <input type="search" />
    Search for words in articles
  </label>
</div>

כדי להעביר את div הזה למעלה לשורת הכותרת, נדרש CSS מסוים:

.search {
  /* Make sure the `div` stays there, even when scrolling. */
  position: fixed;
  /**
   * Gradient, because why not. Endless opportunities.
   * The gradient ends in `#36c`, which happens to be the app's
   * `<meta name="theme-color" content="#36c">`.
   */
  background-image: linear-gradient(90deg, #36c, #131313, 33%, #36c);
  /* Use the environment variable for the left anchoring with a fallback. */
  left: env(titlebar-area-x, 0);
  /* Use the environment variable for the top anchoring with a fallback. */
  top: env(titlebar-area-y, 0);
  /* Use the environment variable for setting the width with a fallback. */
  width: env(titlebar-area-width, 100%);
  /* Use the environment variable for setting the height with a fallback. */
  height: env(titlebar-area-height, 33px);
}

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

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

קביעה אילו חלקים של סרגל הכותרת ניתנים לגרירה

צילום המסך שלמעלה מרמז שסיימת, אבל עדיין לא סיימת. בחלון ה-PWA אי אפשר יותר לגרור (מלבד אזור קטן מאוד), מכיוון שלחצני החלון אינם אזורי גרירה ושאר סרגל הכותרת כולל את ווידג'ט החיפוש. מתקנים את הבעיה באמצעות מאפיין ה-CSS app-region עם הערך drag. במקרה הבטון, אפשר להפוך את כל מה חוץ מהרכיב input לגרירה.

/* The entire search `div` is draggable… */
.search {
  -webkit-app-region: drag;
  app-region: drag;
}

/* …except for the `input`. */
input {
  -webkit-app-region: no-drag;
  app-region: no-drag;
}

כשה-CSS נמצא במקום, המשתמש יכול לגרור את חלון האפליקציה כרגיל על ידי גרירה של ה-div, ה-img או label. רק הרכיב input הוא אינטראקטיבי כך שאפשר להזין את שאילתת החיפוש.

זיהוי תכונות

כדי לזהות תמיכה בשכבת-על של פקדי חלונות אפשר לבדוק אם יש windowControlsOverlay:

if ('windowControlsOverlay' in navigator) {
  // Window Controls Overlay is supported.
}

שליחת שאילתה לאזור פקדי החלונות באמצעות windowControlsOverlay

בקוד עד עכשיו יש בעיה אחת: בחלק מהפלטפורמות פקדי החלונות נמצאים בצד ימין, ובחלק אחר הם נמצאים בצד שמאל. כדי להחמיר את המצב, תפריט "שלוש הנקודות" של Chrome ישנה גם את המיקום, בהתאם לפלטפורמה. כלומר, צריך להתאים באופן דינמי את תמונת הרקע ההדרגתית הלינארית כך שתפעל מ-#131313maroon או מ-maroon#131313maroon, כדי שהיא תשתלב עם צבע הרקע maroon של סרגל הכותרת, שנקבע לפי <meta name="theme-color" content="maroon">. כדי לעשות זאת, אפשר לשלוח שאילתה ל-API getTitlebarAreaRect() בנכס navigator.windowControlsOverlay.

if ('windowControlsOverlay' in navigator) {
  const { x } = navigator.windowControlsOverlay.getTitlebarAreaRect();
  // Window controls are on the right (like on Windows).
  // Chrome menu is left of the window controls.
  // [ windowControlsOverlay___________________ […] [_] [■] [X] ]
  if (x === 0) {
    div.classList.add('search-controls-right');
  }
  // Window controls are on the left (like on macOS).
  // Chrome menu is right of the window controls overlay.
  // [ [X] [_] [■] ___________________windowControlsOverlay [⋮] ]
  else {
    div.classList.add('search-controls-left');
  }
} else {
  // When running in a non-supporting browser tab.
  div.classList.add('search-controls-right');
}

במקום להשתמש בתמונת הרקע בכללי ה-CSS של המחלקה .search (כמו קודם), הקוד שהשתנה משתמש עכשיו בשתי מחלקות שהקוד שלמעלה מגדיר באופן דינמי.

/* For macOS: */
.search-controls-left {
  background-image: linear-gradient(90deg, #36c, 45%, #131313, 90%, #36c);
}

/* For Windows: */
.search-controls-right {
  background-image: linear-gradient(90deg, #36c, #131313, 33%, #36c);
}

בדיקה אם שכבת-העל של פקדי החלונות גלויה

שכבת-העל של פקדי החלונות לא תהיה גלויה באזור סרגל הכותרת בכל מצב. באופן טבעי הוא לא יהיה זמין בדפדפנים שלא תומכים בתכונה 'שכבת-על של פקדי חלונות', אבל היא לא תהיה זמינה גם כשה-PWA המדובר יפעל בכרטיסייה. כדי לזהות את המצב הזה, אפשר להריץ שאילתה על המאפיין visible של windowControlsOverlay:

if (navigator.windowControlsOverlay.visible) {
  // The window controls overlay is visible in the title bar area.
}

לחלופין, אתם יכולים גם להשתמש בשאילתת המדיה display-mode ב-JavaScript ו/או ב-CSS:

// Create the query list.
const mediaQueryList = window.matchMedia('(display-mode: window-controls-overlay)');

// Define a callback function for the event listener.
function handleDisplayModeChange(mql) {
  // React on display mode changes.
}

// Run the display mode change handler once.
handleDisplayChange(mediaQueryList);

// Add the callback function as a listener to the query list.
mediaQueryList.addEventListener('change', handleDisplayModeChange);
@media (display-mode: window-controls-overlay) { 
  /* React on display mode changes. */ 
}

קבלת התראות על שינויים בגאומטריה

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

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

כדי לקבל התראה על שינויים בגאומטריה, אפשר להירשם ל-navigator.windowControlsOverlay.ongeometrychange או להגדיר event listener עבור geometrychange האירוע. האירוע הזה יופעל רק כששכבת-העל של פקדי החלונות גלויה, כלומר כשהערך של navigator.windowControlsOverlay.visible הוא true.

const debounce = (func, wait) => {
  let timeout;
  return function executedFunction(...args) {
    const later = () => {
      clearTimeout(timeout);
      func(...args);
    };
    clearTimeout(timeout);
    timeout = setTimeout(later, wait);
  };
};

if ('windowControlsOverlay' in navigator) {
  navigator.windowControlsOverlay.ongeometrychange = debounce((e) => {
    span.hidden = e.titlebarAreaRect.width < 800;
  }, 250);
}

במקום להקצות פונקציה ל-ongeometrychange, אפשר גם להוסיף event listener ל-windowControlsOverlay כמו שמתואר בהמשך. ב-MDN אפשר לקרוא על ההבדל בין הסוגים.

navigator.windowControlsOverlay.addEventListener(
  'geometrychange',
  debounce((e) => {
    span.hidden = e.titlebarAreaRect.width < 800;
  }, 250),
);

תאימות בהפעלה בכרטיסייה ובדפדפנים שאינם תומכים

יש שני מקרים אפשריים:

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

בשני המקרים, כברירת מחדל, ה-HTML שנוצר לשכבת-העל של פקדי החלונות יוצג בתוך השורה, כמו תוכן HTML רגיל, והערכים החלופיים של המשתנים env() ייכנסו לתוקף עבור המיקום. בדפדפנים תומכים, אפשר גם להחליט לא להציג את ה-HTML שמיועד לשכבת-העל של פקדי החלונות. לשם כך, בודקים את המאפיין visible של שכבת-העל, ואם היא מדווחת על false, ומסתירים את תוכן ה-HTML הזה.

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

תזכורת: דפדפנים שלא תומכים בתכונה הזו לא יתייחסו בכלל לנכס המניפסט של אפליקציית האינטרנט "display_override" או לא יזהו את "window-controls-overlay", ולכן הם ישתמשו בערך האפשרי הבא בהתאם לשרשרת החלופית, לדוגמה, "standalone".

PWA שפועלת במצב עצמאי, ושכבת-העל של פקדי החלונות מוצגת בגוף.
בדפדפנים ישנים יותר אפשר להציג בקלות פקדים שמיועדים לסרגל הכותרת.

שיקולים בממשק המשתמש

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

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

הדגמה (דמו)

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

אפליקציית ההדגמה של התוכן המוצג של Wikimedia עם שכבת-על של פקדי החלונות.
אפליקציית ההדגמה זמינה לעריכת ניסויים.

תכונת החיפוש בשכבת-העל של פקדי החלונות פועלת באופן מלא:

אפליקציית ההדגמה של התוכן המוצג של Wikimedia עם שכבת-על של פקדי החלונות וחיפוש פעיל עבור המונח &#39;קלאופרה...&#39; המדגישה אחד מהמאמרים עם המונח התואם &#39;קליאופטרה&#39;.
תכונת חיפוש באמצעות שכבת-העל של פקדי החלונות.

שיקולי אבטחה

צוות Chromium תכנן והטמיע את window Controls Overlay API באמצעות עקרונות הליבה שהוגדרו במאמר שליטה בגישה לתכונות מתקדמות של פלטפורמת אינטרנט, כולל בקרת משתמשים, שקיפות וארגונומיה.

זיוף

כשנותנים לאתרים שליטה חלקית בסרגל הכותרת, המפתחים יכולים לזייף תוכן באזור שהיה בעבר אזור מהימן שנשלט על ידי הדפדפן. כרגע, בדפדפני Chromium, המצב העצמאי כולל סרגל כותרת, שבהפעלה הראשונית, מוצג בו הכותרת של דף האינטרנט בצד שמאל ואת מקור הדף מצד ימין (ולאחר מכן הלחצן 'הגדרות ועוד' ופקדי החלונות). אחרי כמה שניות, טקסט המקור ייעלם. אם הדפדפן מוגדר לשפה מימין לשמאל (RTL), הפריסה הזו הופכת כך שטקסט המקור מופיע בצד שמאל. הפעולה הזו פותחת את שכבת-העל של פקדי החלון כדי לזייף את המקור, אם אין מספיק מרווח בין המקור לבין הקצה הימני של שכבת-העל. לדוגמה, ניתן לצרף את המקור "evil.ltd" לאתר מהימן "google.com", ולגרום למשתמשים להאמין שהמקור מהימן. התוכנית היא לשמור את טקסט המקור הזה כדי שהמשתמשים ידעו מהו מקור האפליקציה, ולהבטיח שהוא תואם לציפיות שלהם. בדפדפנים שמוגדרים כ-RTL, צריך להיות מספיק מרווח פנימי מימין לטקסט המקור כדי למנוע מאתר זדוני להוסיף את המקור הלא בטוח עם מקור מהימן.

טביעת אצבע

הפעלה של שכבת-העל של פקדי החלונות והאזורים שאפשר לגרור לא גורמת לבעיות פרטיות משמעותיות, מלבד זיהוי התכונות. עם זאת, בגלל ההבדלים בגדלים ובמיקומים של לחצני השליטה בחלון במערכות ההפעלה, השיטה navigator.windowControlsOverlay.getTitlebarAreaRect() מחזירה DOMRect שהמיקום והמידות שלה חושפים מידע על מערכת ההפעלה שבה הדפדפן פועל. נכון לעכשיו, מפתחים יכולים כבר לגלות את מערכת ההפעלה מהמחרוזת של סוכן המשתמש, אבל בגלל בעיות שקשורות ליצירה של טביעת אצבע דיגיטלית, מתקיים דיון על הקפאת המחרוזת של UA ואיחוד גרסאות של מערכת ההפעלה. בקהילת הדפדפנים אנחנו משקיעים מאמצים רבים כדי להבין באיזו תדירות הגודל של שכבת-העל של פקדי החלונות משתנה בפלטפורמות שונות. ההנחה הנוכחית היא שהגרסאות האלה יציבות למדי בכל הגרסאות של מערכת ההפעלה, ולכן הן לא יכולות לעזור לתצפית על גרסאות משניות של מערכת ההפעלה. למרות שיכול להיות שמדובר בבעיה של טביעת אצבע דיגיטלית, היא רלוונטית רק לאפליקציות PWA מותקנות שמבוססות על התכונה של סרגל הכותרת בהתאמה אישית, ולא חלה על שימוש כללי בדפדפן. בנוסף, ה-API navigator.windowControlsOverlay לא יהיה זמין למסגרות iframe שמוטמעות בתוך PWA.

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

סרגל כתובת URL שחור לניווט מחוץ למקור.
מוצג פס שחור כשהמשתמש עובר למקור אחר.

משוב

צוות Chromium רוצה לשמוע על החוויה שלך בשימוש ב-Window Controls Overlay API.

לספר לנו על עיצוב ה-API

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

דיווח על בעיה בהטמעה

האם מצאת באג בהטמעה של Chromium? או שההטמעה שונה מהמפרט? דווחו על באג בכתובת new.crbug.com. הקפידו לכלול כמה שיותר פרטים, הוראות פשוטות לשחזור ולהזין UI>Browser>WebAppInstalls בתיבה רכיבים. גליץ' הוא כלי מעולה לשיתוף גיבויים מהירים וקלים.

הבעת תמיכה ב-API

האם בכוונתך להשתמש ב-Window Controls Overlay API? התמיכה הציבורית שלכם עוזרת לצוות של Chromium לקבוע סדר עדיפויות לתכונות, ומראה לספקי דפדפנים אחרים עד כמה חשוב התמיכה בהן.

עליך לשלוח ציוץ אל @ChromiumDev עם ה-hashtag של #WindowControlsOverlay ולהסביר לנו איפה ואיך אתם משתמשים בו.

קישורים שימושיים

אישורים

שכבת-העל של פקדי החלונות הוטמעה וסומנה על ידי Amanda Baker מצוות Microsoft Edge. המאמר הזה נכתב על ידי Joe Medley ו-Kenneth Rohde Christiansen. תמונה ראשית (Hero) של זיגמונד ב-UnFlood.