Overlay der Fenstersteuerelemente in der Titelleiste der PWA anpassen

Mit dem Bereich in der Titelleiste neben den Fenstersteuerelementen lässt sich Ihre PWA noch mehr wie eine App aussehen.

Wenn Sie sich an meinen Artikel Ihre PWA nutzerfreundlicher gestalten erinnern, erinnern Sie sich vielleicht daran, dass ich die Anpassung der Titelleiste Ihrer App als Strategie zur Schaffung einer App-ähnlichen Benutzeroberfläche erwähnt habe. Hier siehst du ein Beispiel für die macOS-Podcasts App.

Titelleiste der macOS-Podcasts App mit Schaltflächen zur Mediensteuerung und Metadaten zum gerade wiedergegebenen Podcast
Eine benutzerdefinierte Titelleiste lässt Ihre PWA eher wie eine plattformspezifische App wirken.

Jetzt könnten Sie einwenden, dass Podcasts eine plattformspezifische macOS-App ist, die nicht in einem Browser ausgeführt wird und daher tun und lassen 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 der Funktion „Fenstersteuerungs-Overlay“, die in diesem Artikel behandelt wird, bald ähnliche Benutzeroberflächen für Ihre PWA erstellen können.

Komponenten für das Overlay für Fenstersteuerelemente

Das Overlay für Fenstersteuerelemente besteht aus vier Unterfunktionen:

  1. Der "window-controls-overlay"-Wert für das Feld "display_override" im Manifest der Webanwendung.
  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-Property -webkit-app-region als Property app-region zum Definieren von ziehbaren Bereichen in Webinhalten.
  4. Ein Mechanismus, mit dem der Bereich für Fenstersteuerungen über das Mitglied windowControlsOverlay von window.navigator abgefragt und umgangen werden kann.

Was ist das Overlay für Fenstersteuerelemente?

Der Bereich der Titelleiste bezieht sich auf den Bereich links oder rechts neben den Fenstersteuerungen (d. h. die 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) ein App-ähnlicheres Erscheinungsbild bieten, indem die vorhandene Titelleiste in voller Breite durch ein kleines Overlay mit den Fenstersteuerelementen ersetzt wird. So können Entwickler benutzerdefinierte Inhalte in dem Bereich platzieren, der zuvor vom Browser gesteuert wurde.

Aktueller Status

Schritt Status
1. Erläuternde Mitteilung 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)

Overlay für Fenstersteuerelemente verwenden

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

Für eine progressive Webanwendung kann das Overlay für Fenstersteuerungen aktiviert werden, indem "window-controls-overlay" als primäres "display_override"-Mitglied in das Manifest der Webanwendung eingefügt wird:

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

Das Overlay mit den Fenstersteuerungen ist nur sichtbar, 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. Die aktuelle Quelle stimmt mit der Quelle überein, für die die PWA installiert wurde.

Das Ergebnis ist ein leerer Titelleistenbereich mit den regulären Fenstersteuerungen links oder rechts, je nach Betriebssystem.

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

Inhalte in die Titelleiste verschieben

Da jetzt Platz in der Titelleiste ist, können Sie dort etwas verschieben. Für diesen Artikel habe ich eine PWA für die Funktion „Empfohlene Inhalte“ von Wikimedia erstellt. Eine nützliche Funktion für diese App könnte die Suche nach Wörtern in den Artikeltiteln sein. 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>

Um dieses div in die Titelleiste zu verschieben, 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 Wirkung dieses Codes ist 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 bestünde sie aus regulären HTML-Inhalten, was in gewisser Weise auch der Fall ist.

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

Festlegen, welche Teile der Titelleiste verschiebbar sind

Der Screenshot oben suggeriert, dass Sie fertig sind, aber das ist noch nicht der Fall. Das PWA-Fenster kann nicht mehr verschoben werden (außer in einem sehr kleinen Bereich), da die Schaltflächen für die Fenstersteuerung keine Ziehpunkte sind und der Rest der Titelleiste aus dem Such-Widget besteht. Verwenden Sie dazu die CSS-Eigenschaft app-region mit dem Wert drag. In diesem konkreten Fall ist es in Ordnung, alles außer dem input-Element zu einem Ziehpunkt 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 durch Ziehen der div, img oder label verschieben. Nur das input-Element ist interaktiv, sodass die Suchanfrage eingegeben werden kann.

Funktionserkennung

Die Unterstützung für das Einblenden von Fenstersteuerelementen lässt sich prüfen, indem Sie prüfen, ob folgende Elemente vorhanden sind: windowControlsOverlay

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

Bereich für Fenstersteuerungen mit windowControlsOverlay abfragen

Der Code hat bisher ein Problem: Auf einigen Plattformen befinden sich die Fenstersteuerungen rechts, auf anderen links. Außerdem ändert sich die Position des Chrome-Dreipunkt-Menüs je nach Plattform. Das bedeutet, dass das lineare Farbverlaufs-Hintergrundbild dynamisch angepasst werden muss, damit es von #131313 nach maroon oder von maroon nach #131313 nach maroon verläuft, damit es sich in die maroon-Hintergrundfarbe der Titelleiste einfügt, die von <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 wie zuvor direkt in den CSS-Regeln der Klasse .search zu haben, werden im geänderten Code jetzt zwei Klassen verwendet, die vom 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);
}

Feststellen, ob das Overlay für Fenstersteuerelemente sichtbar ist

Das Overlay für die Fenstersteuerung ist nicht in allen Fällen im Bereich der Titelleiste sichtbar. In Browsern, die die Funktion „Fenstersteuerungs-Overlay“ nicht unterstützen, ist sie natürlich nicht zu sehen. Das gilt auch, wenn die betreffende PWA in einem Tab ausgeführt wird. Um diese Situation zu erkennen, können Sie die Property visible der windowControlsOverlay abfragen:

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

Alternativ können Sie die Medienabfrage display-mode auch 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 Fenstersteuerelemente mit getTitlebarAreaRect() kann für einmalige Aktionen wie das Festlegen des richtigen Hintergrundbilds basierend auf der Position der Fenstersteuerelemente ausreichen. In anderen Fällen ist jedoch eine detailliertere Steuerung erforderlich. Ein möglicher Anwendungsfall wäre beispielsweise, das Overlay mit den Fenstersteuerelementen anhand des verfügbaren Platzes anzupassen und bei ausreichend Platz einen Witz direkt in das Overlay einzufügen.

In einem schmalen Fenster wird der Bereich mit den Fenstersteuerungen überlagert und der Text wird gekürzt.
Titelleistensteuerungen, die an ein schmales Fenster angepasst sind.

Sie können sich über Änderungen an der Geometrie benachrichtigen lassen, indem Sie navigator.windowControlsOverlay.ongeometrychange abonnieren oder einen Ereignis-Listener für das Ereignis geometrychange einrichten. Dieses Ereignis wird nur ausgelöst, wenn das Overlay mit den Fenstersteuerungen sichtbar ist, d. h. wenn navigator.windowControlsOverlay.visible 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 dargestellt. Weitere Informationen zu den Unterschieden zwischen den beiden finden Sie auf der MDN.

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

Kompatibilität beim Ausführen in einem Tab und in nicht unterstützten Browsern

Es gibt zwei mögliche Fälle:

  • Eine App wird in einem Browser ausgeführt, der das Overlay für Fenstersteuerungen unterstützt, aber die App wird in einem Browsertab verwendet.
  • Eine App wird in einem Browser ausgeführt, der das Einblenden von Fenstersteuerelementen nicht unterstützt.

In beiden Fällen wird das für das Fensterkontroll-Overlay erstellte HTML-Element standardmäßig Inline wie reguläre HTML-Inhalte 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 mit den Fenstersteuerungen vorgesehene HTML nicht angezeigt wird. Prüfen Sie dazu die Eigenschaft visible des Overlays. Wenn false zurückgegeben wird, können Sie die HTML-Inhalte ausblenden.

Eine PWA, die in einem Browsertab ausgeführt wird, wobei die Fenstersteuerung im Body eingeblendet ist.
Steuerelemente, die für die Titelleiste gedacht sind, können in älteren Browsern leicht im Textkörper angezeigt werden.

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

Eine PWA, die im eigenständigen Modus ausgeführt wird, wobei die Fenstersteuerung im Body angezeigt wird.
Steuerelemente, die für die Titelleiste gedacht sind, können in älteren Browsern leicht im Textkörper angezeigt werden.

Hinweise zur Benutzeroberfläche

Es ist zwar verlockend, aber es wird nicht empfohlen, im Bereich „Fenstersteuerung“ ein klassisches Drop-down-Menü zu erstellen. Dies würde gegen die Designrichtlinien für macOS verstoßen, einer Plattform, auf der Nutzer Menüleisten (sowohl systemeigene als auch benutzerdefinierte) oben auf dem Bildschirm erwarten.

Wenn Ihre App im Vollbildmodus ausgeführt wird, sollten Sie sorgfältig überlegen, ob es sinnvoll ist, das Overlay für die Fenstersteuerung in der Vollbildansicht zu platzieren. Möglicherweise möchten Sie Ihr Layout neu anordnen, wenn das Ereignis onfullscreenchange ausgelöst wird.

Demo

Ich habe eine Demo erstellt, die Sie in verschiedenen Browsern mit und ohne Unterstützung sowie im installierten und nicht installierten Zustand ausprobieren können. Wenn Sie das Fensterkontroll-Overlay verwenden möchten, müssen Sie die App installieren. Unten sehen Sie zwei Screenshots, die die Funktion veranschaulichen. Der Quellcode für die App ist auf Glitch verfügbar.

Die Demo-App „Empfohlene Inhalte“ von Wikimedia mit Overlay für Fenstersteuerelemente.
Die Demo-App kann für Tests verwendet werden.

Die Suchfunktion im Overlay mit den Fenstersteuerelementen ist voll funktionsfähig:

Die Demo-App für „Empfohlene Inhalte“ von Wikimedia mit einem Fensterkontroll-Overlay und einer aktiven Suche nach dem Begriff „cleopa…“, bei der einer der Artikel mit dem übereinstimmenden Begriff „Cleopatra“ hervorgehoben wird.
Eine Suchfunktion mit dem Window Controls Overlay.

Sicherheitsaspekte

Das Chromium-Team hat die Window Controls Overlay API anhand der in Controlling Access to Powerful Web Platform Features (Zugriff auf leistungsstarke Funktionen der Webplattform steuern) definierten Grundprinzipien entwickelt und implementiert, einschließlich Nutzersteuerung, Transparenz und Ergonomie.

Spoofing

Wenn Websites die teilweise Kontrolle über die Titelleiste erhalten, können Entwickler Inhalte in einer zuvor vertrauenswürdigen, browsergesteuerten Region fälschen. Derzeit enthält der eigenständige Modus in Chromium-Browsern eine Titelleiste, in der beim ersten Start links der Titel der Webseite und rechts die Herkunft der Seite angezeigt werden, gefolgt von der Schaltfläche „Einstellungen und mehr“ und den Fenstersteuerungen. Nach einigen Sekunden verschwindet der Originaltext. Wenn der Browser auf eine Sprache eingestellt ist, die von rechts nach links geschrieben wird, wird dieses Layout so gedreht, dass der Originaltext links angezeigt wird. Dadurch wird das Overlay mit den Fenstersteuerungen geöffnet, um den Ursprung zu fälschen, wenn zwischen dem Ursprung und dem rechten Rand des Overlays nicht genügend Abstand vorhanden ist. So könnte beispielsweise der Ursprung „evil.ltd“ an die vertrauenswürdige Website „google.com“ angehängt werden, was Nutzer glauben lässt, dass die Quelle vertrauenswürdig ist. Wir möchten diesen Ursprungstext beibehalten, damit Nutzer wissen, woher die App stammt, und sichergehen können, dass sie ihren Erwartungen entspricht. Bei Browsern, die für die RTL-Leserichtung konfiguriert sind, muss rechts neben dem Ursprungstext genügend Abstand vorhanden sein, damit eine schädliche Website den unsicheren Ursprung nicht an einen vertrauenswürdigen Ursprung anhängen kann.

Fingerabdruck

Das Aktivieren des Overlays für die Fenstersteuerung und der Ziehpunkte stellt abgesehen von der Funktion zur Erkennung von Funktionen keine erheblichen Datenschutzrisiken dar. Aufgrund unterschiedlicher Größen und Positionen der Fenstersteuerungsschaltflächen in verschiedenen Betriebssystemen gibt die Methode navigator.windowControlsOverlay.getTitlebarAreaRect() jedoch eine DOMRect zurück, deren Position und Abmessungen Informationen zum Betriebssystem enthalten, unter dem der Browser ausgeführt wird. Derzeit können Entwickler das Betriebssystem bereits anhand des User-Agent-Strings ermitteln. Aufgrund von Bedenken im Zusammenhang mit dem Fingerprinting wird jedoch diskutiert, den UA-String einzufrieren und die Betriebssystemversionen zu vereinheitlichen. Die Browser-Community versucht derzeit herauszufinden, wie oft sich die Größe des Overlays für die Fenstersteuerung zwischen den Plattformen ändert. Derzeit wird davon ausgegangen, dass diese Overlays zwischen den Betriebssystemversionen relativ stabil sind und daher nicht für die Beobachtung von kleineren Betriebssystemversionen geeignet sind. Obwohl dies ein potenzielles Fingerprinting-Problem ist, gilt es nur für installierte PWAs, die die benutzerdefinierte Titelleiste verwenden, und nicht für die allgemeine Browsernutzung. Außerdem ist die navigator.windowControlsOverlay API nicht für Iframes verfügbar, die in einer PWA eingebettet sind.

Wenn Sie innerhalb einer PWA zu einem anderen Ursprung wechseln, wird die normale eigenständige Titelleiste verwendet, auch wenn die PWA die oben genannten Kriterien erfüllt und mit dem Overlay für Fenstersteuerelemente gestartet wird. Dies ist für die schwarze Leiste erforderlich, die beim Wechsel zu einer anderen Quelle angezeigt wird. Wenn Sie zum ursprünglichen Ursprung zurückkehren, wird das Overlay für die Fenstersteuerung wieder verwendet.

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

Feedback

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

Informationen zum API-Design

Funktioniert die API nicht wie erwartet? Oder fehlen Methoden oder Eigenschaften, die Sie für die Implementierung Ihrer Idee benötigen? Haben Sie Fragen oder Kommentare zum Sicherheitsmodell? Reichen Sie ein Problem mit der Spezifikation im entsprechenden GitHub-Repository ein oder fügen Sie Ihre Gedanken zu einem vorhandenen Problem hinzu.

Problem mit der Implementierung melden

Haben Sie einen Fehler in der Chromium-Implementierung gefunden? Oder unterscheidet sich die Implementierung von der Spezifikation? Melden Sie den Fehler unter new.crbug.com. Geben Sie dabei so viele Details wie möglich an, eine einfache Anleitung zur Reproduktion und geben Sie UI>Browser>WebAppInstalls in das Feld Components ein. Glitch eignet sich hervorragend, um schnell und einfach Reproduktionen zu teilen.

Unterstützung für die API anzeigen

Beabsichtigen Sie, die Window Controls Overlay API zu verwenden? Ihre öffentliche Unterstützung 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 ihn 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