Escolher entre a API Popover e a API Dialog é difícil porque elas parecem fazer o mesmo trabalho, mas não fazem!
Depois um pouco Depois de muita pesquisa, descobri que a API Popover e a API Dialog são totalmente diferentes em termos de acessibilidade. Então, se você está tentando decidir se deve usar a API Popover ou a API do Dialog, recomendo que você:
- Use a API Popover para a maioria dos popovers.
- Use a API do Dialog apenas para diálogos modais.
Popover vs. Diálogo
A relação entre Popovers e Dialogs é confusa para a maioria dos desenvolvedores, mas na verdade é bastante simples.
Os diálogos são simplesmente subconjuntos de popovers. E os diálogos modais são subconjuntos de diálogos. Leia este artigo se quiser entender a lógica por trás desse relacionamento.
É por isso que você pode usar a API Popover mesmo em um elemento.
Estilisticamente, a diferença entre popovers e modais é ainda mais clara:
- Os modais devem mostrar um pano de fundo.
- Popovers não deveriam.
Portanto, você nunca deve estilizar um popover ::backdrop elemento. Fazer isso simplesmente indicará que o popover é uma caixa de diálogo — que cria uma lata inteira de problemas.
Você só deve estilizar um modal ::backdrop elemento.
API Popover e sua acessibilidade
Construir um popover com a API Popover é relativamente fácil. Você especifica três coisas:
- um
popovertargetatributo no gatilho popover, - um
idno popover, e - um
popoveratributo no popover.
O popovertarget deve corresponder ao id.
Observe que estou usando o elemento para criar um dialog papel. Isso é opcional, mas recomendado. Eu faço isso porque dialog é uma ótima função padrão, já que a maioria dos popovers são simplesmente diálogos.
Essas duas linhas de código vêm com vários recursos de acessibilidade já integrados para você:
- Gerenciamento automático de foco
- O foco vai para o popover ao abrir.
- O foco volta para o gatilho ao fechar.
- Conexão automática de ária
- Não há necessidade de escrever
aria-expanded,aria-popupearia-controls. Os navegadores lidam com isso nativamente. Uau!
- Não há necessidade de escrever
- Dispensação automática de luz
- O popover fecha quando o usuário clica fora.
- Popover fecha quando eles pressionam o Esc chave.
Agora, sem estilo adicional, o popover parece meio meh. O estilo é outra questão, então abordaremos isso em um artigo futuro. Geoff tem algumas notas que você pode revisar enquanto isso.
API Dialog e sua acessibilidade
Ao contrário da API Popover, a API Dialog não possui muitos recursos integrados por padrão:
- Sem gerenciamento automático de foco
- Sem conexão ARIA automática
- Sem dispensa automática de luz
Então, temos que construí-los nós mesmos com JavaScript. É por isso a API Popover é superior à API Dialog em quase todos os aspectos – exceto em um: quando modais estão envolvidos.
A API de diálogo tem um showModal método. Quando showModal é usado, a API Dialog cria um modal. Isto:
- automaticamente
inertoutros elementos, - impede que os usuários acessem outros elementos e
- impede que os leitores de tela alcancem outros elementos.
Ele faz isso de forma tão eficaz que não precisamos mais prender o foco no modal.
Mas precisamos cuidar do foco e do material ARIA quando usamos a API Dialog, então vamos abordar o código mínimo necessário para um diálogo funcional.
Começaremos construindo o andaime HTML:
Observe que não adicionei nenhum aria-expanded no HTML. Faço isso por vários motivos:
- Isso reduz a complexidade do HTML.
- Podemos escrever
aria-expanded,aria-controlse o foco diretamente em JavaScript – já que não funcionarão sem JavaScript. - Fazer isso torna esse HTML muito reutilizável.
Configurando
Vou escrever sobre uma implementação simples de JavaScript aqui. Se estiver usando uma estrutura, como React ou Svelte, você terá que fazer algumas alterações – mas espero que seja simples para você.
A primeira coisa a fazer é percorrer todos dialog-invokerse definir aria-expanded para false. Isso cria o estado inicial.
Também vamos definir aria-controls para o elemento. Faremos isso mesmo que aria-controls é cocôporque não há melhor maneira de conectar esses elementos (e não há mal nenhum em conectá-los), até onde eu sei.
const modalInvokers = Array.from(document.querySelectorAll('.modal-invoker'))
modalInvokers.forEach(invoker => {
const dialogId = invoker.dataset.target
const dialog = document.querySelector(`#${dialogId}`)
invoker.setAttribute('aria-expanded', false)
invoker.setAttribute('aria-controls', dialogId)
})
Abrindo o modal
Quando o invocador/gatilho é clicado, temos que:
- mudar o
aria-expandeddefalseparatrueparashowo modal para usuários de tecnologia assistiva, e - use o
showModalfunção para abrir o modal.
Não precisamos escrever nenhum código para ocultar o modal neste click manipulador porque os usuários nunca poderão clicar no invocador quando a caixa de diálogo for aberta.
modalInvokers.forEach(invoker => {
// ...
// Opens the modal
invoker.addEventListener('click', event => {
invoker.setAttribute('aria-expanded', true)
dialog.showModal()
})
})
Ótimo. O modal está aberto. Agora temos que escrever o código para fechar o modal.
Fechando o modal
Por padrão, showModal não possui dispensa automática de luz, então os usuários não podem fechar o modal clicando na sobreposição ou pressionando o botão Esc chave. Isso significa que temos que adicionar outro botão que feche o modal. Isso deve ser colocado dentro do conteúdo modal.
Quando os usuários clicam no botão Fechar, temos que:
- definir
aria-expandedno invocador de abertura parafalse, - feche o modal com o
closemétodo, e - traga o foco de volta para o elemento invocador de abertura.
modalInvokers.forEach(invoker => {
// ...
// Opens the modal
invoker.addEventListener('click', event => {
invoker.setAttribute('aria-expanded', true)
dialog.showModal()
})
})
const modalClosers = Array.from(document.querySelectorAll('.modal-closer'))
modalClosers.forEach(closer => {
const dialog = closer.closest('dialog')
const dialogId = dialog.id
const invoker = document.querySelector(`(data-target="${dialogId}")`)
closer.addEventListener('click', event => {
dialog.close()
invoker.setAttribute('aria-expanded', false)
invoker.focus()
})
})
Ufa, com isso, terminamos com o básico implementação.
Claro, há trabalhos avançados como desmoldagem leve e estilo… que podemos abordar em um artigo futuro.
Você pode usar a API Popover para criar modais?
Sim, você pode.
Mas você terá que lidar com isso sozinho:
- Inertizando outros elementos
- Foco de captura
Acho que o que fizemos anteriormente (configuração aria-expanded, aria-controlse focus) são mais fáceis em comparação com elementos de inertização e foco de captura.
A API Dialog pode se tornar muito mais fácil de usar no futuro
Uma proposta sobre comandos invocadores foi criado para que a API Dialog possa incluir popovertarget como a API Popover.
Isso está a caminho, então poderemos tornar os modais ainda mais simples com a API Dialog no futuro. Enquanto isso, precisamos fazer o trabalho necessário para corrigir as coisas de acessibilidade.
Aprofunde-se na construção de popovers e modais viáveis
Nós apenas começamos a arranhar a superfície da construção de popovers e modais funcionais com o código acima – são versões básicas que são acessíveis, mas definitivamente não têm boa aparência e ainda não podem ser usadas para fins profissionais.
Para facilitar o processo de construção de popovers e modais, nos aprofundaremos nos detalhes de implementação de um popover de nível profissional e de um modal de nível profissional em artigos futuros.
Enquanto isso, espero que isso lhe dê algumas ideias sobre quando escolher a API Popover e a API Dialog!
Lembre-se de que não há necessidade de usar ambos. Um servirá.
Deseja saber mais sobre Programação e Desenvolvimento Clique Aqui!
