Personnaliser les commandes de fenêtre en superposition de la barre de titre de votre PWA

Utilisez la zone de la barre de titre à côté des commandes de fenêtre pour donner à votre PWA l'apparence d'une application.

Si vous vous souvenez de mon article Donner à votre PWA l'apparence d'une application, vous vous souviendrez peut-être que j'ai mentionné la personnalisation de la barre de titre de votre application comme stratégie pour créer une expérience plus proche d'une application. Voici un exemple de ce à quoi cela peut ressembler dans l'application Podcasts pour macOS.

Barre de titre de l'application Podcasts pour macOS affichant les boutons de commande multimédia et les métadonnées du podcast en cours de lecture.
Une barre de titre personnalisée donne à votre PWA l'apparence d'une application spécifique à la plate-forme.

Vous pouvez être tenté de vous opposer en disant que Podcasts est une application macOS spécifique à la plate-forme qui ne s'exécute pas dans un navigateur et peut donc faire ce qu'elle veut sans avoir à respecter les règles du navigateur. C'est vrai, mais la bonne nouvelle est que la fonctionnalité de superposition des commandes de fenêtre, qui est l'objet de cet article, vous permettra bientôt de créer des interfaces utilisateur similaires pour votre PWA.

Composants de la superposition des commandes de fenêtre

La superposition des commandes de fenêtre se compose de quatre sous-fonctionnalités:

  1. Valeur "window-controls-overlay" pour le champ "display_override" dans le fichier manifeste de l'application Web.
  2. Les variables d'environnement CSS titlebar-area-x, titlebar-area-y, titlebar-area-width et titlebar-area-height.
  3. Standardisation de la propriété CSS -webkit-app-region, auparavant propriétaire, en tant que propriété app-region pour définir des zones déplaçables dans le contenu Web.
  4. Mécanisme permettant d'interroger et de contourner la région de commandes de fenêtre via le membre windowControlsOverlay de window.navigator.

Qu'est-ce que la superposition des commandes de fenêtre ?

La zone de la barre de titre fait référence à l'espace situé à gauche ou à droite des commandes de la fenêtre (c'est-à-dire les boutons de réduction, de maximisation, de fermeture, etc.) et contient souvent le titre de l'application. La superposition des commandes de fenêtre permet aux applications Web progressives (PWA) de fournir une expérience plus semblable à une application en remplaçant la barre de titre pleine largeur existante par une petite superposition contenant les commandes de fenêtre. Cela permet aux développeurs de placer du contenu personnalisé dans la zone de barre de titre auparavant contrôlée par le navigateur.

État actuel

Étape État
1. Créer un message d'explication Fin
2. Créer une première ébauche de la spécification Fin
3. Recueillir des commentaires et itérer sur la conception En cours
4. Essai Origin Terminé
5. Lancement Terminé (dans Chromium 104)

Utiliser la superposition des commandes de fenêtre

Ajouter window-controls-overlay au fichier manifeste de l'application Web

Une progressive web app peut activer la superposition des commandes de fenêtre en ajoutant "window-controls-overlay" en tant que membre "display_override" principal dans le fichier manifeste de l'application Web:

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

La superposition des commandes de fenêtre n'est visible que si toutes les conditions suivantes sont remplies:

  1. L'application n'est pas ouverte dans le navigateur, mais dans une fenêtre PWA distincte.
  2. Le fichier manifeste inclut "display_override": ["window-controls-overlay"]. (D'autres valeurs sont autorisées par la suite.)
  3. La PWA s'exécute sur un système d'exploitation pour ordinateur.
  4. L'origine actuelle correspond à l'origine pour laquelle la PWA a été installée.

La zone de la barre de titre est donc vide, avec les commandes de fenêtre standards à gauche ou à droite, selon le système d'exploitation.

Fenêtre d'application avec une barre de titre vide et les commandes de la fenêtre à gauche.
Barre de titre vide prête à accueillir du contenu personnalisé.

Déplacer du contenu dans la barre de titre

Maintenant qu'il y a de l'espace dans la barre de titre, vous pouvez y placer un élément. Pour cet article, j'ai créé une PWA de contenus sélectionnés Wikimedia. Une fonctionnalité utile pour cette application peut être la recherche de mots dans les titres des articles. Le code HTML de la fonctionnalité de recherche se présente comme suit:

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

Pour déplacer cet élément div vers le haut de la barre de titre, vous devez ajouter du code 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);
}

Vous pouvez voir l'effet de ce code dans la capture d'écran ci-dessous. La barre de titre est entièrement responsive. Lorsque vous redimensionnez la fenêtre de la PWA, la barre de titre réagit comme si elle était composée de contenu HTML standard, ce qui est le cas.

Fenêtre d&#39;application avec une barre de recherche dans la barre de titre.
La nouvelle barre de titre est active et réactive.

Déterminer les parties de la barre de titre qui peuvent être déplacées

Bien que la capture d'écran ci-dessus suggère que vous avez terminé, ce n'est pas tout à fait le cas. La fenêtre de la PWA n'est plus déplaçable (à l'exception d'une très petite zone), car les boutons de commande de la fenêtre ne sont pas des zones de glissement, et le reste de la barre de titre se compose du widget de recherche. Pour résoudre ce problème, utilisez la propriété CSS app-region avec une valeur de drag. Dans le cas concret, vous pouvez tout à fait rendre tout élément autre que l'élément input déplaçable.

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

Avec ce CSS en place, l'utilisateur peut faire glisser la fenêtre de l'application comme d'habitude en faisant glisser le div, le img ou le label. Seul l'élément input est interactif afin que la requête de recherche puisse être saisie.

Détection de fonctionnalités

La prise en charge de la superposition des commandes de fenêtre peut être détectée en vérifiant l'existence de windowControlsOverlay:

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

Interroger la région des commandes de fenêtre avec windowControlsOverlay

Le code présente un problème jusqu'à présent: sur certaines plates-formes, les commandes de fenêtre se trouvent à droite, sur d'autres, à gauche. Pour couronner le tout, le menu Chrome à trois points change également de position en fonction de la plate-forme. Cela signifie que l'image d'arrière-plan au dégradé linéaire doit être adaptée de manière dynamique pour s'exécuter de #131313maroon ou maroon#131313maroon, afin qu'elle se marie à la couleur d'arrière-plan maroon de la barre de titre, qui est déterminée par <meta name="theme-color" content="maroon">. Pour ce faire, interrogez l'API getTitlebarAreaRect() sur la propriété 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');
}

Au lieu d'avoir directement l'image de fond dans les règles CSS de la classe .search (comme précédemment), le code modifié utilise désormais deux classes que le code ci-dessus définit de manière dynamique.

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

Déterminer si la superposition des commandes de fenêtre est visible

La superposition des commandes de fenêtre n'est pas toujours visible dans la barre de titre. Bien qu'il ne soit naturellement pas présent dans les navigateurs qui ne prennent pas en charge la fonctionnalité de superposition des commandes de fenêtre, il ne sera pas non plus présent lorsque la PWA en question s'exécute dans un onglet. Pour détecter cette situation, vous pouvez interroger la propriété visible de windowControlsOverlay:

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

Vous pouvez également utiliser la requête média display-mode en JavaScript et/ou en 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. */ 
}

Recevoir des notifications en cas de modification de la géométrie

Interroger la zone de superposition des commandes de fenêtre avec getTitlebarAreaRect() peut suffire pour des opérations ponctuelles, comme définir l'image de fond appropriée en fonction de l'emplacement des commandes de fenêtre, mais dans d'autres cas, un contrôle plus précis est nécessaire. Par exemple, un cas d'utilisation possible consiste à adapter la superposition des commandes de fenêtre en fonction de l'espace disponible et à ajouter une blague directement dans la superposition des commandes de fenêtre lorsqu'il y a suffisamment d'espace.

Zone de superposition des commandes de fenêtre sur une fenêtre étroite avec du texte abrégé.
Les commandes de la barre de titre sont adaptées à une fenêtre étroite.

Vous pouvez être averti des modifications de géométrie en vous abonnant à navigator.windowControlsOverlay.ongeometrychange ou en configurant un écouteur d'événement pour l'événement geometrychange. Cet événement ne se déclenche que lorsque la superposition des commandes de fenêtre est visible, c'est-à-dire lorsque navigator.windowControlsOverlay.visible est 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);
}

Plutôt que d'attribuer une fonction à ongeometrychange, vous pouvez également ajouter un écouteur d'événements à windowControlsOverlay, comme ci-dessous. Pour en savoir plus sur la différence entre les deux, consultez la page MDN.

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

Compatibilité lors de l'exécution dans un onglet et sur des navigateurs non compatibles

Il existe deux cas possibles:

  • Cas où une application s'exécute dans un navigateur qui prend en charge la superposition des commandes de fenêtre, mais où l'application est utilisée dans un onglet de navigateur.
  • Cas où une application s'exécute dans un navigateur qui n'est pas compatible avec la superposition des commandes de fenêtre.

Dans les deux cas, par défaut, le code HTML créé pour la superposition des commandes de fenêtre s'affiche en ligne comme un contenu HTML standard, et les valeurs de remplacement des variables env() sont utilisées pour le positionnement. Dans les navigateurs compatibles, vous pouvez également choisir de ne pas afficher le code HTML désigné pour la superposition des commandes de fenêtre en vérifiant la propriété visible de la superposition. Si elle indique false, vous pouvez masquer ce contenu HTML.

Une PWA exécutée dans un onglet de navigateur, avec la superposition des commandes de fenêtre affichée dans le corps.
Les commandes destinées à la barre de titre peuvent être facilement affichées dans le corps dans les anciens navigateurs.

Pour rappel, les navigateurs non compatibles n'envisagent pas du tout la propriété de fichier manifeste d'application Web "display_override", ou ne reconnaissent pas "window-controls-overlay" et utilisent donc la valeur suivante possible selon la chaîne de remplacement, par exemple "standalone".

Une PWA exécutée en mode autonome avec la superposition des commandes de fenêtre affichée dans le corps.
Les commandes destinées à la barre de titre peuvent être facilement affichées dans le corps dans les anciens navigateurs.

Considérations concernant l'interface utilisateur

Bien que cela puisse être tentant, il est déconseillé de créer un menu déroulant classique dans la zone de superposition des commandes de fenêtre. Cela ne respecterait pas les consignes de conception sur macOS, une plate-forme sur laquelle les utilisateurs s'attendent à ce que les barres de menu (à la fois celles fournies par le système et celles personnalisées) se trouvent en haut de l'écran.

Si votre application offre une expérience en plein écran, réfléchissez bien à l'opportunité d'intégrer la superposition des commandes de fenêtre à la vue en plein écran. Vous pouvez éventuellement réorganiser votre mise en page lorsque l'événement onfullscreenchange se déclenche.

Démo

J'ai créé une démo que vous pouvez utiliser dans différents navigateurs compatibles et non compatibles, et dans les états installés et non installés. Pour profiter de l'expérience de superposition des commandes de fenêtre, vous devez installer l'application. Vous trouverez ci-dessous deux captures d'écran de ce à quoi vous pouvez vous attendre. Le code source de l'application est disponible sur Glitch.

Application de démonstration de la sélection de contenus Wikimedia avec superposition des commandes de fenêtre.
Vous pouvez tester l'application de démonstration.

La fonctionnalité de recherche dans la superposition des commandes de fenêtre est entièrement fonctionnelle:

Application de démonstration de contenus sélectionnés Wikimedia avec superposition des commandes de fenêtre et recherche active du terme &quot;cleopa…&quot; mettant en surbrillance l&#39;un des articles contenant le terme correspondant &quot;Cléopâtre&quot;.
Élément de recherche utilisant la superposition des commandes de fenêtre.

Considérations de sécurité

L'équipe Chromium a conçu et implémenté l'API Window Controls Overlay en suivant les principes de base définis dans Controlling Access to Powerful Web Platform Features (Contrôler l'accès aux fonctionnalités puissantes de la plate-forme Web), y compris le contrôle utilisateur, la transparence et l'ergonomie.

Spoofing

En accordant aux sites un contrôle partiel de la barre de titre, les développeurs peuvent falsifier le contenu dans ce qui était auparavant une région fiable, contrôlée par le navigateur. Actuellement, dans les navigateurs Chromium, le mode autonome inclut une barre de titre qui, au lancement initial, affiche le titre de la page Web à gauche et l'origine de la page à droite (suivi du bouton "Paramètres et plus" et des commandes de la fenêtre). Au bout de quelques secondes, le texte d'origine disparaît. Si le navigateur est défini sur une langue de droite à gauche (RTL), cette mise en page est inversée de sorte que le texte d'origine se trouve à gauche. Cela ouvre la superposition des commandes de fenêtre pour falsifier l'origine si la marge intérieure n'est pas suffisante entre l'origine et le bord droit de la superposition. Par exemple, l'origine "evil.ltd" peut être ajoutée à un site de confiance "google.com", ce qui peut inciter les utilisateurs à penser que la source est fiable. Le plan est de conserver ce texte d'origine afin que les utilisateurs sachent d'où vient l'application et puissent s'assurer qu'elle correspond à leurs attentes. Pour les navigateurs configurés en mode RTL, il doit y avoir suffisamment de marge à droite du texte d'origine pour empêcher un site Web malveillant d'ajouter l'origine non sécurisée à une origine approuvée.

Fingerprinting

L'activation de la superposition des commandes de fenêtre et des régions déplaçables ne pose pas de problèmes de confidentialité importants, à l'exception de la détection des fonctionnalités. Toutefois, en raison des différentes tailles et positions des boutons de contrôle de la fenêtre selon les systèmes d'exploitation, la méthode navigator.windowControlsOverlay.getTitlebarAreaRect() renvoie un DOMRect dont la position et les dimensions révèlent des informations sur le système d'exploitation sur lequel le navigateur s'exécute. Actuellement, les développeurs peuvent déjà découvrir l'OS à partir de la chaîne de l'agent utilisateur, mais en raison des problèmes d'empreinte digitale, il est question de figer la chaîne UA et d'unifier les versions de l'OS. La communauté des navigateurs s'efforce de comprendre la fréquence à laquelle la taille de la superposition des commandes de fenêtre change d'une plate-forme à l'autre, car l'hypothèse actuelle est qu'elle est assez stable d'une version d'OS à l'autre et qu'elle ne serait donc pas utile pour observer les versions mineures de l'OS. Bien qu'il s'agisse d'un problème potentiel d'empreinte digitale, il ne s'applique qu'aux PWA installés qui utilisent la fonctionnalité de barre de titre personnalisée et ne s'applique pas à l'utilisation générale du navigateur. De plus, l'API navigator.windowControlsOverlay ne sera pas disponible pour les iFrames intégrés à une PWA.

Si vous accédez à une autre origine dans une PWA, la barre de titre autonome normale est utilisée, même si elle répond aux critères ci-dessus et est lancée avec la superposition des commandes de fenêtre. Cela permet d'accommoder la barre noire qui s'affiche lors de la navigation vers une autre origine. Une fois que vous êtes revenu à l'origine d'origine, la superposition des commandes de fenêtre est à nouveau utilisée.

Barre d&#39;URL noire pour la navigation hors de l&#39;origine.
Une barre noire s'affiche lorsque l'utilisateur accède à une autre origine.

Commentaires

L'équipe Chromium souhaite connaître votre expérience avec l'API Window Controls Overlay.

Parlez-nous de la conception de l'API

L'API ne fonctionne-t-elle pas comme prévu ? Ou manque-t-il des méthodes ou des propriétés dont vous avez besoin pour implémenter votre idée ? Vous avez une question ou un commentaire sur le modèle de sécurité ? Signalez un problème de spécification dans le dépôt GitHub correspondant ou ajoutez vos commentaires à un problème existant.

Signaler un problème d'implémentation

Avez-vous trouvé un bug dans l'implémentation de Chromium ? Ou l'implémentation est-elle différente de la spécification ? Signalez un bug sur new.crbug.com. Veillez à inclure autant de détails que possible, des instructions simples pour reproduire le problème et saisissez UI>Browser>WebAppInstalls dans le champ Composants. Glitch est idéal pour partager des reproductions rapidement et facilement.

Afficher la compatibilité avec l'API

Comptez-vous utiliser l'API Window Controls Overlay ? Votre soutien public aide l'équipe Chromium à hiérarchiser les fonctionnalités et montre aux autres fournisseurs de navigateurs à quel point il est essentiel de les prendre en charge.

Envoyez un tweet à @ChromiumDev avec le hashtag #WindowControlsOverlay et indiquez-nous où et comment vous l'utilisez.

Liens utiles

Remerciements

La superposition des commandes de fenêtre a été implémentée et spécifiée par Amanda Baker de l'équipe Microsoft Edge. Cet article a été relu par Joe Medley et Kenneth Rohde Christiansen. Image principale par Sigmund sur Unsplash.