אפשר להשתמש באזור של סרגל הכותרת לצד פקדי החלונות כדי שה-PWA ייראה יותר כמו אפליקציה.
אם קראתם את המאמר שלי Make your PWA feel more like an app, אולי אתם זוכרים שציינתי התאמה אישית של סרגל הכותרת של האפליקציה כאסטרטגיה ליצירת חוויה שדומה יותר לאפליקציה. דוגמה לאופן שבו זה יכול להיראות באפליקציית Podcasts ב-macOS.

יכול להיות שתרצו להגיד שפודקאסטים היא אפליקציית macOS ספציפית לפלטפורמה שלא פועלת בדפדפן, ולכן היא יכולה לעשות מה שהיא רוצה בלי לפעול לפי הכללים של הדפדפן. נכון, אבל החדשות הטובות הן שבעזרת התכונה Window Controls Overlay (שכבת-על של פקדי חלונות), שהיא הנושא של המאמר הזה, בקרוב תוכלו ליצור ממשקי משתמש דומים ל-PWA שלכם.
רכיבים של שכבת-העל של פקדי החלונות
שכבת-העל של פקדי החלונות מורכבת מארבע תכונות משנה:
- הערך
"window-controls-overlay"
של השדה"display_override"
במניפסט של אפליקציית האינטרנט. - משתני הסביבה של CSS
titlebar-area-x
,titlebar-area-y
,titlebar-area-width
ו-titlebar-area-height
. - הסטנדרטיזציה של מאפיין ה-CSS הקנייני
-webkit-app-region
הקודם כמאפייןapp-region
להגדרת אזורים שניתן לגרור בתוכן אינטרנט. - מנגנון לשאילתות ולפתרונות עקיפים של אזור הפקדים של החלון באמצעות חבר
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"]
}
שכבת העל של אמצעי הבקרה של החלון תהיה גלויה רק אם כל התנאים הבאים יתקיימו:
- האפליקציה לא נפתחת בדפדפן, אלא בחלון PWA נפרד.
- קובץ המניפסט כולל את
"display_override": ["window-controls-overlay"]
. (אחרי כן אפשר להשתמש בערכים אחרים). - אפליקציית ה-PWA פועלת במערכת הפעלה למחשב.
- המקור הנוכחי תואם למקור שבו הותקנה אפליקציית ה-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 (חוץ מאזור קטן מאוד), כי לחצני השליטה בחלון לא משמשים כאזורי גרירה, ושאר סרגל הכותרת מורכב מווידג'ט החיפוש. כדי לפתור את הבעיה, צריך להשתמש במאפיין app-region
CSS עם ערך של 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 (שלוש הנקודות) ישתנה בהתאם לפלטפורמה. כלומר, תמונת הרקע עם המעבר הליניארי צריכה להיות מותאמת באופן דינמי כדי להציג מעבר מ#131313
לmaroon
או מmaroon
ל#131313
לmaroon
, כך שהיא תשתלב עם צבע הרקע של סרגל הכותרת maroon
, שנקבע על ידי <meta name="theme-color" content="maroon">
. אפשר לעשות זאת על ידי שליחת שאילתה אל getTitlebarAreaRect()
API בנכס 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);
}
קביעה אם שכבת-העל של פקדי החלונות גלויה
שכבת-העל של פקדי החלונות לא תמיד תופיע באזור סרגל הכותרת. הלחצן לא יופיע בדפדפנים שלא תומכים בתכונה Window Controls Overlay, אבל הוא גם לא יופיע כשה-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()
יכולה להספיק למקרים חד-פעמיים כמו הגדרת תמונת הרקע הנכונה בהתאם למיקום של פקדי החלונות, אבל במקרים אחרים נדרשת שליטה מדויקת יותר. לדוגמה, אפשר להשתמש ב-API כדי להתאים את שכבת-העל של פקדי החלונות בהתאם למקום הפנוי, ולהוסיף בדיחה לשכבת-העל של פקדי החלונות אם יש מספיק מקום.

כדי לקבל התראה על שינויים בגיאומטריה, אפשר להירשם ל-navigator.windowControlsOverlay.ongeometrychange
או להגדיר מאזין לאירוע 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
, אפשר גם להוסיף listener לאירוע ל-windowControlsOverlay
כמו בדוגמה שלמטה. אפשר לקרוא על ההבדל בין השניים ב-MDN.
navigator.windowControlsOverlay.addEventListener(
'geometrychange',
debounce((e) => {
span.hidden = e.titlebarAreaRect.width < 800;
}, 250),
);
תאימות כשמריצים בכרטיסייה ובדפדפנים שלא תומכים
יש שני תרחישים אפשריים:
- המקרה שבו אפליקציה פועלת בדפדפן שתומך ב-Window Controls Overlay, אבל האפליקציה נמצאת בכרטיסיית דפדפן.
- המקרה שבו אפליקציה פועלת בדפדפן שלא תומך בשכבת-העל של פקדי החלונות.
בשני המקרים, כברירת מחדל, רכיב ה-HTML שנוצר בשביל שכבת העל של אמצעי הבקרה של החלון יוצג מוטבע כמו תוכן HTML רגיל, והערכים של משתני env()
יופעלו למיקום. בדפדפנים תומכים, אפשר גם להחליט לא להציג את ה-HTML שמוגדר לכיסוי של אמצעי הבקרה של החלון. כדי לעשות את זה, צריך לבדוק את המאפיין visible
של הכיסוי, ואם הוא מחזיר false
, צריך להסתיר את תוכן ה-HTML הזה.

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

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

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

שיקולי אבטחה
צוות Chromium תכנן והטמיע את Window Controls Overlay API על סמך העקרונות המרכזיים שמוגדרים במאמר שליטה בגישה לתכונות מתקדמות של פלטפורמת האינטרנט, כולל שליטת משתמשים, שקיפות וארגונומיה.
זיוף
מתן שליטה חלקית לאתרים בסרגל הכותרת משאיר מקום למפתחים לזיוף תוכן באזור שהיה מהימן ונשלט על ידי הדפדפן. בשלב הזה, בדפדפני Chromium, מצב עצמאי כולל סרגל כותרת שבהפעלה הראשונית מוצגת הכותרת של דף האינטרנט בצד ימין, והמקור של הדף בצד שמאל (ואחריו הלחצן 'הגדרות ועוד' ואמצעי הבקרה של החלון). אחרי כמה שניות, הטקסט המקורי נעלם. אם הדפדפן מוגדר לשפה שמוצגת מימין לשמאל (RTL), הפריסה הזו מתהפכת כך שהטקסט המקורי מוצג בצד שמאל. הפעולה הזו פותחת את שכבת העל של אמצעי הבקרה של החלון כדי לזייף את המקור אם אין מספיק מרווחים בין המקור לבין הקצה השמאלי של שכבת העל. לדוגמה, אפשר לצרף למקור evil.ltd את האתר המהימן google.com, וכך לגרום למשתמשים להאמין שהמקור מהימן. המטרה היא לשמור את הטקסט המקורי הזה כדי שהמשתמשים ידעו מה המקור של האפליקציה ויוכלו לוודא שהיא עומדת בציפיות שלהם. בדפדפנים שהוגדר בהם כיוון כתיבה מימין לשמאל, צריך להוסיף מספיק ריווח משמאל לטקסט של המקור כדי למנוע מאתר זדוני לצרף את המקור הלא בטוח למקור מהימן.
יצירה של טביעת אצבע דיגיטלית (fingerprinting)
הפעלת שכבת-העל של פקדי החלונות והאזורים שניתן לגרור לא מעוררת חששות משמעותיים בנוגע לפרטיות, מלבד זיהוי התכונה. עם זאת, בגלל הגדלים והמיקומים השונים של לחצני השליטה בחלון במערכות הפעלה שונות, השיטה navigator.
מחזירה DOMRect
שהמיקום והממדים שלו חושפים מידע על מערכת ההפעלה שבה הדפדפן פועל. נכון לעכשיו, מפתחים יכולים לגלות את מערכת ההפעלה ממחרוזת סוכן המשתמש, אבל בגלל חששות לגבי טביעת אצבע דיגיטלית, מתנהל דיון על הקפאת מחרוזת סוכן המשתמש ואיחוד גרסאות מערכת ההפעלה. קהילת הדפדפנים משקיעה מאמצים כדי להבין באיזו תדירות משתנה הגודל של שכבת העל של לחצני החלון בפלטפורמות שונות, כי ההנחה הנוכחית היא שהגודל הזה יציב למדי בגרסאות שונות של מערכות הפעלה, ולכן לא יהיה שימושי לצורך מעקב אחרי גרסאות משניות של מערכות הפעלה. למרות שזו בעיה פוטנציאלית של טביעת אצבע דיגיטלית, היא חלה רק על אפליקציות PWA מותקנות שמשתמשות בתכונה של סרגל כותרת מותאם אישית, ולא על שימוש כללי בדפדפן. בנוסף, ממשק ה-API של navigator.
לא יהיה זמין ל-iframe שמוטמעים בתוך PWA.
ניווט
אם מנווטים למקור אחר בתוך PWA, המערכת תחזור לסרגל הכותרת הרגיל של האפליקציה העצמאית, גם אם היא עומדת בקריטריונים שלמעלה והיא מופעלת עם שכבת-העל של פקדי החלונות. הסיבה לכך היא שמופיע פס שחור כשעוברים לנקודת מוצא אחרת. אחרי שתחזרו למקור המקורי, שכבת העל של אמצעי הבקרה של החלון תשמש שוב.

משוב
צוות Chromium רוצה לשמוע על החוויות שלכם עם Window Controls Overlay API.
נשמח לקבל מידע על עיצוב ה-API
האם יש משהו ב-API שלא פועל כמו שציפית? או שיש שיטות או מאפיינים חסרים שצריך להטמיע כדי לממש את הרעיון? יש לך שאלה או הערה לגבי מודל האבטחה? אפשר לפתוח בעיה במפרט במאגר GitHub המתאים, או להוסיף את המחשבות שלכם לבעיה קיימת.
דיווח על בעיה בהטמעה
מצאתם באג בהטמעה של Chromium? או שההטמעה שונה מהמפרט?
מדווחים על באג בכתובת new.crbug.com. חשוב לכלול כמה שיותר פרטים, הוראות פשוטות לשחזור הבאג ומזינים UI>Browser>WebAppInstalls
בתיבה Components.
תמיכה ב-API
האם אתם מתכננים להשתמש ב-Window Controls Overlay API? התמיכה הציבורית שלכם עוזרת לצוות Chromium לתעדף תכונות ומראה לספקי דפדפנים אחרים עד כמה חשוב לתמוך בהן.
אתם יכולים לשלוח ציוץ אל @ChromiumDev עם ההאשטאג #WindowControlsOverlay
ולספר לנו איפה ואיך אתם משתמשים בו.
קישורים שימושיים
- הסבר
- Spec draft
- באג ב-Chromium
- כניסה לסטטוס הפלטפורמה של Chrome
- בדיקת תגים
- מסמכים קשורים של Microsoft Edge
תודות
התכונה Window Controls Overlay הוטמעה והוגדרה על ידי Amanda Baker מצוות Microsoft Edge. המאמר הזה נבדק על ידי Joe Medley ועל ידי Kenneth Rohde Christiansen. תמונה ראשית (Hero) מאת Sigmund ב-Unsplash.