Use a área da barra de título ao lado dos controles da janela para que o PWA pareça mais um app.
Se você se lembra do meu artigo Fazer com que sua PWA pareça mais um app, talvez se lembre de como mencionei personalizar a barra de título do app como uma estratégia para criar uma experiência mais parecida com um app. Confira um exemplo de como isso pode ficar mostrando o app Podcasts do macOS.
Agora, você pode ter a tentação de objetar dizendo que o Podcasts é um app específico do macOS que não é executado em um navegador e, portanto, pode fazer o que quiser sem ter que seguir as regras do navegador. É verdade, mas a boa notícia é que o recurso de sobreposição de controles de janela, que é o tema deste artigo, em breve vai permitir que você crie interfaces de usuário semelhantes para sua PWA.
Componentes da sobreposição de controles da janela
A sobreposição de controles de janela consiste em quatro subrecursos:
- O valor
"window-controls-overlay"
do campo"display_override"
no manifesto do app da Web. - As variáveis de ambiente do CSS
titlebar-area-x
,titlebar-area-y
,titlebar-area-width
etitlebar-area-height
. - A padronização da propriedade CSS
-webkit-app-region
, anteriormente reservada, como a propriedadeapp-region
para definir regiões arrastáveis no conteúdo da Web. - Um mecanismo para consultar e contornar a região de controles de janela pelo
membro
windowControlsOverlay
dewindow.navigator
.
O que é a sobreposição de controles de janela
A área da barra de título se refere ao espaço à esquerda ou à direita dos controles da janela (ou seja, os botões para minimizar, maximizar, fechar etc.) e geralmente contém o título do aplicativo. A sobreposição de controles da janela permite que os Progressive Web Apps (PWAs) ofereçam uma sensação mais parecida com um app, trocando a barra de título de largura total existente por uma pequena sobreposição com os controles da janela. Isso permite que os desenvolvedores coloquem conteúdo personalizado na área da barra de título controlada pelo navegador.
Status atual
Etapa | Status |
---|---|
1. Criar uma explicação | Concluído |
2. Criar um rascunho inicial da especificação | Concluído |
3. Coletar feedback e iterar o design | Em andamento |
4. Teste de origem | Concluído |
5. Lançamento | Concluída (no Chromium 104) |
Como usar a sobreposição de controles de janela
Como adicionar window-controls-overlay
ao manifesto do app da Web
Um app da Web progressivo pode ativar a sobreposição de controles de janela adicionando
"window-controls-overlay"
como o membro principal de "display_override"
no manifesto do app da Web:
{
"display_override": ["window-controls-overlay"]
}
A sobreposição de controles de janela só vai ficar visível quando todas as condições a seguir forem atendidas:
- O app não é aberto no navegador, mas em uma janela separada da PWA.
- O manifesto inclui
"display_override": ["window-controls-overlay"]
. Outros valores são permitidos depois disso. - A PWA está sendo executada em um sistema operacional para computador.
- A origem atual corresponde à origem em que a PWA foi instalada.
O resultado disso é uma área de barra de título vazia com os controles de janela normais à esquerda ou à direita, dependendo do sistema operacional.
Como mover conteúdo para a barra de título
Agora que há espaço na barra de título, você pode mover algo para lá. Para este artigo, criei uma PWA de conteúdo em destaque da Wikimedia. Um recurso útil para esse app pode ser uma pesquisa de palavras nos títulos dos artigos. O HTML do recurso de pesquisa tem esta aparência:
<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>
Para mover esse div
para a barra de título, é necessário usar um pouco de 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);
}
Confira o efeito desse código na captura de tela abaixo. A barra de título é totalmente responsiva. Quando você redimensiona a janela do PWA, a barra de título reage como se fosse composta de conteúdo HTML normal, o que, na verdade, é.
Como determinar quais partes da barra de título são arrastáveis
A captura de tela acima sugere que você terminou, mas ainda não terminou. A janela da PWA não
pode mais ser arrastada (exceto uma área muito pequena), já que os botões de controle da janela não são áreas
de arrasto, e o restante da barra de título consiste no widget de pesquisa. Corrija isso usando
a propriedade CSS app-region
com um valor de drag
. No caso concreto, é possível fazer
tudo, exceto o elemento input
, ser arrastável.
/* 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;
}
Com esse CSS em vigor, o usuário pode arrastar a janela do app como de costume arrastando o div
, o img
ou o label
. Somente o elemento input
é interativo, para que a consulta de pesquisa possa ser inserida.
Detecção de recursos
O suporte à sobreposição de controles de janela pode ser detectado testando a existência de
windowControlsOverlay
:
if ('windowControlsOverlay' in navigator) {
// Window Controls Overlay is supported.
}
Consultar a região de controles da janela com windowControlsOverlay
O código até agora tem um problema: em algumas plataformas, os controles de janela estão à direita, em
outras, estão à esquerda. Para piorar, o menu "Três pontos" do Chrome também muda
de posição com base na plataforma. Isso significa que a imagem de plano de fundo com gradiente linear precisa ser
adaptada dinamicamente para ser executada de #131313
→maroon
ou maroon
→#131313
→maroon
, para que ela
se misture com a cor de plano de fundo maroon
da barra de título, que é determinada por
<meta name="theme-color" content="maroon">
. Isso pode ser feito consultando a
API getTitlebarAreaRect()
na propriedade 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');
}
Em vez de ter a imagem de plano de fundo nas regras CSS da classe .search
diretamente (como antes), o
código modificado agora usa duas classes que o código acima define dinamicamente.
/* 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);
}
Como determinar se a sobreposição de controles de janela está visível
A sobreposição de controles de janela não fica visível na área da barra de título em todas as circunstâncias. Embora ele
não esteja disponível em navegadores que não oferecem suporte ao recurso de sobreposição de controles de janela, ele
também não está disponível quando a PWA em questão é executada em uma guia. Para detectar essa situação, você pode
consultar a propriedade visible
do windowControlsOverlay
:
if (navigator.windowControlsOverlay.visible) {
// The window controls overlay is visible in the title bar area.
}
Como alternativa, use a consulta de mídia display-mode
no JavaScript e/ou 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. */
}
Receber notificações sobre mudanças na geometria
Consultar a área de sobreposição dos controles de janela com getTitlebarAreaRect()
pode ser suficiente para
coisas únicas, como definir a imagem de plano de fundo correta com base na localização dos controles de janela. Em
outros casos, um controle mais refinado é necessário. Por exemplo, um possível caso de uso pode ser
adaptar a sobreposição de controles de janela com base no espaço disponível e adicionar uma piada na sobreposição
de controle de janela quando houver espaço suficiente.
Você pode receber notificações sobre mudanças na geometria se inscrever em
navigator.windowControlsOverlay.ongeometrychange
ou configurar um listener de eventos para o evento
geometrychange
. Esse evento só será acionado quando a sobreposição de controles de janela estiver visível, ou
seja, quando navigator.windowControlsOverlay.visible
for 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);
}
Em vez de atribuir uma função a ongeometrychange
, você também pode adicionar um listener de eventos a
windowControlsOverlay
, conforme abaixo. Leia sobre a diferença entre os dois na
MDN.
navigator.windowControlsOverlay.addEventListener(
'geometrychange',
debounce((e) => {
span.hidden = e.titlebarAreaRect.width < 800;
}, 250),
);
Compatibilidade ao executar em uma guia e em navegadores sem suporte
Há dois casos possíveis a serem considerados:
- O caso em que um app está sendo executado em um navegador que oferece suporte à sobreposição de controles de janela, mas em que o app é usado em uma guia do navegador.
- O caso em que um app está sendo executado em um navegador que não oferece suporte à sobreposição de controles de janela.
Em ambos os casos, por padrão, o HTML criado para a sobreposição de controles
de janela aparece inline como conteúdo HTML normal, e os valores padrão das variáveis env()
são usados para o posicionamento. Em navegadores compatíveis, você também pode decidir não mostrar o
HTML designado para a sobreposição de controles de janela verificando a propriedade visible
da sobreposição e, se
ela informar false
, ocultando esse conteúdo HTML.
Lembrete: os navegadores sem suporte não consideram a
propriedade do manifesto de app da Web "display_override"
ou não reconhecem o
"window-controls-overlay"
e, portanto, usam o próximo valor possível de acordo com a cadeia de fallback,
por exemplo, "standalone"
.
Considerações sobre a interface
Embora seja tentador, não é recomendável criar um menu suspenso clássico na área de sobreposição dos controles da janela. Isso violaria as diretrizes de design no macOS, uma plataforma em que os usuários esperam encontrar barras de menu (fornecidas pelo sistema e personalizadas) na parte de cima da tela.
Se o app oferece uma experiência em tela cheia, considere cuidadosamente se faz sentido
que a sobreposição de controles de janela faça parte da visualização em tela cheia. Talvez você queira
reorganizar o layout quando o evento
onfullscreenchange
for acionado.
Demonstração
Criei uma demonstração que você pode testar em diferentes navegadores com e sem suporte e no estado instalado e não instalado. Para a experiência real da sobreposição de controles de janela, você precisa instalar o app. Confira duas capturas de tela abaixo. O código-fonte do app está disponível no Glitch.
O recurso de pesquisa na sobreposição de controles de janela é totalmente funcional:
Considerações sobre segurança
A equipe do Chromium projetou e implementou a API Window Controls Overlay usando os princípios básicos definidos em Como controlar o acesso a recursos poderosos da plataforma da Web, incluindo o controle do usuário, transparência e ergonomia.
Spoofing
Dar aos sites o controle parcial da barra de título permite que os desenvolvedores falsifiquem o conteúdo na região que antes era confiável e controlada pelo navegador. Atualmente, nos navegadores Chromium, o modo independente inclui uma barra de título que, na inicialização inicial, exibe o título da página da Web à esquerda e a origem da página à direita (seguida pelo botão "configurações e mais" e os controles da janela). Após alguns segundos, o texto de origem desaparece. Se o navegador estiver definido para um idioma da direita para a esquerda (RTL), esse layout será invertido para que o texto de origem fique à esquerda. Isso abre a sobreposição de controles de janela para falsificar a origem se não houver padding suficiente entre a origem e a borda direita da sobreposição. Por exemplo, a origem "evil.ltd" pode ser anexada a um site confiável, "google.com", fazendo com que os usuários acreditem que a origem é confiável. O plano é manter esse texto de origem para que os usuários saibam qual é a origem do app e possam garantir que ele corresponda às expectativas deles. Para navegadores configurados para RTL, é necessário ter padding suficiente à direita do texto de origem para evitar que um site malicioso anexe a origem não segura a uma origem confiável.
Técnicas de impressão digital
Ativar a sobreposição de controles de janela e as regiões arrastáveis não representam
problemas de privacidade consideráveis, exceto a detecção de recursos. No entanto, devido a
tamanhos e posições diferentes dos botões de controle de janela em sistemas
operacionais, o método
navigator.
retorna um DOMRect
cuja posição e dimensões revelam informações sobre o sistema operacional em
que o navegador está sendo executado. Atualmente, os desenvolvedores já podem descobrir o SO
pela string do agente do usuário, mas, devido a preocupações com a impressão digital, há
discussões sobre congelar a string do UA e unificar as versões do SO. Há um
esforço contínuo na comunidade de navegadores para entender com que frequência o
tamanho da sobreposição dos controles de janela muda entre as plataformas, já que a
suposição atual é que eles são bastante estáveis em todas as versões do SO e, portanto, não
seriam úteis para observar versões menores do SO. Embora esse seja um possível
problema de impressão digital, ele se aplica apenas a PWAs instalados que usam o recurso de barra de título
personalizada e não se aplica ao uso geral do navegador. Além disso, a
API navigator.
não estará disponível para
iframes incorporados em uma PWA.
Navegação
A navegação para uma origem diferente em um PWA fará com que ele volte à barra de título independente normal, mesmo que atenda aos critérios acima e seja iniciado com a sobreposição de controles da janela. Isso é para acomodar a barra preta que aparece na navegação para uma origem diferente. Depois de navegar de volta à origem original, a sobreposição de controles de janela será usada novamente.
Feedback
A equipe do Chromium quer saber sobre sua experiência com a API Window Controls Overlay.
Conte sobre o design da API
Há algo na API que não funciona como esperado? Ou há métodos ou propriedades ausentes que você precisa para implementar sua ideia? Tem dúvidas ou comentários sobre o modelo de segurança? Envie um problema de especificação no repositório do GitHub correspondente ou adicione sua opinião a um problema existente.
Informar um problema com a implementação
Você encontrou um bug na implementação do Chromium? Ou a implementação é diferente da especificação?
Registre um bug em new.crbug.com. Inclua o máximo de detalhes possível,
instruções simples para reprodução e digite UI>Browser>WebAppInstalls
na caixa
Components. O Glitch é ótimo para compartilhar reprosões rápidas e fáceis.
Mostrar suporte para a API
Você planeja usar a API Window Controls Overlay? Seu apoio público ajuda a equipe do Chromium a priorizar recursos e mostra a outros fornecedores de navegadores a importância de oferecer suporte a eles.
Envie um Tweet para @ChromiumDev com a
hashtag #WindowControlsOverlay
e nos informe onde e como você está usando.
Links úteis
- Explicação
- Especificação do rascunho
- Bug do Chromium
- Entrada "Status da plataforma do Chrome"
- Análise da TAG
- Documentos relacionados do Microsoft Edge
Agradecimentos
A sobreposição de controles de janela foi implementada e especificada por Amanda Baker, da equipe do Microsoft Edge. Este artigo foi revisado por Joe Medley e Kenneth Rohde Christiansen. Imagem principal de Sigmund no Unsplash.