Overlay der Fenstersteuerelemente in der Titelleiste der PWA anpassen

Nutzen Sie den Bereich der Titelleiste neben den Fenstersteuerelementen, damit sich Ihre PWA eher wie eine App anfühlt.

Wenn Sie sich an meinen Artikel Make your PWA feel more like an app erinnern, wissen Sie vielleicht noch, dass ich das Anpassen der Titelleiste Ihrer App als Strategie für eine app-ähnlichere Nutzererfahrung erwähnt habe. Hier sehen Sie ein Beispiel für die Darstellung in der macOS-Podcast-App.

Die Titelleiste der macOS-Podcast-App mit Schaltflächen zur Mediensteuerung und Metadaten zum aktuell wiedergegebenen Podcast.
Mit einer benutzerdefinierten Titelleiste wirkt Ihre PWA eher wie eine plattformspezifische App.

Jetzt könnten Sie einwenden, dass Podcasts eine plattformspezifische macOS-App ist, die nicht in einem Browser ausgeführt wird und daher tun kann, was sie will, ohne sich an die Regeln des Browsers halten zu müssen. Das stimmt, aber die gute Nachricht ist, dass Sie mit dem Fenstersteuerelement-Overlay, um das es in diesem Artikel geht, bald ähnliche Benutzeroberflächen für Ihre PWA erstellen können.

Komponenten des Window Controls Overlay

Das Window Controls Overlay besteht aus vier untergeordneten Funktionen:

  1. Der "window-controls-overlay"-Wert für das Feld "display_override" im Web-App-Manifest.
  2. Die CSS-Umgebungsvariablen titlebar-area-x, titlebar-area-y, titlebar-area-width und titlebar-area-height.
  3. Die Standardisierung der zuvor proprietären CSS-Eigenschaft -webkit-app-region als app-region-Eigenschaft zum Definieren von ziehbaren Bereichen in Webinhalten.
  4. Ein Mechanismus zum Abfragen und Umgehen des Bereichs für Fenstersteuerelemente über das windowControlsOverlay-Element von window.navigator.

Was ist das Window Controls Overlay?

Der Bereich der Titelleiste befindet sich links oder rechts neben den Fenstersteuerelementen (also den Schaltflächen zum Minimieren, Maximieren, Schließen usw.) und enthält häufig den Titel der Anwendung. Mit dem Overlay für Fenstersteuerelemente können progressive Web-Apps (PWAs) app-ähnlicher wirken, indem die vorhandene Titelleiste mit voller Breite durch ein kleines Overlay mit den Fenstersteuerelementen ersetzt wird. So können Entwickler benutzerdefinierte Inhalte in dem Bereich platzieren, der zuvor von der Titelleiste des Browsers belegt war.

Aktueller Status

Schritt Status
1. Erklärung erstellen Abschließen
2. Ersten Entwurf der Spezifikation erstellen Abschließen
3. Feedback einholen und Design iterieren In Bearbeitung
4. Ursprungstest Abgeschlossen
5. Launch Abgeschlossen (in Chromium 104)

Window Controls Overlay verwenden

window-controls-overlay dem Web-App-Manifest hinzufügen

Eine progressive Web-App kann die Überlagerung der Fenstersteuerelemente aktivieren, indem sie "window-controls-overlay" als primäres "display_override"-Element im Web-App-Manifest hinzufügt:

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

Das Overlay mit den Fenstersteuerelementen wird nur angezeigt, wenn alle folgenden Bedingungen erfüllt sind:

  1. Die App wird nicht im Browser, sondern in einem separaten PWA-Fenster geöffnet.
  2. Das Manifest enthält "display_override": ["window-controls-overlay"]. Danach sind andere Werte zulässig.
  3. Die PWA wird auf einem Desktop-Betriebssystem ausgeführt.
  4. Der aktuelle Ursprung stimmt mit dem Ursprung überein, für den die PWA installiert wurde.

Das Ergebnis ist ein leerer Titelbereich mit den regulären Fenstersteuerelementen auf der linken oder rechten Seite, je nach Betriebssystem.

Ein App-Fenster mit einer leeren Titelleiste und den Fenstersteuerelementen auf der linken Seite.
Eine leere Titelleiste, die für benutzerdefinierte Inhalte vorgesehen ist.

Inhalte in die Titelleiste verschieben

Da nun Platz in der Titelleiste ist, können Sie etwas dorthin verschieben. Für diesen Artikel habe ich eine PWA für Wikimedia Featured Content erstellt. Eine nützliche Funktion für diese App wäre die Suche nach Wörtern in den Artikeltiteln. Der HTML-Code für die Suchfunktion sieht so aus:

<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>

Damit das div in die Titelleiste verschoben wird, ist etwas CSS erforderlich:

.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);
}

Die Auswirkungen dieses Codes sind im Screenshot unten zu sehen. Die Titelleiste ist vollständig responsiv. Wenn Sie die Größe des PWA-Fensters ändern, reagiert die Titelleiste so, als ob sie aus regulärem HTML-Inhalt bestünde, was tatsächlich der Fall ist.

Ein App-Fenster mit einer Suchleiste in der Titelleiste.
Die neue Titelleiste ist aktiv und reagiert.

Festlegen, welche Teile der Titelleiste gezogen werden können

Der Screenshot oben deutet zwar darauf hin, dass Sie fertig sind, aber das ist noch nicht ganz der Fall. Das PWA-Fenster kann nicht mehr verschoben werden (abgesehen von einem sehr kleinen Bereich), da die Schaltflächen für die Fenstersteuerung keine Ziehbereiche sind und der Rest der Titelleiste aus dem Such-Widget besteht. Sie können das Problem mit der CSS-Eigenschaft app-region und dem Wert drag beheben. Im konkreten Fall ist es in Ordnung, alles außer dem input-Element ziehbar zu machen.

/* 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;
}

Mit diesem CSS kann der Nutzer das App-Fenster wie gewohnt verschieben, indem er div, img oder label zieht. Nur das input-Element ist interaktiv, damit die Suchanfrage eingegeben werden kann.

Funktionserkennung

Die Unterstützung für das Einblenden von Fenstersteuerelementen kann durch Testen auf das Vorhandensein von windowControlsOverlay erkannt werden:

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

Abfragen des Bereichs mit den Fenstersteuerelementen mit windowControlsOverlay

Der bisherige Code hat ein Problem: Auf einigen Plattformen befinden sich die Fenstersteuerelemente rechts, auf anderen links. Außerdem ändert sich die Position des Chrome-Dreipunkt-Menüs je nach Plattform. Das bedeutet, dass das Hintergrundbild mit linearem Farbverlauf dynamisch angepasst werden muss, damit es von #131313 → maroon oder maroon → #131313 → maroon verläuft und sich in die Hintergrundfarbe maroon der Titelleiste einfügt, die durch <meta name="theme-color" content="maroon"> bestimmt wird. Dazu können Sie die getTitlebarAreaRect() API für das Attribut navigator.windowControlsOverlay abfragen.

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');
}

Anstatt das Hintergrundbild direkt in den CSS-Regeln der Klasse .search zu definieren (wie bisher), werden im geänderten Code jetzt zwei Klassen verwendet, die durch den Code oben dynamisch festgelegt werden.

/* 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);
}

Ermitteln, ob das Overlay für Fenstersteuerelemente sichtbar ist

Das Overlay für Fenstersteuerelemente ist nicht immer im Bereich der Titelleiste sichtbar. Natürlich ist sie nicht in Browsern verfügbar, die das Window Controls Overlay-Feature nicht unterstützen. Sie ist aber auch nicht verfügbar, wenn die entsprechende PWA in einem Tab ausgeführt wird. Um diese Situation zu erkennen, können Sie das Attribut visible des windowControlsOverlay abfragen:

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

Alternativ können Sie auch die Media-Query display-mode in JavaScript und/oder CSS verwenden:

// 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. */ 
}

Benachrichtigungen über Änderungen an der Geometrie erhalten

Das Abfragen des Overlay-Bereichs für die Fenstersteuerung mit getTitlebarAreaRect() kann für einmalige Aktionen wie das Festlegen des richtigen Hintergrundbilds basierend auf der Position der Fenstersteuerung ausreichen. In anderen Fällen ist jedoch eine detailliertere Steuerung erforderlich. Ein möglicher Anwendungsfall wäre beispielsweise, das Overlay für Fenstersteuerelemente an den verfügbaren Platz anzupassen und einen Witz direkt im Overlay für Fenstersteuerelemente hinzuzufügen, wenn genügend Platz vorhanden ist.

Bereich für das Window Controls Overlay in einem schmalen Fenster mit gekürztem Text.
An ein schmaleres Fenster angepasste Steuerelemente der Titelleiste.

Sie können sich über Änderungen an der Geometrie benachrichtigen lassen, indem Sie navigator.windowControlsOverlay.ongeometrychange abonnieren oder einen Event-Listener für das geometrychange-Ereignis einrichten. Dieses Ereignis wird nur ausgelöst, wenn das Overlay für die Fenstersteuerung sichtbar ist, d. h. wenn navigator.windowControlsOverlay.visible gleich true ist.

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

Anstatt ongeometrychange eine Funktion zuzuweisen, können Sie windowControlsOverlay auch einen Event-Listener hinzufügen, wie unten gezeigt. MDN finden Sie weitere Informationen zu den Unterschieden zwischen den beiden.

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

Kompatibilität bei der Ausführung in einem Tab und in nicht unterstützten Browsern

Es gibt zwei mögliche Fälle:

  • Der Fall, in dem eine App in einem Browser ausgeführt wird, der das Window Controls Overlay unterstützt, die App aber in einem Browser-Tab verwendet wird.
  • Wenn eine App in einem Browser ausgeführt wird, der keine Fenstersteuerelemente unterstützt.

In beiden Fällen wird der für das Overlay mit den Fenstersteuerelementen erstellte HTML-Code standardmäßig inline wie regulärer HTML-Inhalt angezeigt und die Fallback-Werte der env()-Variablen werden für die Positionierung verwendet. In unterstützten Browsern können Sie auch festlegen, dass das für das Overlay der Fenstersteuerelemente vorgesehene HTML nicht angezeigt wird. Prüfen Sie dazu die visible-Eigenschaft des Overlays. Wenn sie false zurückgibt, können Sie den entsprechenden HTML-Inhalt ausblenden.

Eine PWA, die in einem Browser-Tab ausgeführt wird. Die Overlay-Fenstersteuerelemente werden im Hauptteil angezeigt.
Steuerelemente für die Titelleiste können in älteren Browsern problemlos im Hauptbereich angezeigt werden.

Zur Erinnerung: In Browsern, die das nicht unterstützen, wird die Manifest-Property "display_override" entweder gar nicht berücksichtigt oder "window-controls-overlay" wird nicht erkannt. In diesem Fall wird der nächste mögliche Wert gemäß der Fallback-Kette verwendet, z. B. "standalone".

Eine PWA, die im eigenständigen Modus ausgeführt wird und deren Fenstersteuerelemente im Body angezeigt werden.
Steuerelemente für die Titelleiste können in älteren Browsern problemlos im Hauptbereich angezeigt werden.

Hinweise zur Benutzeroberfläche

Es ist zwar verlockend, ein klassisches Drop-down-Menü im Bereich des Window Controls Overlay zu erstellen, wird aber nicht empfohlen. Dies würde gegen die Designrichtlinien für macOS verstoßen, eine Plattform, auf der Nutzer Menüleisten (sowohl vom System bereitgestellte als auch benutzerdefinierte) oben auf dem Bildschirm erwarten.

Wenn Ihre App im Vollbildmodus ausgeführt wird, sollten Sie sorgfältig abwägen, ob das Overlay für Fenstersteuerelemente Teil der Vollbildansicht sein soll. Möglicherweise möchten Sie das Layout neu anordnen, wenn das onfullscreenchange-Ereignis ausgelöst wird.

Demo

Ich habe eine Demo erstellt, die Sie in verschiedenen unterstützten und nicht unterstützten Browsern sowie im installierten und nicht installierten Zustand ausprobieren können. Um das Window Controls Overlay nutzen zu können, müssen Sie die App installieren. Unten sehen Sie zwei Screenshots, die Ihnen einen Eindruck davon vermitteln, was Sie erwartet. Der Quellcode für die App ist auf Glitch verfügbar.

Die Wikimedia Featured Content-Demo-App mit dem Overlay für Fenstersteuerelemente.
Die Demo-App ist für Tests verfügbar.

Die Suchfunktion im Overlay für Fenstersteuerelemente ist voll funktionsfähig:

Die Wikimedia Featured Content-Demo-App mit Window Controls Overlay und aktiver Suche nach dem Begriff „cleopa…“, wobei einer der Artikel mit dem übereinstimmenden Begriff „Cleopatra“ hervorgehoben wird.
Eine Suchfunktion, die das Window Controls Overlay verwendet.

Sicherheitsaspekte

Das Chromium-Team hat die Window Controls Overlay API unter Berücksichtigung der in Controlling Access to Powerful Web Platform Features definierten Grundsätze entwickelt und implementiert, darunter Nutzerkontrolle, Transparenz und Ergonomie.

Spoofing

Wenn Websites die Titelleiste teilweise steuern können, haben Entwickler die Möglichkeit, Inhalte in einem Bereich zu fälschen, der zuvor vertrauenswürdig und vom Browser gesteuert war. Derzeit enthält der Standalone-Modus in Chromium-Browsern eine Titelleiste, in der beim ersten Start links der Titel der Webseite und rechts der Ursprung der Seite angezeigt wird (gefolgt von der Schaltfläche „Einstellungen und mehr“ und den Fenstersteuerelementen). Nach einigen Sekunden verschwindet der Originaltext. Wenn der Browser auf eine linksläufige Sprache eingestellt ist, wird dieses Layout gespiegelt, sodass sich der Ausgangstext auf der linken Seite befindet. Dadurch wird das Overlay mit den Fenstersteuerelementen geöffnet, um den Ursprung zu fälschen, wenn zwischen dem Ursprung und dem rechten Rand des Overlays nicht genügend Abstand vorhanden ist. Beispielsweise könnte der Ursprung „evil.ltd“ mit der vertrauenswürdigen Website „google.com“ ergänzt werden, sodass Nutzer die Quelle für vertrauenswürdig halten. Der Quelltext soll beibehalten werden, damit Nutzer wissen, woher die App stammt, und sichergehen können, dass dies ihren Erwartungen entspricht. Bei Browsern, die für die Leserichtung von rechts nach links konfiguriert sind, muss rechts vom Ursprungstext genügend Padding vorhanden sein, damit eine schädliche Website den unsicheren Ursprung nicht mit einem vertrauenswürdigen Ursprung verknüpfen kann.

Fingerprinting

Das Aktivieren des Einblendens von Fenstersteuerelementen und der ziehbaren Bereiche birgt keine erheblichen Datenschutzbedenken, abgesehen von der Funktionserkennung. Aufgrund der unterschiedlichen Größen und Positionen der Schaltflächen zur Fenstersteuerung in den verschiedenen Betriebssystemen gibt die Methode navigator.windowControlsOverlay.getTitlebarAreaRect() jedoch ein DOMRect zurück, dessen Position und Abmessungen Informationen zum Betriebssystem liefern, auf dem der Browser ausgeführt wird. Derzeit können Entwickler das Betriebssystem bereits über den User-Agent-String ermitteln. Aufgrund von Bedenken hinsichtlich des Fingerprintings wird jedoch darüber diskutiert, den UA-String einzufrieren und Betriebssystemversionen zu vereinheitlichen. Die Browser-Community untersucht derzeit, wie häufig sich die Größe des Overlays für Fenstersteuerelemente auf verschiedenen Plattformen ändert. Derzeit wird davon ausgegangen, dass diese über Betriebssystemversionen hinweg relativ stabil sind und daher nicht für die Beobachtung kleinerer Betriebssystemversionen geeignet wären. Dies ist zwar ein potenzielles Fingerprinting-Problem, es betrifft jedoch nur installierte PWAs, die die benutzerdefinierte Titelleistenfunktion verwenden, und nicht die allgemeine Browsernutzung. Außerdem ist die navigator.windowControlsOverlay API nicht für iFrames verfügbar, die in eine PWA eingebettet sind.

Wenn Sie in einer PWA zu einem anderen Ursprung wechseln, wird die normale eigenständige Titelleiste verwendet, auch wenn die oben genannten Kriterien erfüllt sind und die PWA mit dem Overlay für Fenstersteuerelemente gestartet wird. So wird der schwarze Balken berücksichtigt, der bei der Navigation zu einem anderen Startpunkt angezeigt wird. Nachdem Sie zum ursprünglichen Ursprung zurückgekehrt sind, wird wieder das Overlay mit den Fenstersteuerelementen verwendet.

Eine schwarze URL-Leiste für die Navigation außerhalb der Herkunft.
Eine schwarze Leiste wird angezeigt, wenn der Nutzer zu einem anderen Ursprung wechselt.

Feedback

Das Chromium-Team möchte mehr über Ihre Erfahrungen mit der Window Controls Overlay API erfahren.

Informationen zum API-Design

Funktioniert etwas an der API nicht wie erwartet? Oder fehlen Methoden oder Eigenschaften, die Sie für die Umsetzung Ihrer Idee benötigen? Haben Sie Fragen oder Anmerkungen zum Sicherheitsmodell? Melden Sie ein Spezifikationsproblem im entsprechenden GitHub-Repository oder fügen Sie Ihre Gedanken zu einem bestehenden Problem hinzu.

Problem mit der Implementierung melden

Haben Sie einen Fehler in der Chromium-Implementierung gefunden? Oder weicht die Implementierung von der Spezifikation ab? Melden Sie einen Fehler unter new.crbug.com. Geben Sie dabei so viele Details wie möglich an, fügen Sie eine einfache Anleitung zur Reproduktion hinzu und geben Sie UI>Browser>WebAppInstalls in das Feld Components (Komponenten) ein.

API-Support zeigen

Planen Sie, die Window Controls Overlay API zu verwenden? Ihr öffentlicher Support hilft dem Chromium-Team, Funktionen zu priorisieren, und zeigt anderen Browseranbietern, wie wichtig es ist, sie zu unterstützen.

Senden Sie einen Tweet an @ChromiumDev mit dem Hashtag #WindowControlsOverlay und teilen Sie uns mit, wo und wie Sie die Funktion verwenden.

Nützliche Links

Danksagungen

Das Overlay für Fenstersteuerelemente wurde von Amanda Baker vom Microsoft Edge-Team implementiert und spezifiziert. Dieser Artikel wurde von Joe Medley und Kenneth Rohde Christiansen geprüft. Hero-Image von Sigmund auf Unsplash.