Use a área da barra de título ao lado dos controles da janela para fazer seu PWA parecer um app.
Se você se lembra do meu artigo Faça seu PWA parecer um app, talvez se lembre de como mencionei como personalizar a barra de título do seu app como uma estratégia para criar uma experiência mais parecida com o app. Confira um exemplo disso no app Podcasts para macOS.
![Uma barra de título do app macOS Podcasts mostrando botões de controle de mídia e metadados sobre o podcast em reprodução.](https://web.dev/static/articles/window-controls-overlay/image/a-macos-podcasts-app-titl-20aca29098b84.png?authuser=7&hl=pt)
Agora, você pode se sentir tentado a dizer que Podcasts é um app para macOS específico da plataforma que não é executado em um navegador e, portanto, pode fazer o que quiser sem precisar reproduzir as regras do navegador. Verdadeiro, mas a boa notícia é que o recurso de sobreposição de controles da janela, que é o assunto deste artigo, em breve permite criar interfaces do usuário semelhantes para seu PWA.
Componentes da sobreposição de controles da janela
A sobreposição de controles da janela consiste em quatro sub-recursos:
- O valor
"window-controls-overlay"
do campo"display_override"
no manifesto do app da Web. - As variáveis de ambiente 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 da janela por meio do
membro
windowControlsOverlay
dewindow.navigator
.
O que é a sobreposição de controles da janela
A área da barra de título refere-se 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 de janela permite que os Progressive Web Apps (PWAs) pareçam um app, trocando a barra de título de largura total por uma pequena sobreposição contendo 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
Step | Status |
---|---|
1. Criar explicação | Concluído |
2. Criar rascunho inicial da especificação | Concluído |
3. Reunir feedbacks e iterar no design | Em andamento |
4. Teste de origem | Completos |
5. Lançamento | Concluído (no Chromium 104) |
Como usar a sobreposição de controles da janela
Adicionar window-controls-overlay
ao manifesto do app da Web
Um Progressive Web App pode ativar a sobreposição de controles de janela adicionando
"window-controls-overlay"
como o membro principal da "display_override"
no manifesto do app da Web:
{
"display_override": ["window-controls-overlay"]
}
A sobreposição de controles da janela só será visível quando todas as condições a seguir forem atendidas:
- O app não é aberto no navegador, mas em uma janela do PWA separada.
- O manifesto inclui
"display_override": ["window-controls-overlay"]
. (Outros valores são permitidos depois disso.) - O PWA está sendo executado em um sistema operacional de computador.
- A origem atual corresponde à origem para que o PWA foi instalado.
O resultado é uma área vazia na barra de título, com os controles normais da janela à esquerda ou à direita, dependendo do sistema operacional.
![Uma janela de app com uma barra de título vazia e os controles da janela à esquerda.](https://web.dev/static/articles/window-controls-overlay/image/an-app-window-an-empty-t-43c563112c2d7.png?authuser=7&hl=pt)
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 um PWA de conteúdo em destaque da Wikimedia. Um recurso útil para esse app pode ser a pesquisa de palavras nos títulos de artigos. O HTML do recurso de pesquisa é semelhante ao seguinte:
<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 este div
para cima na barra de título, é necessário um 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);
}
Veja 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, é.
![Uma janela de app com uma barra de pesquisa na barra de título.](https://web.dev/static/articles/window-controls-overlay/image/an-app-window-a-search-b-e0052c91f794c.png?authuser=7&hl=pt)
Determinar quais partes da barra de título são arrastáveis
Embora a captura de tela acima sugira que você terminou, o trabalho ainda não terminou. A janela do PWA não
é mais arrastável (além de uma área muito pequena), já que os botões de controles da janela não são áreas
de arrastar, e o restante da barra de título consiste no widget de pesquisa. Corrija esse problema usando
a propriedade CSS app-region
com um valor de drag
. No caso concreto, não há problema em tornar
tudo, além do elemento input
, 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 normalmente arrastando a div
, a img
ou a label
. Somente o elemento input
é interativo. Portanto, a consulta de pesquisa pode 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
Até agora, o código tem um problema: em algumas plataformas, os controles de janela estão à direita e em
outras à esquerda. Para piorar as coisas, o menu de três pontos do Google Chrome também
mudará de posição, com base na plataforma. Isso significa que a imagem de plano de fundo do gradiente linear precisa
ser adaptada dinamicamente para ser executada de #131313
→maroon
ou maroon
→#131313
→maroon
, para que
se mescle com a cor de fundo maroon
da barra de título, que é determinada por
<meta name="theme-color" content="maroon">
. Para isso, consulte 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 de CSS da classe .search
diretamente, como antes, o
código modificado agora usa duas classes definidas pelo código acima 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 da janela está visível
A sobreposição de controles da janela não será 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 da janela, ele
também não está disponível quando o PWA em questão é executado em uma guia. Para detectar essa situação, consulte a propriedade visible
de windowControlsOverlay
:
if (navigator.windowControlsOverlay.visible) {
// The window controls overlay is visible in the title bar area.
}
Como alternativa, também é possível usar a consulta de mídia display-mode
em 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 alterações na geometria
Consultar a área de sobreposição dos controles da janela com getTitlebarAreaRect()
pode ser suficiente para algo
único, como definir a imagem de plano de fundo correta com base na localização dos controles da janela. Em
outros casos, é necessário ter um controle mais refinado. Por exemplo, um caso de uso possível pode ser
adaptar a sobreposição de controles da janela com base no espaço disponível e adicionar uma piada diretamente na
sobreposição de controle da janela quando houver espaço suficiente.
![Os controles de janela se sobrepõem à área de sobreposição em uma janela estreita com texto reduzido.](https://web.dev/static/articles/window-controls-overlay/image/window-controls-overlay-a-383c6a756329.png?authuser=7&hl=pt)
Você pode receber notificações sobre mudanças na geometria inscrevendo-se em navigator.windowControlsOverlay.ongeometrychange
ou configurando um listener de eventos para o evento geometrychange
. Esse evento só será disparado quando a sobreposição de controles da 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
, também é possível adicionar um listener de eventos ao
windowControlsOverlay
, conforme mostrado abaixo. Leia sobre a diferença entre os dois no
MDN.
navigator.windowControlsOverlay.addEventListener(
'geometrychange',
debounce((e) => {
span.hidden = e.titlebarAreaRect.width < 800;
}, 250),
);
Compatibilidade ao executar em uma guia e em navegadores incompatíveis
Existem dois casos possíveis a serem considerados:
- O caso em que um app é executado em um navegador com suporte à sobreposição de controles da 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 da janela.
Em ambos os casos, por padrão, o HTML criado para a sobreposição de controles
da janela é exibido inline como conteúdo HTML normal, e os valores substitutos das variáveis env()
são ativados no posicionamento. Em navegadores compatíveis, também é possível optar por não exibir o HTML designado para a sobreposição de controles da janela verificando a propriedade visible
da sobreposição e, se ela informar false
, e ocultando esse conteúdo HTML.
![Um PWA em execução em uma guia do navegador com a sobreposição de controles de janela exibida no corpo.](https://web.dev/static/articles/window-controls-overlay/image/a-pwa-running-a-browser-404595bd2cb6d.png?authuser=7&hl=pt)
Navegadores sem suporte não consideram a
propriedade do manifesto do app da Web "display_override"
ou não reconhecem
"window-controls-overlay"
e, portanto, usam o próximo valor possível de acordo com a cadeia de substituto,
por exemplo, "standalone"
.
![Um PWA em execução no modo independente com a sobreposição de controles de janela exibida no corpo.](https://web.dev/static/articles/window-controls-overlay/image/a-pwa-running-standalone-2badef6176edf.png?authuser=7&hl=pt)
Considerações sobre a interface
Embora possa ser tentador, não é recomendável criar um menu suspenso clássico na área de sobreposição de controles da janela. Isso violaria as diretrizes de design no macOS, uma plataforma em que os usuários esperam barras de menu (fornecidas pelo sistema e personalizadas) na parte de cima da tela.
Caso seu app ofereça uma experiência em tela cheia, considere cuidadosamente se faz sentido
que a sobreposição de controles da janela faça parte da visualização em tela cheia. É possível
reorganizar o layout quando o evento
onfullscreenchange
for disparado.
Demonstração
Criei uma demonstração que você pode usar em diferentes navegadores compatíveis ou incompatíveis e no estado instalado e não instalado. Para ter a experiência real de sobreposição dos controles da janela, instale o app. Confira abaixo duas capturas de tela do que esperar. O código-fonte do app está disponível no Glitch.
![O aplicativo de demonstração de Conteúdo em destaque da Wikimedia com sobreposição de controles de janela.](https://web.dev/static/articles/window-controls-overlay/image/the-wikimedia-featured-co-1d13973f05a73.png?authuser=7&hl=pt)
O recurso de pesquisa na sobreposição de controles da janela é totalmente funcional:
![O aplicativo de demonstração de Conteúdo em destaque da Wikimedia com sobreposição de controles de janela e a pesquisa ativa pelo termo "cleopa...", destacando um dos artigos com o termo correspondente "Cleópatra".](https://web.dev/static/articles/window-controls-overlay/image/the-wikimedia-featured-co-b28ddfbf5edaf.png?authuser=7&hl=pt)
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 avançados da plataforma da Web, incluindo controle do usuário, transparência e ergonomia.
Spoofing
Oferecer aos sites controle parcial da barra de título permite que os desenvolvedores falsifiquem conteúdo em uma região confiável controlada pelo navegador. Atualmente, nos navegadores Chromium, o modo autônomo 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 pelos controles da janela). Após alguns segundos, o texto de origem desaparece. Se o navegador estiver configurado para um idioma da direita para a esquerda (RTL, na sigla em inglês), o layout será invertido para que o texto de origem fique à esquerda. Isso abre a sobreposição de controles da 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", levando os usuários a acreditar que a fonte é 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 com RTL, é necessário que haja padding suficiente à direita do texto de origem para evitar que um site malicioso anexe a origem não segura com uma origem confiável.
Impressão digital
A ativação da sobreposição de controles da janela e das regiões arrastáveis não representa
preocupações de privacidade consideráveis além da detecção de recursos. No entanto, devido aos
tamanhos e posições diferentes dos botões de controle da janela nos 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 a partir da string do user agent, mas, devido a questões de impressão digital, há discussões sobre como congelar a string do UA e unificar 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 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
são úteis para observar versões secundárias do SO. Embora esse seja um possível
problema de impressão digital, ele se aplica apenas aos PWAs instalados que usam o recurso
personalizado da barra de título 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 um PWA.
Navegação
Navegar 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 serve para acomodar a barra preta que aparece na navegação para uma origem diferente. Depois de voltar à origem original, a sobreposição de controles da janela vai ser usada novamente.
![Uma barra de URL preta para navegação fora da origem.](https://web.dev/static/articles/window-controls-overlay/image/a-black-url-bar-out-ori-e3d2faea499bf.png?authuser=7&hl=pt)
Feedback
A equipe do Chromium quer saber mais sobre suas experiências com a API Window Controls Overlay.
Fale sobre o design da API
Algo na API não funciona como você esperava? Ou há métodos ou propriedades ausentes que você precisa para implementar sua ideia? Tem alguma dúvida ou comentário sobre o modelo de segurança? Registre um problema de especificação no repositório do GitHub correspondente ou adicione suas ideias 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 insira UI>Browser>WebAppInstalls
na caixa
Componentes. O Glitch funciona muito bem para compartilhar repetições rápidas e fáceis.
Mostrar suporte à API
Você planeja usar a API Window Controls Overlay? Seu suporte público ajuda a equipe do Chromium a priorizar recursos e mostra a outros fornecedores de navegador como é importante oferecer suporte a eles.
Envie um tweet para @ChromiumDev com a hashtag
#WindowControlsOverlay
e informe onde e como você está usando essa tag.
Links úteis
- Explicação
- Rascunho das especificações
- Bug do Chromium
- Entrada de 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 (links em inglês).